11import { fs , invoke , path , process , shell } from "@tauri-apps/api" ;
2- import { exists } from "@tauri-apps/api/fs" ;
2+ import { exists , writeTextFile , readTextFile } from "@tauri-apps/api/fs" ;
33import { t } from "i18next" ;
44import { invoke_rpc } from "../api/rpc" ;
55import { ResourceInfo , validFileChecksums } from "../constants/app" ;
@@ -12,6 +12,8 @@ import { Log } from "./logger";
1212import { sc } from "./sizeScaler" ;
1313import { Server } from "./types" ;
1414import { useGenericPersistentState } from "../states/genericStates" ;
15+ import { save , open } from '@tauri-apps/api/dialog' ;
16+ import { useNotification } from "../states/notification" ;
1517
1618export const copySharedFilesIntoGameFolder = async ( ) => {
1719 const { gtasaPath } = useSettings . getState ( ) ;
@@ -315,3 +317,150 @@ export const checkDirectoryValidity = async (
315317
316318 return true ;
317319} ;
320+
321+ export const exportFavoriteListFile = async ( ) => {
322+ const { favorites } = usePersistentServers . getState ( ) ;
323+ const { showMessageBox, hideMessageBox } = useMessageBox . getState ( ) ;
324+
325+ if ( ! favorites . length ) {
326+ showMessageBox ( {
327+ title : t ( "export_failed_title" ) ,
328+ description : t ( "export_no_servers_description" ) ,
329+ buttons : [
330+ {
331+ title : "OK" ,
332+ onPress : ( ) => hideMessageBox ( ) ,
333+ } ,
334+ ] ,
335+ } ) ;
336+ return ;
337+ }
338+
339+ try {
340+ const exportData = {
341+ version : 1 ,
342+ servers : favorites . map ( server => ( {
343+ ip : server . ip ,
344+ port : server . port ,
345+ name : server . hostname ,
346+ password : server . password || ""
347+ } ) )
348+ } ;
349+
350+ const jsonString = JSON . stringify ( exportData , null , 2 ) ;
351+
352+ const savePath = await save ( {
353+ filters : [ {
354+ name : 'JSON' ,
355+ extensions : [ 'json' ]
356+ } ] ,
357+ defaultPath : 'omp_servers.json'
358+ } ) ;
359+
360+ if ( savePath ) {
361+ await writeTextFile ( savePath , jsonString ) ;
362+
363+ const { showNotification } = useNotification . getState ( ) ;
364+ showNotification (
365+ t ( "export_successful_title" ) ,
366+ t ( "export_successful_description" , { count : favorites . length , path : savePath } )
367+ ) ;
368+ }
369+ } catch ( error ) {
370+ Log . debug ( "Error exporting servers:" , error ) ;
371+ showMessageBox ( {
372+ title : t ( "export_failed_title" ) ,
373+ description : t ( "export_failed_description" ) ,
374+ buttons : [
375+ {
376+ title : "OK" ,
377+ onPress : ( ) => hideMessageBox ( ) ,
378+ } ,
379+ ] ,
380+ } ) ;
381+ }
382+ } ;
383+
384+ export const importFavoriteListFile = async ( ) => {
385+ const { showMessageBox, hideMessageBox } = useMessageBox . getState ( ) ;
386+
387+ try {
388+ const selected = await open ( {
389+ multiple : false ,
390+ filters : [ {
391+ name : 'JSON' ,
392+ extensions : [ 'json' ]
393+ } ]
394+ } ) ;
395+ if ( ! selected ) return ;
396+ const fileContent = await readTextFile ( selected as string ) ;
397+ const { addToFavorites } = usePersistentServers . getState ( ) ;
398+ const { showNotification } = useNotification . getState ( ) ;
399+
400+ try {
401+ const data = JSON . parse ( fileContent ) ;
402+
403+ if ( ! data . servers || ! Array . isArray ( data . servers ) ) {
404+ throw new Error ( "Invalid file format: missing servers array" ) ;
405+ }
406+
407+ let importCount = 0 ;
408+
409+ for ( const importedServer of data . servers ) {
410+ if ( importedServer . ip && importedServer . port ) {
411+ const serverInfo : Server = {
412+ ip : importedServer . ip ,
413+ port : Number ( importedServer . port ) ,
414+ hostname : importedServer . name || "Imported Server" ,
415+ playerCount : 0 ,
416+ maxPlayers : 0 ,
417+ gameMode : "-" ,
418+ language : "-" ,
419+ hasPassword : ! ! importedServer . password ,
420+ version : "-" ,
421+ usingOmp : false ,
422+ partner : false ,
423+ ping : 9999 ,
424+ players : [ ] ,
425+ password : importedServer . password || "" ,
426+ rules : { } as Server [ "rules" ] ,
427+ } ;
428+
429+ addToFavorites ( serverInfo ) ;
430+ importCount ++ ;
431+ }
432+ }
433+
434+ showNotification (
435+ t ( "import_successful_title" ) ,
436+ t ( "import_successful_description" , { count : importCount , path : selected } )
437+ ) ;
438+
439+ } catch ( parseError ) {
440+ showMessageBox ( {
441+ title : t ( "import_failed_title" ) ,
442+ description : t ( "import_invalid_data_description" ) ,
443+ buttons : [
444+ {
445+ title : "OK" ,
446+ onPress : ( ) => hideMessageBox ( ) ,
447+ } ,
448+ ] ,
449+ } ) ;
450+ Log . debug ( "Error parsing imported file:" , parseError ) ;
451+ }
452+
453+ } catch ( error ) {
454+ showMessageBox ( {
455+ title : t ( "import_failed_title" ) ,
456+ description : t ( "import_failed_description" ) ,
457+ buttons : [
458+ {
459+ title : "OK" ,
460+ onPress : ( ) => hideMessageBox ( ) ,
461+ } ,
462+ ] ,
463+ } ) ;
464+ Log . debug ( "Error importing servers:" , error ) ;
465+ }
466+ } ;
0 commit comments