Skip to content

Commit

Permalink
feat: Add network timeout setting, reorder settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustl22 committed Mar 5, 2024
1 parent 3bec47a commit d63e7ce
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 110 deletions.
2 changes: 2 additions & 0 deletions wrestling_scoreboard_client/lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"themeModeDark": "Dunkler Modus",
"apiUrl": "Api-Url",
"wsUrl": "Websocket-Url",
"database": "Datenbank",
"exportDatabase": "Datenbank exportieren",
"restoreDatabase": "Datenbank wiederherstellen",
"restoreDefaultDatabase": "Standard-Datenbank wiederherstellen",
Expand Down Expand Up @@ -55,6 +56,7 @@
"invalidParameterException": "Die Änderung war nicht erfolgreich, bitte überprüfe deine Eingabeparameter.",
"warningBoutGenerate": "Diese Aktion überschreibt alle existierenden Kämpfe dieser Begegnung. Um einzelne Kämpfe zu bearbeiten, nutze die Seite zur Kampf-Bearbeitung. Bist du sicher, dass du fortfahren möchtest?",
"retry": "Erneut versuchen",
"networkTimeout": "Netzwerk-Timeout",

"date": "Datum",
"place": "Ort",
Expand Down
2 changes: 2 additions & 0 deletions wrestling_scoreboard_client/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"themeModeDark": "Dark mode",
"apiUrl": "Api-Url",
"wsUrl": "Websocket-Url",
"database": "Database",
"exportDatabase": "Export database",
"restoreDatabase": "Restore database",
"restoreDefaultDatabase": "Restore default database",
Expand Down Expand Up @@ -58,6 +59,7 @@
"invalidParameterException": "The change was not successful, please check your input parameters.",
"warningBoutGenerate": "This action overrides all existing bouts of this match. To edit single bouts, use the bout editing page. Are you sure, you want to continue?",
"retry": "Retry",
"networkTimeout": "Network timeout",

"date": "Date",
"place": "Place",
Expand Down
6 changes: 5 additions & 1 deletion wrestling_scoreboard_client/lib/localization/duration.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extension DurationLocalization on Duration {
String formatMinutesAndSeconds() {
return '${inMinutes.remainder(60)}:${inSeconds.remainder(60).toString().padLeft(2, '0')}';
return '$inMinutes:${inSeconds.remainder(60).toString().padLeft(2, '0')}';
}

String formatSecondsAndMilliseconds() {
return '$inSeconds.${inMilliseconds.remainder(1000).toString().padLeft(3, '0')}s';
}
}
11 changes: 11 additions & 0 deletions wrestling_scoreboard_client/lib/provider/local_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Preferences {
static const keyApiUrl = 'api-url';
static const keyWsUrl = 'ws-url';
static const keyBellSound = 'bell-sound';

/// Network timeout in milliseconds.
static const keyNetworkTimeout = 'network-timeout';

static final StreamController<Locale?> onChangeLocale = StreamController.broadcast();
Expand All @@ -32,6 +34,15 @@ class Preferences {
}
}

static Future<void> setInt(String key, int? value) async {
final prefs = await SharedPreferences.getInstance();
if (value != null) {
await prefs.setInt(key, value);
} else {
await prefs.remove(key);
}
}

static Future<String?> getString(String key) => SharedPreferences.getInstance().then((value) => value.getString(key));

