From 22ac2efea2821d55c7361851a6b69242c7f0e44f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 1 May 2025 00:41:35 +0200 Subject: [PATCH] Implemented exportJsonFile & importJsonFile methods --- lib/utility/local_storage_service.dart | 103 +++++++++++++++++++------ lib/views/information_view.dart | 10 +-- pubspec.yaml | 5 +- 3 files changed, 88 insertions(+), 30 deletions(-) diff --git a/lib/utility/local_storage_service.dart b/lib/utility/local_storage_service.dart index 79aee1e..ce9c762 100644 --- a/lib/utility/local_storage_service.dart +++ b/lib/utility/local_storage_service.dart @@ -1,17 +1,34 @@ import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/utility/globals.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:file_saver/file_saver.dart'; import 'package:path_provider/path_provider.dart'; class LocalStorageService { static const String _fileName = 'game_data.json'; - /// Speichert GameSessions im App-Dokumentenverzeichnis + /// Writes the game session list to a JSON file and returns it as string. + static String getJsonFile() { + final jsonFile = + Globals.gameList.map((session) => session.toJson()).toList(); + return json.encode(jsonFile); + } + + /// Returns the path to the local JSON file. + static Future _getFilePath() async { + final directory = await getApplicationDocumentsDirectory(); + final path = '${directory.path}/$_fileName'; + return File(path); + } + + /// Saves the game sessions to a local JSON file. static Future saveGameSessions() async { try { - final file = await _getLocalFile(); + final file = await _getFilePath(); final jsonFile = getJsonFile(); await file.writeAsString(jsonFile); print('Daten gespeichert'); @@ -20,44 +37,82 @@ class LocalStorageService { } } - /// Lädt GameSessions aus dem App-Dokumentenverzeichnis + /// Loads the game data from a local JSON file. static Future loadGameSessions() async { - print('Versuche, Daten zu laden...'); // FIXME Debug-Ausgabe + print('Versuche, Daten zu laden...'); try { - final file = await _getLocalFile(); + final file = await _getFilePath(); if (await file.exists()) { - print('Datei existiert'); // FIXME Debug-Ausgabe + print('Es existiert bereits eine Datei mit Spieldaten'); final jsonString = await file.readAsString(); if (jsonString.isNotEmpty) { - print('Datei ist nicht leer'); // FIXME Debug-Ausgabe + print('Die Datei ist nicht leer'); final jsonList = json.decode(jsonString) as List; - print('JSON: $jsonList'); // FIXME Debug-Ausgabe - Globals.gameList = - jsonList.map((json) => GameSession.fromJson(json)).toList(); - print('Daten erfolgreich geladen'); + print('JSON: $jsonList'); + Globals.gameList = jsonList + .map((jsonItem) => + GameSession.fromJson(jsonItem as Map)) + .toList() + .cast(); // Explicit cast to List + print('Die Daten wurden erfolgreich geladen'); } else { - print('Datei ist leer'); + print('Die Datei ist leer'); } } else { - print('Datei existiert nicht'); + print('Es existiert bisher noch keine Datei mit Spieldaten'); } } catch (e) { - print('Fehler beim Laden: $e'); - // Bei Fehler eine leere Liste setzen + print('Fehler beim Laden der Spieldaten:\n$e'); Globals.gameList = []; } } - static String getJsonFile() { - final jsonFile = - Globals.gameList.map((session) => session.toJson()).toList(); - return json.encode(jsonFile); + /// Opens the file picker to save a JSON file with the current game data. + static Future exportJsonFile() async { + final jsonString = getJsonFile(); + try { + final bytes = Uint8List.fromList(utf8.encode(jsonString)); + final result = await FileSaver.instance.saveAs( + name: 'cabo_counter_data', + bytes: bytes, + ext: 'json', + mimeType: MimeType.json, + ); + print('Datei gespeichert: $result'); + } catch (e) { + print('Fehler beim Speichern: $e'); + } } - static Future _getLocalFile() async { - final directory = await getApplicationDocumentsDirectory(); - final path = '${directory.path}/$_fileName'; - print('Speicherpfad: $path'); // FIXME Debug-Ausgabe - return File(path); + static Future importJsonFile() async { + try { + final result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['json'], + ); + String jsonString = ''; + if (result != null) { + if (result.files.single.bytes != null) { + final Uint8List fileBytes = result.files.single.bytes!; + jsonString = utf8.decode(fileBytes); + } else if (result.files.single.path != null) { + final file = File(result.files.single.path!); + jsonString = await file.readAsString(); + } + final jsonList = json.decode(jsonString) as List; + print('JSON Inhalt: $jsonList'); + Globals.gameList = jsonList + .map((jsonItem) => + GameSession.fromJson(jsonItem as Map)) + .toList(); + return true; + } else { + print('Der Dialog wurde abgebrochen'); + return false; + } + } catch (e) { + print('Fehler beim Importieren: $e'); + return false; + } } } diff --git a/lib/views/information_view.dart b/lib/views/information_view.dart index d64f2ff..04b51a4 100644 --- a/lib/views/information_view.dart +++ b/lib/views/information_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/utility/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -83,7 +84,10 @@ class InformationView extends StatelessWidget { ), CupertinoButton( child: const Text('Spieldaten exportieren'), - onPressed: () => {saveJsonToDevice()}) + onPressed: () => LocalStorageService.exportJsonFile()), + CupertinoButton( + child: const Text('Spieldaten importieren'), + onPressed: () => LocalStorageService.importJsonFile()), ], ), Positioned( @@ -115,8 +119,4 @@ class InformationView extends StatelessWidget { ], ))); } - - void saveJsonToDevice() async { - //todo: implement - } } diff --git a/pubspec.yaml b/pubspec.yaml index 76baaef..36e7f73 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.1.3+103 +version: 0.1.3+107 environment: sdk: ^3.5.4 @@ -17,6 +17,9 @@ dependencies: flutter_keyboard_visibility: ^6.0.0 path_provider: ^2.1.1 file_picker: any + file_saver: ^0.2.6 + typed_data: ^1.3.2 + dev_dependencies: flutter_test: