Merge pull request #81 from flixcoo/feature/64-implement-export-game-button-in-activegameview

Implementing single game export
This commit is contained in:
2025-07-07 23:03:19 +02:00
committed by GitHub
4 changed files with 67 additions and 23 deletions

View File

@@ -20,8 +20,8 @@ enum ImportStatus {
class LocalStorageService { class LocalStorageService {
static const String _fileName = 'game_data.json'; static const String _fileName = 'game_data.json';
/// Writes the game session list to a JSON file and returns it as string. /// Writes the game session list to a JSON file and returns it as string.
static String getJsonFile() { static String getGameDataAsJsonFile() {
final jsonFile = final jsonFile =
gameManager.gameList.map((session) => session.toJson()).toList(); gameManager.gameList.map((session) => session.toJson()).toList();
return json.encode(jsonFile); return json.encode(jsonFile);
@@ -39,7 +39,7 @@ class LocalStorageService {
print('[local_storage_service.dart] Versuche, Daten zu speichern...'); print('[local_storage_service.dart] Versuche, Daten zu speichern...');
try { try {
final file = await _getFilePath(); final file = await _getFilePath();
final jsonFile = getJsonFile(); final jsonFile = getGameDataAsJsonFile();
await file.writeAsString(jsonFile); await file.writeAsString(jsonFile);
print( print(
'[local_storage_service.dart] Die Spieldaten wurden zwischengespeichert.'); '[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. /// Opens the file picker to export game data as a JSON file.
static Future<bool> exportJsonFile() async { /// This method will export the given [jsonString] as a JSON file. It opens
final jsonString = getJsonFile(); /// the file picker with the choosen [fileName].
static Future<bool> exportJsonData(
String jsonString,
String fileName,
) async {
try { try {
final bytes = Uint8List.fromList(utf8.encode(jsonString)); final bytes = Uint8List.fromList(utf8.encode(jsonString));
final result = await FileSaver.instance.saveAs( final path = await FileSaver.instance.saveAs(
name: 'cabo_counter_data', name: fileName,
bytes: bytes, bytes: bytes,
ext: 'json', ext: 'json',
mimeType: MimeType.json, mimeType: MimeType.json,
); );
print( if (path == null) {
'[local_storage_service.dart] Die Spieldaten wurden exportiert. Dateipfad: $result'); print('[local_storage_service.dart]: Export abgebrochen');
} else {
print(
'[local_storage_service.dart] Die Spieldaten wurden exportiert. Dateipfad: $path');
}
return true; return true;
} catch (e) { } catch (e) {
print( print(
@@ -123,22 +131,36 @@ class LocalStorageService {
} }
} }
/// Opens the file picker to export all game sessions as a JSON file.
static Future<bool> 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<bool> 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. /// Opens the file picker to import a JSON file and loads the game data from it.
static Future<ImportStatus> importJsonFile() async { static Future<ImportStatus> importJsonFile() async {
final result = await FilePicker.platform.pickFiles( final path = await FilePicker.platform.pickFiles(
dialogTitle: 'Wähle eine Datei mit Spieldaten aus', dialogTitle: 'Wähle eine Datei mit Spieldaten aus',
type: FileType.custom, type: FileType.custom,
allowedExtensions: ['json'], allowedExtensions: ['json'],
); );
if (result == null) { if (path == null) {
print( print(
'[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen'); '[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen');
return ImportStatus.canceled; return ImportStatus.canceled;
} }
try { try {
final jsonString = await _readFileContent(result.files.single); final jsonString = await _readFileContent(path.files.single);
if (!await validateJsonSchema(jsonString)) { if (!await validateJsonSchema(jsonString)) {
return ImportStatus.validationError; return ImportStatus.validationError;

View File

@@ -1,6 +1,7 @@
import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_manager.dart';
import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/data/game_session.dart';
import 'package:cabo_counter/l10n/app_localizations.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/utility/custom_theme.dart';
import 'package:cabo_counter/views/create_game_view.dart'; import 'package:cabo_counter/views/create_game_view.dart';
import 'package:cabo_counter/views/graph_view.dart'; import 'package:cabo_counter/views/graph_view.dart';
@@ -192,14 +193,35 @@ class _ActiveGameViewState extends State<ActiveGameView> {
}, },
), ),
CupertinoListTile( CupertinoListTile(
title: title: Text(
Text(AppLocalizations.of(context).export_game, AppLocalizations.of(context).export_game,
style: const TextStyle( ),
color: Colors.white30, backgroundColorActivated:
)), CustomTheme.backgroundColor,
backgroundColorActivated: onTap: () async {
CustomTheme.backgroundColor, 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),
),
],
),
);
}
}),
], ],
) )
], ],

View File

@@ -140,7 +140,7 @@ class _SettingsViewState extends State<SettingsView> {
), ),
onPressed: () async { onPressed: () async {
final success = final success =
await LocalStorageService.exportJsonFile(); await LocalStorageService.exportGameData();
if (!success && context.mounted) { if (!success && context.mounted) {
showCupertinoDialog( showCupertinoDialog(
context: context, context: context,

View File

@@ -2,7 +2,7 @@ name: cabo_counter
description: "Mobile app for the card game Cabo" description: "Mobile app for the card game Cabo"
publish_to: 'none' publish_to: 'none'
version: 0.3.7+323 version: 0.3.7+325
environment: environment:
sdk: ^3.5.4 sdk: ^3.5.4