static Future<int?> getInt(String key) => SharedPreferences.getInstance().then((value) => value.getInt(key));
Expand Down
252 changes: 143 additions & 109 deletions wrestling_scoreboard_client/lib/view/screens/more/settings/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:wrestling_scoreboard_client/localization/duration.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences_provider.dart';
import 'package:wrestling_scoreboard_client/provider/network_provider.dart';
Expand Down Expand Up @@ -129,115 +130,6 @@ class CustomSettingsScreen extends ConsumerWidget {
);
},
),
LoadingBuilder<String>(
future: ref.watch(apiUrlNotifierProvider),
builder: (context, apiUrl) {
return LoadingBuilder<String>(
future: ref.watch(webSocketUrlNotifierProvider),
builder: (context, wsUrl) {
return SettingsSection(
title: localizations.network,
action: TextButton(
onPressed: () {
apiUrl = Env.apiUrl.fromString();
Preferences.setString(Preferences.keyApiUrl, apiUrl);
Preferences.onChangeApiUrl.add(apiUrl);

wsUrl = Env.webSocketUrl.fromString();
Preferences.setString(Preferences.keyWsUrl, wsUrl);
Preferences.onChangeWsUrlWebSocket.add(wsUrl);
},
child: Text(localizations.reset),
),
children: [
ListTile(
subtitle: Text(apiUrl),
title: Text(localizations.apiUrl),
leading: const Icon(Icons.link),
onTap: () async {
final val = await showDialog<String>(
context: context,
builder: (BuildContext context) {
return TextInputDialog(initialValue: apiUrl);
},
);
if (val != null) {
Preferences.onChangeApiUrl.add(val);
await Preferences.setString(Preferences.keyApiUrl, val);
}
},
),
ListTile(
leading: const Icon(Icons.link),
title: Text(localizations.wsUrl),
subtitle: Text(wsUrl),
onTap: () async {
final val = await showDialog<String?>(
context: context,
builder: (BuildContext context) {
return TextInputDialog(initialValue: wsUrl);
},
);
if (val != null) {
Preferences.onChangeWsUrlWebSocket.add(val);
await Preferences.setString(Preferences.keyWsUrl, val);
}
},
),
ListTile(
leading: const Icon(Icons.cloud_download),
title: Text(localizations.exportDatabase),
onTap: () async {
String? outputPath = await FilePicker.platform.saveFile(
fileName:
'${DateTime.now().toIso8601String().replaceAll(':', '-').replaceAll(RegExp(r'\.[0-9]{3}'), '')}-'
'PostgreSQL-wrestling_scoreboard-dump.sql',
);
if (outputPath != null) {
final dataManager = await ref.read(dataManagerNotifierProvider);
final sqlString = await dataManager.exportDatabase();
final outputFile = File(outputPath);
await outputFile.writeAsString(sqlString, encoding: const Utf8Codec());
}
},
),
ListTile(
leading: const Icon(Icons.settings_backup_restore),
title: Text(localizations.resetDatabase),
onTap: () async {
final dataManager = await ref.read(dataManagerNotifierProvider);
await dataManager.resetDatabase();
},
),
ListTile(
leading: const Icon(Icons.history),
title: Text(localizations.restoreDefaultDatabase),
onTap: () async {
final dataManager = await ref.read(dataManagerNotifierProvider);
await dataManager.restoreDefaultDatabase();
},
),
ListTile(
leading: const Icon(Icons.cloud_upload),
title: Text(localizations.restoreDatabase),
onTap: () async {
FilePickerResult? filePickerResult = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['sql'],
);
if (filePickerResult != null) {
File file = File(filePickerResult.files.single.path!);
final dataManager = await ref.read(dataManagerNotifierProvider);
await dataManager.restoreDatabase(await file.readAsString(encoding: const Utf8Codec()));
}
},
),
],
);
},
);
},
),
LoadingBuilder<String>(
future: ref.watch(bellSoundNotifierProvider),
builder: (context, bellSoundPath) {
Expand Down Expand Up @@ -293,6 +185,148 @@ class CustomSettingsScreen extends ConsumerWidget {
);
},
),
LoadingBuilder<Duration>(
future: ref.watch(networkTimeoutNotifierProvider),
builder: (context, networkTimeout) {
return LoadingBuilder<String>(
future: ref.watch(apiUrlNotifierProvider),
builder: (context, apiUrl) {
return LoadingBuilder<String>(
future: ref.watch(webSocketUrlNotifierProvider),
builder: (context, wsUrl) {
return SettingsSection(
title: localizations.network,
action: TextButton(
onPressed: () {
apiUrl = Env.apiUrl.fromString();
Preferences.setString(Preferences.keyApiUrl, apiUrl);
Preferences.onChangeApiUrl.add(apiUrl);

wsUrl = Env.webSocketUrl.fromString();
Preferences.setString(Preferences.keyWsUrl, wsUrl);
Preferences.onChangeWsUrlWebSocket.add(wsUrl);

const defaultNetworkTimeout = Duration(seconds: 10);
Preferences.setInt(Preferences.keyNetworkTimeout, defaultNetworkTimeout.inMilliseconds);
Preferences.onChangeNetworkTimeout.add(defaultNetworkTimeout);
},
child: Text(localizations.reset),
),
children: [
ListTile(
subtitle: Text(apiUrl),
title: Text(localizations.apiUrl),
leading: const Icon(Icons.link),
onTap: () async {
final val = await showDialog<String>(
context: context,
builder: (BuildContext context) {
return TextInputDialog(initialValue: apiUrl);
},
);
if (val != null) {
Preferences.onChangeApiUrl.add(val);
await Preferences.setString(Preferences.keyApiUrl, val);
}
},
),
ListTile(
leading: const Icon(Icons.link),
title: Text(localizations.wsUrl),
subtitle: Text(wsUrl),
onTap: () async {
final val = await showDialog<String?>(
context: context,
builder: (BuildContext context) {
return TextInputDialog(initialValue: wsUrl);
},
);
if (val != null) {
Preferences.onChangeWsUrlWebSocket.add(val);
await Preferences.setString(Preferences.keyWsUrl, val);
}
},
),
ListTile(
leading: const Icon(Icons.running_with_errors),
title: Text(localizations.networkTimeout),
subtitle: Text(networkTimeout.formatSecondsAndMilliseconds()),
onTap: () async {
final val = await showDialog<Duration?>(
context: context,
builder: (BuildContext context) {
return DurationDialog(
initialValue: networkTimeout,
maxValue: const Duration(hours: 1),
);
},
);
if (val != null) {
Preferences.onChangeNetworkTimeout.add(val);
await Preferences.setInt(Preferences.keyNetworkTimeout, val.inMilliseconds);
}
},
),
],
);
},
);
},
);
}),
SettingsSection(
title: localizations.database,
children: [
ListTile(
leading: const Icon(Icons.cloud_download),
title: Text(localizations.exportDatabase),
onTap: () async {
String? outputPath = await FilePicker.platform.saveFile(
fileName:
'${DateTime.now().toIso8601String().replaceAll(':', '-').replaceAll(RegExp(r'\.[0-9]{3}'), '')}-'
'PostgreSQL-wrestling_scoreboard-dump.sql',
);
if (outputPath != null) {
final dataManager = await ref.read(dataManagerNotifierProvider);
final sqlString = await dataManager.exportDatabase();
final outputFile = File(outputPath);
await outputFile.writeAsString(sqlString, encoding: const Utf8Codec());
}
},
),
ListTile(
leading: const Icon(Icons.settings_backup_restore),
title: Text(localizations.resetDatabase),
onTap: () async {
final dataManager = await ref.read(dataManagerNotifierProvider);
await dataManager.resetDatabase();
},
),
ListTile(
leading: const Icon(Icons.history),
title: Text(localizations.restoreDefaultDatabase),
onTap: () async {
final dataManager = await ref.read(dataManagerNotifierProvider);
await dataManager.restoreDefaultDatabase();
},
),
ListTile(
leading: const Icon(Icons.cloud_upload),
title: Text(localizations.restoreDatabase),
onTap: () async {
FilePickerResult? filePickerResult = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['sql'],
);
if (filePickerResult != null) {
File file = File(filePickerResult.files.single.path!);
final dataManager = await ref.read(dataManagerNotifierProvider);
await dataManager.restoreDatabase(await file.readAsString(encoding: const Utf8Codec()));
}
},
),
],
),
],
),
);
Expand Down

0 comments on commit d63e7ce

Please sign in to comment.