|
1 | | -import { GameSettings, WindowSize } from "@/app/types"; |
| 1 | +import { GameSettings, LaunchProfiles, WindowSize } from "@/app/types"; |
2 | 2 | import { useContext, useEffect, useState } from "react"; |
3 | 3 | import { Col, Container, Form, Row } from "react-bootstrap"; |
4 | 4 | import SettingControlDropdown from "./SettingControlDropdown"; |
5 | 5 | import SettingControlWindowSize from "./SettingControlWindowSize"; |
6 | | -import SettingControlText from "./SettingControlText"; |
7 | 6 | import { deepEqual, getDebugMode } from "@/app/util"; |
8 | 7 | import SettingsHeader from "./SettingsHeader"; |
9 | 8 | import { SettingsCtx } from "@/app/contexts"; |
10 | 9 | import SettingControlFpsFix from "./SettingControlFpsFix"; |
| 10 | +import Button from "@/app/components/Button"; |
| 11 | +import EditProfileModal from "@/app/components/EditProfileModal"; |
| 12 | +import { invoke } from "@tauri-apps/api/core"; |
11 | 13 |
|
12 | 14 | export default function GameSettingsTab({ |
13 | 15 | active, |
| 16 | + currentProfiles, |
14 | 17 | currentSettings, |
15 | 18 | updateSettings, |
16 | 19 | }: { |
17 | 20 | active: boolean; |
18 | 21 | currentSettings: GameSettings; |
| 22 | + currentProfiles: LaunchProfiles; |
19 | 23 | updateSettings: ( |
20 | 24 | newSettings: GameSettings | undefined, |
21 | 25 | ) => Promise<GameSettings>; |
| 26 | + |
22 | 27 | }) { |
23 | 28 | const [settings, setSettings] = useState<GameSettings>(currentSettings); |
| 29 | + const [launchProfiles, setLaunchProfiles] = useState<LaunchProfiles>(currentProfiles); |
24 | 30 | const [working, setWorking] = useState<boolean>(false); |
25 | 31 |
|
| 32 | + const [showAddProfile, setShowAddProfile] = useState<boolean>(false); |
| 33 | + const [showEditProfile, setShowEditProfile] = useState<boolean>(false); |
| 34 | + |
26 | 35 | const [debug, setDebug] = useState<boolean>(false); |
27 | 36 |
|
28 | 37 | const ctx = useContext(SettingsCtx); |
@@ -62,6 +71,86 @@ export default function GameSettingsTab({ |
62 | 71 | } |
63 | 72 | }; |
64 | 73 |
|
| 74 | + const selectedLaunchProfile = launchProfiles.profiles.find( |
| 75 | + (p) => p.uuid === settings.launch_profile, |
| 76 | + ); |
| 77 | + |
| 78 | + const canModify = (selectedLaunchProfile !== undefined) && !selectedLaunchProfile!.preset; |
| 79 | + |
| 80 | + const saveProfile = async (name: string, command: string, uuid?: string) => { |
| 81 | + setWorking(true); |
| 82 | + if (uuid) { |
| 83 | + // existing profile |
| 84 | + const updatedProfile = { |
| 85 | + uuid, |
| 86 | + name, |
| 87 | + command, |
| 88 | + preset: false, |
| 89 | + }; |
| 90 | + |
| 91 | + try { |
| 92 | + await invoke("update_launch_profile", { profile: updatedProfile }); |
| 93 | + setLaunchProfiles({ |
| 94 | + profiles: launchProfiles.profiles.map((p) => |
| 95 | + p.uuid === uuid ? updatedProfile : p |
| 96 | + ), |
| 97 | + }); |
| 98 | + } catch (e: unknown) { |
| 99 | + if (ctx.alertError) { |
| 100 | + ctx.alertError("Failed to update launch profile: (" + e + ")"); |
| 101 | + } |
| 102 | + } |
| 103 | + } else { |
| 104 | + // new profile |
| 105 | + const newUuid: string = await invoke("add_launch_profile", { name, command }); |
| 106 | + setLaunchProfiles({ |
| 107 | + profiles: [ |
| 108 | + ...launchProfiles.profiles, |
| 109 | + { |
| 110 | + uuid: newUuid, |
| 111 | + name, |
| 112 | + command, |
| 113 | + preset: false, |
| 114 | + }, |
| 115 | + ], |
| 116 | + }); |
| 117 | + setSettings({ |
| 118 | + ...settings!, |
| 119 | + launch_profile: newUuid, |
| 120 | + }) |
| 121 | + } |
| 122 | + setWorking(false); |
| 123 | + }; |
| 124 | + |
| 125 | + const deleteProfile = async (uuid: string) => { |
| 126 | + await invoke("delete_launch_profile", { uuid }); |
| 127 | + const newProfiles = launchProfiles.profiles.filter((p) => p.uuid !== uuid); |
| 128 | + setLaunchProfiles({ |
| 129 | + profiles: newProfiles, |
| 130 | + }); |
| 131 | + |
| 132 | + if (newProfiles.length > 0) { |
| 133 | + const newSettings = { |
| 134 | + ...settings!, |
| 135 | + launch_profile: newProfiles[0].uuid, |
| 136 | + }; |
| 137 | + setSettings(newSettings); |
| 138 | + await updateSettings(newSettings); |
| 139 | + } |
| 140 | + }; |
| 141 | + |
| 142 | + const showDeleteProfileConfirmation = () => { |
| 143 | + const selectedProfile = selectedLaunchProfile; |
| 144 | + if (ctx.showConfirmationModal && selectedProfile) { |
| 145 | + ctx.showConfirmationModal( |
| 146 | + "Are you sure you want to delete the launch profile \"" + selectedProfile.name + "\"?", |
| 147 | + "Delete Launch Profile", |
| 148 | + "danger", |
| 149 | + async () => deleteProfile(selectedProfile!.uuid), |
| 150 | + ); |
| 151 | + } |
| 152 | + }; |
| 153 | + |
65 | 154 | return ( |
66 | 155 | <Container fluid id="settings-container" className="bg-footer"> |
67 | 156 | <Row> |
@@ -99,22 +188,24 @@ export default function GameSettingsTab({ |
99 | 188 | setSettings({ ...settings!, graphics_api: value }) |
100 | 189 | } |
101 | 190 | /> |
102 | | - <SettingControlText |
103 | | - id="launch_command" |
104 | | - name="Custom Launch Command" |
105 | | - oldValue={currentSettings.launch_command} |
106 | | - value={settings.launch_command} |
107 | | - placeholder="{}" |
108 | | - validator={(value) => |
109 | | - value === "" || value.indexOf("{}") !== -1 |
110 | | - } |
| 191 | + <SettingControlDropdown |
| 192 | + id="launch_profile" |
| 193 | + name="Launch Profile" |
| 194 | + options={launchProfiles.profiles.map((profile) => ({ key: profile.uuid, label: profile.preset ? profile.name + " (preset)" : profile.name }))} |
| 195 | + defaultKey={launchProfiles.profiles.length > 0 ? launchProfiles.profiles[0].uuid : ""} |
| 196 | + oldValue={currentSettings.launch_profile} |
| 197 | + value={settings.launch_profile} |
111 | 198 | onChange={(value) => |
112 | 199 | setSettings({ |
113 | 200 | ...settings!, |
114 | | - launch_command: value === "" ? undefined : value, |
| 201 | + launch_profile: value, |
115 | 202 | }) |
116 | 203 | } |
117 | | - /> |
| 204 | + > |
| 205 | + <Button className="ms-1" icon="trash" tooltip="Delete..." variant="danger" enabled={canModify} onClick={() => showDeleteProfileConfirmation()} /> |
| 206 | + <Button className="ms-1" icon="edit" tooltip="Edit..." enabled={selectedLaunchProfile !== undefined} onClick={() => setShowEditProfile(true)} /> |
| 207 | + <Button className="ms-1" icon="plus" tooltip="Add..." variant="success" onClick={() => setShowAddProfile(true)} /> |
| 208 | + </SettingControlDropdown> |
118 | 209 | <SettingControlWindowSize |
119 | 210 | id="window_size" |
120 | 211 | name="Window Size" |
@@ -163,6 +254,19 @@ export default function GameSettingsTab({ |
163 | 254 | </Col> |
164 | 255 | <Col /> |
165 | 256 | </Row> |
| 257 | + <EditProfileModal |
| 258 | + isAdd={true} |
| 259 | + show={showAddProfile} |
| 260 | + setShow={setShowAddProfile} |
| 261 | + saveProfile={saveProfile} |
| 262 | + /> |
| 263 | + <EditProfileModal |
| 264 | + profile={selectedLaunchProfile} |
| 265 | + isAdd={false} |
| 266 | + show={showEditProfile} |
| 267 | + setShow={setShowEditProfile} |
| 268 | + saveProfile={saveProfile} |
| 269 | + /> |
166 | 270 | </Container> |
167 | 271 | ); |
168 | 272 | } |
0 commit comments