diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 71dd332..338a0c3 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -20,8 +20,8 @@ enum ImportStatus { class LocalStorageService { static const String _fileName = 'game_data.json'; - /// Writes the game session list to a JSON file and returns it as string. - static String getJsonFile() { + /// Writes the game session list to a JSON file and returns it as string. + static String getGameDataAsJsonFile() { final jsonFile = gameManager.gameList.map((session) => session.toJson()).toList(); return json.encode(jsonFile); @@ -39,7 +39,7 @@ class LocalStorageService { print('[local_storage_service.dart] Versuche, Daten zu speichern...'); try { final file = await _getFilePath(); - final jsonFile = getJsonFile(); + final jsonFile = getGameDataAsJsonFile(); await file.writeAsString(jsonFile); print( '[local_storage_service.dart] Die Spieldaten wurden zwischengespeichert.'); @@ -102,19 +102,27 @@ class LocalStorageService { } } - /// Opens the file picker to save a JSON file with the current game data. - static Future exportJsonFile() async { - final jsonString = getJsonFile(); + /// Opens the file picker to export game data as a JSON file. + /// This method will export the given [jsonString] as a JSON file. It opens + /// the file picker with the choosen [fileName]. + static Future exportJsonData( + String jsonString, + String fileName, + ) async { try { final bytes = Uint8List.fromList(utf8.encode(jsonString)); - final result = await FileSaver.instance.saveAs( - name: 'cabo_counter_data', + final path = await FileSaver.instance.saveAs( + name: fileName, bytes: bytes, ext: 'json', mimeType: MimeType.json, ); - print( - '[local_storage_service.dart] Die Spieldaten wurden exportiert. Dateipfad: $result'); + if (path == null) { + print('[local_storage_service.dart]: Export abgebrochen'); + } else { + print( + '[local_storage_service.dart] Die Spieldaten wurden exportiert. Dateipfad: $path'); + } return true; } catch (e) { print( @@ -123,22 +131,36 @@ class LocalStorageService { } } + /// Opens the file picker to export all game sessions as a JSON file. + static Future exportGameData() async { + String jsonString = getGameDataAsJsonFile(); + String fileName = 'cabo_counter-game_data'; + return exportJsonData(jsonString, fileName); + } + + /// Opens the file picker to save a single game session as a JSON file. + static Future exportSingleGameSession(GameSession session) async { + String jsonString = json.encode(session.toJson()); + String fileName = 'cabo_counter-game_${session.id.substring(0, 7)}'; + return exportJsonData(jsonString, fileName); + } + /// Opens the file picker to import a JSON file and loads the game data from it. static Future importJsonFile() async { - final result = await FilePicker.platform.pickFiles( + final path = await FilePicker.platform.pickFiles( dialogTitle: 'Wähle eine Datei mit Spieldaten aus', type: FileType.custom, allowedExtensions: ['json'], ); - if (result == null) { + if (path == null) { print( '[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen'); return ImportStatus.canceled; } try { - final jsonString = await _readFileContent(result.files.single); + final jsonString = await _readFileContent(path.files.single); if (!await validateJsonSchema(jsonString)) { return ImportStatus.validationError; diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 586eab3..68dfeeb 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:cabo_counter/views/create_game_view.dart'; import 'package:cabo_counter/views/graph_view.dart'; @@ -192,14 +193,35 @@ class _ActiveGameViewState extends State { }, ), CupertinoListTile( - title: - Text(AppLocalizations.of(context).export_game, - style: const TextStyle( - color: Colors.white30, - )), - backgroundColorActivated: - CustomTheme.backgroundColor, - ), + title: Text( + AppLocalizations.of(context).export_game, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () async { + final success = await LocalStorageService + .exportSingleGameSession( + widget.gameSession); + if (!success && context.mounted) { + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context) + .export_error_title), + content: Text(AppLocalizations.of(context) + .export_error_message), + actions: [ + CupertinoDialogAction( + child: Text( + AppLocalizations.of(context).ok), + onPressed: () => + Navigator.pop(context), + ), + ], + ), + ); + } + }), ], ) ], diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index b9ae02c..f98c542 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -140,7 +140,7 @@ class _SettingsViewState extends State { ), onPressed: () async { final success = - await LocalStorageService.exportJsonFile(); + await LocalStorageService.exportGameData(); if (!success && context.mounted) { showCupertinoDialog( context: context, diff --git a/pubspec.yaml b/pubspec.yaml index 160097c..b786c31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.7+323 +version: 0.3.7+325 environment: sdk: ^3.5.4