import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart'; import 'package:game_tracker/services/data_transfer_service.dart'; import 'package:json_schema/json_schema.dart'; class SettingsView extends StatefulWidget { const SettingsView({super.key}); @override State createState() => _SettingsViewState(); static Future validateJsonSchema(String jsonString) async { final String schemaString; schemaString = await rootBundle.loadString('assets/schema.json'); try { final schema = JsonSchema.create(json.decode(schemaString)); final jsonData = json.decode(jsonString); final result = schema.validate(jsonData); if (result.isValid) { return true; } return false; } catch (e, stack) { print('[validateJsonSchema] $e'); print(stack); return false; } } } class _SettingsViewState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(backgroundColor: CustomTheme.backgroundColor), backgroundColor: CustomTheme.backgroundColor, body: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) => SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Padding( padding: EdgeInsets.fromLTRB(24, 0, 24, 10), child: Text( textAlign: TextAlign.start, 'Menu', style: TextStyle( fontSize: 28, fontWeight: FontWeight.bold, ), ), ), const Padding( padding: EdgeInsets.symmetric(horizontal: 24, vertical: 10), child: Text( textAlign: TextAlign.start, 'Settings', style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, ), ), ), SettingsListTile( title: 'Export data', icon: Icons.upload_outlined, suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), onPressed: () async { final String json = await DataTransferService.getAppDataAsJson(context); final result = await DataTransferService.exportData( json, 'game_tracker-data', ); if (!context.mounted) return; showExportSnackBar(context: context, result: result); }, ), SettingsListTile( title: 'Import data', icon: Icons.download_outlined, suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), onPressed: () async { final result = await DataTransferService.importData( context, ); if (!context.mounted) return; showImportSnackBar(context: context, result: result); }, ), SettingsListTile( title: 'Delete all data', icon: Icons.download_outlined, suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), onPressed: () { DataTransferService.deleteAllData(context); showSnackbar( context: context, message: 'Data successfully deleted', ); }, ), ], ), ), ), ); } /// Displays a snackbar based on the import result. /// /// [context] The BuildContext to show the snackbar in. /// [result] The result of the import operation. void showImportSnackBar({ required BuildContext context, required ImportResult result, }) { switch (result) { case ImportResult.success: showSnackbar(context: context, message: 'Data successfully imported'); case ImportResult.invalidSchema: showSnackbar(context: context, message: 'Invalid Schema'); case ImportResult.fileReadError: showSnackbar(context: context, message: 'Error reading file'); case ImportResult.canceled: showSnackbar(context: context, message: 'Import canceled'); case ImportResult.formatException: showSnackbar( context: context, message: 'Format Exception (see console)', ); case ImportResult.unknownException: showSnackbar( context: context, message: 'Unknown Exception (see console)', ); } } /// Displays a snackbar based on the export result. /// /// [context] The BuildContext to show the snackbar in. /// [result] The result of the export operation. void showExportSnackBar({ required BuildContext context, required ExportResult result, }) { switch (result) { case ExportResult.success: showSnackbar(context: context, message: 'Data successfully exported'); case ExportResult.canceled: showSnackbar(context: context, message: 'Export canceled'); case ExportResult.unknownException: showSnackbar( context: context, message: 'Unknown Exception (see console)', ); } } /// Displays a snackbar with the given message and optional action. /// /// [context] The BuildContext to show the snackbar in. /// [message] The message to display in the snackbar. /// [duration] The duration for which the snackbar is displayed. /// [action] An optional callback function to execute when the action button is pressed. void showSnackbar({ required BuildContext context, required String message, Duration duration = const Duration(seconds: 3), VoidCallback? action, }) { final messenger = ScaffoldMessenger.of(context); messenger.hideCurrentSnackBar(); messenger.showSnackBar( SnackBar( content: Text(message, style: const TextStyle(color: Colors.white)), backgroundColor: CustomTheme.onBoxColor, duration: duration, action: action != null ? SnackBarAction(label: 'Rückgängig', onPressed: action) : null, ), ); } }