Skip to content

Commit d59a995

Browse files
committed
add import and export functionality for favourite server lists in settings
1 parent d14481d commit d59a995

File tree

2 files changed

+185
-1
lines changed

2 files changed

+185
-1
lines changed

src/containers/Settings/Tab/General.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useAppState } from "../../../states/app";
77
import { usePersistentServers } from "../../../states/servers";
88
import { useSettings } from "../../../states/settings";
99
import { useTheme } from "../../../states/theme";
10-
import { checkDirectoryValidity } from "../../../utils/game";
10+
import { checkDirectoryValidity, exportFavoriteListFile, importFavoriteListFile } from "../../../utils/game";
1111
import { Log } from "../../../utils/logger";
1212
import { stateStorage } from "../../../utils/stateStorage";
1313
import { sc } from "../../../utils/sizeScaler";
@@ -174,6 +174,35 @@ const General = () => {
174174
{t("settings_import_samp_favorite_list")}
175175
</Text>
176176
</TouchableOpacity>
177+
178+
<TouchableOpacity
179+
style={[
180+
styles.importButton,
181+
{
182+
backgroundColor: `${theme.primary}BB`,
183+
},
184+
]}
185+
onPress={() => exportFavoriteListFile()}
186+
>
187+
<Text semibold color={"#FFFFFF"} size={2}>
188+
{t("settings_export_favorite_list_file")}
189+
</Text>
190+
</TouchableOpacity>
191+
192+
<TouchableOpacity
193+
style={[
194+
styles.importButton,
195+
{
196+
backgroundColor: `${theme.primary}BB`,
197+
},
198+
]}
199+
onPress={() => importFavoriteListFile()}
200+
>
201+
<Text semibold color={"#FFFFFF"} size={2}>
202+
{t("settings_import_favorite_list_file")}
203+
</Text>
204+
</TouchableOpacity>
205+
177206
<TouchableOpacity
178207
style={[
179208
styles.resetButton,

src/utils/game.ts

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import { Log } from "./logger";
1212
import { sc } from "./sizeScaler";
1313
import { Server } from "./types";
1414
import { useGenericPersistentState } from "../states/genericStates";
15+
import { save } from '@tauri-apps/api/dialog';
16+
import { writeTextFile } from '@tauri-apps/api/fs';
17+
import { useNotification } from "../states/notification";
18+
import { open } from '@tauri-apps/api/dialog';
19+
import { readTextFile } from '@tauri-apps/api/fs';
1520

1621
export const copySharedFilesIntoGameFolder = async () => {
1722
const { gtasaPath } = useSettings.getState();
@@ -315,3 +320,153 @@ export const checkDirectoryValidity = async (
315320

316321
return true;
317322
};
323+
324+
export const exportFavoriteListFile = async () => {
325+
const { favorites } = usePersistentServers.getState();
326+
327+
if (!favorites.length) {
328+
const { showMessageBox } = useMessageBox.getState();
329+
showMessageBox({
330+
title: t("export_no_servers_title"),
331+
description: t("export_no_servers_description"),
332+
buttons: [
333+
{
334+
title: "OK",
335+
onPress: () => {},
336+
},
337+
],
338+
});
339+
return;
340+
}
341+
342+
try {
343+
const exportData = {
344+
version: 1,
345+
servers: favorites.map(server => ({
346+
ip: server.ip,
347+
port: server.port,
348+
name: server.hostname,
349+
password: server.password || ""
350+
}))
351+
};
352+
353+
const jsonString = JSON.stringify(exportData, null, 2);
354+
355+
const savePath = await save({
356+
filters: [{
357+
name: 'JSON',
358+
extensions: ['json']
359+
}],
360+
defaultPath: 'omp_servers.json'
361+
});
362+
363+
if (savePath) {
364+
await writeTextFile(savePath, jsonString);
365+
366+
const { showNotification } = useNotification.getState();
367+
showNotification(
368+
t("export_successful_title"),
369+
t("export_successful_description", { count: favorites.length, path: savePath })
370+
);
371+
}
372+
} catch (error) {
373+
Log.debug("Error exporting servers:", error);
374+
const { showMessageBox } = useMessageBox.getState();
375+
showMessageBox({
376+
title: t("export_failed_title"),
377+
description: t("export_failed_description"),
378+
buttons: [
379+
{
380+
title: "OK",
381+
onPress: () => {},
382+
},
383+
],
384+
});
385+
}
386+
};
387+
388+
export const importFavoriteListFile = async () => {
389+
try {
390+
const selected = await open({
391+
multiple: false,
392+
filters: [{
393+
name: 'JSON',
394+
extensions: ['json']
395+
}]
396+
});
397+
398+
if (!selected) return; // User cancelled the dialog
399+
400+
const fileContent = await readTextFile(selected as string);
401+
const { addToFavorites } = usePersistentServers.getState();
402+
const { showNotification } = useNotification.getState();
403+
404+
try {
405+
const data = JSON.parse(fileContent);
406+
407+
if (!data.servers || !Array.isArray(data.servers)) {
408+
throw new Error("Invalid file format: missing servers array");
409+
}
410+
411+
let importCount = 0;
412+
413+
for (const importedServer of data.servers) {
414+
if (importedServer.ip && importedServer.port) {
415+
const serverInfo: Server = {
416+
ip: importedServer.ip,
417+
port: Number(importedServer.port),
418+
hostname: importedServer.name || "Imported Server",
419+
playerCount: 0,
420+
maxPlayers: 0,
421+
gameMode: "-",
422+
language: "-",
423+
hasPassword: !!importedServer.password,
424+
version: "-",
425+
usingOmp: false,
426+
partner: false,
427+
ping: 9999,
428+
players: [],
429+
password: importedServer.password || "",
430+
rules: {} as Server["rules"],
431+
};
432+
433+
addToFavorites(serverInfo);
434+
importCount++;
435+
}
436+
}
437+
438+
showNotification(
439+
t("import_successful_title"),
440+
t("import_successful_description", { count: importCount, path: selected })
441+
);
442+
443+
} catch (parseError) {
444+
const { showMessageBox } = useMessageBox.getState();
445+
showMessageBox({
446+
title: t("import_failed_title"),
447+
description: t("import_invalid_data_description"),
448+
buttons: [
449+
{
450+
title: "OK",
451+
onPress: () => {},
452+
},
453+
],
454+
});
455+
Log.debug("Error parsing imported file:", parseError);
456+
}
457+
458+
} catch (error) {
459+
const { showMessageBox } = useMessageBox.getState();
460+
showMessageBox({
461+
title: t("import_failed_title"),
462+
description: t("import_failed_description"),
463+
buttons: [
464+
{
465+
title: "OK",
466+
onPress: () => {},
467+
},
468+
],
469+
});
470+
Log.debug("Error importing servers:", error);
471+
}
472+
};

0 commit comments

Comments
 (0)