Merge pull request #71 from flixcoo/enhance/68-improve-file-import
Improve file import
This commit is contained in:
@@ -81,7 +81,16 @@
|
|||||||
"import_data": "Daten importieren",
|
"import_data": "Daten importieren",
|
||||||
"export_data": "Daten exportieren",
|
"export_data": "Daten exportieren",
|
||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
"error_import": "Datei konnte nicht importiert werden",
|
|
||||||
|
"import_success_title": "Import erfolgreich",
|
||||||
|
"import_success_message":"Die Spieldaten wurden erfolgreich importiert.",
|
||||||
|
"import_validation_error_title": "Validierung fehlgeschlagen",
|
||||||
|
"import_validation_error_message": "Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.",
|
||||||
|
"import_format_error_title": "Falsches Format",
|
||||||
|
"import_format_error_message": "Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.",
|
||||||
|
"import_generic_error_title": "Import fehlgeschlagen",
|
||||||
|
"import_generic_error_message": "Der Import ist fehlgeschlagen.",
|
||||||
|
|
||||||
"error_export": "Datei konnte nicht exportiert werden",
|
"error_export": "Datei konnte nicht exportiert werden",
|
||||||
"error_found": "Fehler gefunden?",
|
"error_found": "Fehler gefunden?",
|
||||||
"create_issue": "Issue erstellen",
|
"create_issue": "Issue erstellen",
|
||||||
|
|||||||
@@ -81,7 +81,16 @@
|
|||||||
"import_data": "Import Data",
|
"import_data": "Import Data",
|
||||||
"export_data": "Export Data",
|
"export_data": "Export Data",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"error_import": "Could not import file",
|
|
||||||
|
"import_success_title": "Import successful",
|
||||||
|
"import_success_message":"The game data has been successfully imported.",
|
||||||
|
"import_validation_error_title": "Validation failed",
|
||||||
|
"import_validation_error_message": "No Cabo-Counter game data was found. Please make sure that this is a valid Cabo-Counter export file.",
|
||||||
|
"import_format_error_title": "Wrong format",
|
||||||
|
"import_format_error_message": "The file is not a valid JSON format or contains invalid data.",
|
||||||
|
"import_generic_error_title": "Import failed",
|
||||||
|
"import_generic_error_message": "The import has failed.",
|
||||||
|
|
||||||
"error_export": "Could not export file",
|
"error_export": "Could not export file",
|
||||||
"error_found": "Found a bug?",
|
"error_found": "Found a bug?",
|
||||||
"create_issue": "Create Issue",
|
"create_issue": "Create Issue",
|
||||||
|
|||||||
@@ -452,11 +452,53 @@ abstract class AppLocalizations {
|
|||||||
/// **'Fehler'**
|
/// **'Fehler'**
|
||||||
String get error;
|
String get error;
|
||||||
|
|
||||||
/// No description provided for @error_import.
|
/// No description provided for @import_success_title.
|
||||||
///
|
///
|
||||||
/// In de, this message translates to:
|
/// In de, this message translates to:
|
||||||
/// **'Datei konnte nicht importiert werden'**
|
/// **'Import erfolgreich'**
|
||||||
String get error_import;
|
String get import_success_title;
|
||||||
|
|
||||||
|
/// No description provided for @import_success_message.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Die Spieldaten wurden erfolgreich importiert.'**
|
||||||
|
String get import_success_message;
|
||||||
|
|
||||||
|
/// No description provided for @import_validation_error_title.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Validierung fehlgeschlagen'**
|
||||||
|
String get import_validation_error_title;
|
||||||
|
|
||||||
|
/// No description provided for @import_validation_error_message.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.'**
|
||||||
|
String get import_validation_error_message;
|
||||||
|
|
||||||
|
/// No description provided for @import_format_error_title.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Falsches Format'**
|
||||||
|
String get import_format_error_title;
|
||||||
|
|
||||||
|
/// No description provided for @import_format_error_message.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.'**
|
||||||
|
String get import_format_error_message;
|
||||||
|
|
||||||
|
/// No description provided for @import_generic_error_title.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Import fehlgeschlagen'**
|
||||||
|
String get import_generic_error_title;
|
||||||
|
|
||||||
|
/// No description provided for @import_generic_error_message.
|
||||||
|
///
|
||||||
|
/// In de, this message translates to:
|
||||||
|
/// **'Der Import ist fehlgeschlagen.'**
|
||||||
|
String get import_generic_error_message;
|
||||||
|
|
||||||
/// No description provided for @error_export.
|
/// No description provided for @error_export.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -195,7 +195,31 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get error => 'Fehler';
|
String get error => 'Fehler';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_import => 'Datei konnte nicht importiert werden';
|
String get import_success_title => 'Import erfolgreich';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_success_message =>
|
||||||
|
'Die Spieldaten wurden erfolgreich importiert.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_validation_error_title => 'Validierung fehlgeschlagen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_validation_error_message =>
|
||||||
|
'Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_format_error_title => 'Falsches Format';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_format_error_message =>
|
||||||
|
'Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_generic_error_title => 'Import fehlgeschlagen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_generic_error_message => 'Der Import ist fehlgeschlagen.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_export => 'Datei konnte nicht exportiert werden';
|
String get error_export => 'Datei konnte nicht exportiert werden';
|
||||||
|
|||||||
@@ -192,7 +192,31 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get error => 'Error';
|
String get error => 'Error';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_import => 'Could not import file';
|
String get import_success_title => 'Import successful';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_success_message =>
|
||||||
|
'The game data has been successfully imported.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_validation_error_title => 'Validation failed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_validation_error_message =>
|
||||||
|
'No Cabo-Counter game data was found. Please make sure that this is a valid Cabo-Counter export file.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_format_error_title => 'Wrong format';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_format_error_message =>
|
||||||
|
'The file is not a valid JSON format or contains invalid data.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_generic_error_title => 'Import failed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_generic_error_message => 'The import has failed.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_export => 'Could not export file';
|
String get error_export => 'Could not export file';
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:json_schema/json_schema.dart';
|
import 'package:json_schema/json_schema.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
enum ImportStatus {
|
||||||
|
success,
|
||||||
|
canceled,
|
||||||
|
validationError,
|
||||||
|
formatError,
|
||||||
|
genericError
|
||||||
|
}
|
||||||
|
|
||||||
class LocalStorageService {
|
class LocalStorageService {
|
||||||
static const String _fileName = 'game_data.json';
|
static const String _fileName = 'game_data.json';
|
||||||
|
|
||||||
@@ -111,7 +119,7 @@ class LocalStorageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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<bool> importJsonFile() async {
|
static Future<ImportStatus> importJsonFile() async {
|
||||||
final result = await FilePicker.platform.pickFiles(
|
final result = 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,
|
||||||
@@ -121,14 +129,14 @@ class LocalStorageService {
|
|||||||
if (result == null) {
|
if (result == null) {
|
||||||
print(
|
print(
|
||||||
'[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen');
|
'[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen');
|
||||||
return false;
|
return ImportStatus.canceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final jsonString = await _readFileContent(result.files.single);
|
final jsonString = await _readFileContent(result.files.single);
|
||||||
|
|
||||||
if (!await validateJsonSchema(jsonString)) {
|
if (!await validateJsonSchema(jsonString)) {
|
||||||
return false;
|
return ImportStatus.validationError;
|
||||||
}
|
}
|
||||||
final jsonData = json.decode(jsonString) as List<dynamic>;
|
final jsonData = json.decode(jsonString) as List<dynamic>;
|
||||||
gameManager.gameList = jsonData
|
gameManager.gameList = jsonData
|
||||||
@@ -137,15 +145,16 @@ class LocalStorageService {
|
|||||||
.toList();
|
.toList();
|
||||||
print(
|
print(
|
||||||
'[local_storage_service.dart] Die Datei wurde erfolgreich Importiertn');
|
'[local_storage_service.dart] Die Datei wurde erfolgreich Importiertn');
|
||||||
return true;
|
await saveGameSessions();
|
||||||
|
return ImportStatus.success;
|
||||||
} on FormatException catch (e) {
|
} on FormatException catch (e) {
|
||||||
print(
|
print(
|
||||||
'[local_storage_service.dart] Ungültiges JSON-Format. Exception: $e');
|
'[local_storage_service.dart] Ungültiges JSON-Format. Exception: $e');
|
||||||
return false;
|
return ImportStatus.formatError;
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
print(
|
print(
|
||||||
'[local_storage_service.dart] Fehler beim Dateizugriff. Exception: $e');
|
'[local_storage_service.dart] Fehler beim Dateizugriff. Exception: $e');
|
||||||
return false;
|
return ImportStatus.genericError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,27 +125,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final success =
|
final success =
|
||||||
await LocalStorageService.importJsonFile();
|
await LocalStorageService.importJsonFile();
|
||||||
if (!success && context.mounted) {
|
showFeedbackDialog(success);
|
||||||
showCupertinoDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => CupertinoAlertDialog(
|
|
||||||
title: Text(
|
|
||||||
AppLocalizations.of(context)
|
|
||||||
.error),
|
|
||||||
content: Text(
|
|
||||||
AppLocalizations.of(context)
|
|
||||||
.error_import),
|
|
||||||
actions: [
|
|
||||||
CupertinoDialogAction(
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)
|
|
||||||
.ok),
|
|
||||||
onPressed: () =>
|
|
||||||
Navigator.pop(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
@@ -236,4 +216,52 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
Future<PackageInfo> _getPackageInfo() async {
|
Future<PackageInfo> _getPackageInfo() async {
|
||||||
return await PackageInfo.fromPlatform();
|
return await PackageInfo.fromPlatform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showFeedbackDialog(ImportStatus status) {
|
||||||
|
if (status == ImportStatus.canceled) return;
|
||||||
|
final (title, message) = _getDialogContent(status);
|
||||||
|
|
||||||
|
showCupertinoDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return CupertinoAlertDialog(
|
||||||
|
title: Text(title),
|
||||||
|
content: Text(message),
|
||||||
|
actions: [
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: Text(AppLocalizations.of(context).ok),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
(String, String) _getDialogContent(ImportStatus status) {
|
||||||
|
switch (status) {
|
||||||
|
case ImportStatus.success:
|
||||||
|
return (
|
||||||
|
AppLocalizations.of(context).import_success_title,
|
||||||
|
AppLocalizations.of(context).import_success_message
|
||||||
|
);
|
||||||
|
case ImportStatus.validationError:
|
||||||
|
return (
|
||||||
|
AppLocalizations.of(context).import_validation_error_title,
|
||||||
|
AppLocalizations.of(context).import_validation_error_message
|
||||||
|
);
|
||||||
|
|
||||||
|
case ImportStatus.formatError:
|
||||||
|
return (
|
||||||
|
AppLocalizations.of(context).import_format_error_title,
|
||||||
|
AppLocalizations.of(context).import_format_error_message
|
||||||
|
);
|
||||||
|
case ImportStatus.genericError:
|
||||||
|
return (
|
||||||
|
AppLocalizations.of(context).import_generic_error_title,
|
||||||
|
AppLocalizations.of(context).import_generic_error_message
|
||||||
|
);
|
||||||
|
case ImportStatus.canceled:
|
||||||
|
return ('', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.3+256
|
version: 0.3.3+265
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
|
|||||||
Reference in New Issue
Block a user