Client/lib/view/settings/settings.dart

313 lines
14 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../model/accountData.dart';
import '../../model/timetable/timetableProps.dart';
import '../../notification/notifyUpdater.dart';
import '../../storage/base/settingsProvider.dart';
import '../../theming/appTheme.dart';
import '../../widget/centeredLeading.dart';
import '../../widget/confirmDialog.dart';
import '../../widget/debug/cacheView.dart';
import '../pages/timetable/timetableNameMode.dart';
import 'defaultSettings.dart';
import 'devToolsSettings.dart';
import 'privacyInfo.dart';
class Settings extends StatefulWidget {
const Settings({super.key});
@override
State<Settings> createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
@override
void initState() {
super.initState();
}
bool developerMode = false;
@override
Widget build(BuildContext context) => Consumer<SettingsProvider>(builder: (context, settings, child) => Scaffold(
appBar: AppBar(
title: const Text('Einstellungen'),
),
body: ListView(
children: [
ListTile(
leading: const CenteredLeading(Icon(Icons.logout_outlined)),
title: const Text('Konto abmelden'),
subtitle: Text('Angemeldet als ${AccountData().getUsername()}'),
onTap: () {
showDialog(
context: context,
builder: (context) => ConfirmDialog(
title: 'Abmelden?',
content: 'Möchtest du dich wirklich abmelden?',
confirmButton: 'Abmelden',
onConfirm: () {
SharedPreferences.getInstance().then((value) => {
value.clear(),
}).then((value) async {
PaintingBinding.instance.imageCache.clear();
Provider.of<SettingsProvider>(context, listen: false).reset();
const CacheView().clear();
AccountData().removeData(context: context);
Navigator.popUntil(context, (route) => !Navigator.canPop(context));
});
},
),
);
},
),
const Divider(),
ListTile(
leading: const Icon(Icons.dark_mode_outlined),
title: const Text('Farbgebung'),
trailing: DropdownButton<ThemeMode>(
value: settings.val().appTheme,
icon: const Icon(Icons.arrow_drop_down),
items: ThemeMode.values.map((e) => DropdownMenuItem<ThemeMode>(
value: e,
enabled: e != settings.val().appTheme,
child: Row(
children: [
Icon(AppTheme.getDisplayOptions(e).icon),
const SizedBox(width: 10),
Text(AppTheme.getDisplayOptions(e).displayName),
],
),
)).toList(),
onChanged: (e) {
settings.val(write: true).appTheme = e!;
},
),
),
const Divider(),
ListTile(
leading: const Icon(Icons.abc_outlined),
title: const Text('Fachbezeichnung'),
trailing: DropdownButton<TimetableNameMode>(
value: settings.val().timetableSettings.timetableNameMode,
icon: Icon(Icons.arrow_drop_down),
items: TimetableNameMode.values.map((e) => DropdownMenuItem(
value: e,
enabled: e != settings.val().timetableSettings.timetableNameMode,
child: Row(
children: [
Icon(TimetableNameModes.getDisplayOptions(e).icon),
const SizedBox(width: 10),
Text(TimetableNameModes.getDisplayOptions(e).displayName),
],
),
)).toList(),
onChanged: (value) {
settings.val(write: true).timetableSettings.timetableNameMode = value!;
Provider.of<TimetableProps>(context, listen: false).run(renew: false);
},
)
),
ListTile(
leading: const Icon(Icons.calendar_view_day_outlined),
title: const Text('Doppelstunden zusammenhängend anzeigen'),
trailing: Checkbox(
value: settings.val().timetableSettings.connectDoubleLessons,
onChanged: (e) {
settings.val(write: true).timetableSettings.connectDoubleLessons = e!;
Provider.of<TimetableProps>(context, listen: false).run(renew: false);
},
),
),
const Divider(),
ListTile(
leading: const Icon(Icons.star_border),
title: const Text('Favoriten im Talk nach oben sortieren'),
trailing: Checkbox(
value: settings.val().talkSettings.sortFavoritesToTop,
onChanged: (e) {
settings.val(write: true).talkSettings.sortFavoritesToTop = e!;
},
),
),
ListTile(
leading: const Icon(Icons.mark_email_unread_outlined),
title: const Text('Ungelesene Chats nach oben sortieren'),
trailing: Checkbox(
value: settings.val().talkSettings.sortUnreadToTop,
onChanged: (e) {
settings.val(write: true).talkSettings.sortUnreadToTop = e!;
},
),
),
ListTile(
leading: const CenteredLeading(Icon(Icons.notifications_active_outlined)),
title: const Text('Push-Benachrichtigungen aktivieren'),
subtitle: const Text('Lange tippen für mehr Informationen'),
trailing: Checkbox(
value: settings.val().notificationSettings.enabled,
onChanged: (e) {
if(e!) {
NotifyUpdater.enableAfterDisclaimer(settings).asDialog(context);
} else {
settings.val(write: true).notificationSettings.enabled = e;
}
},
),
onLongPress: () => showDialog(context: context, builder: (context) => AlertDialog(
title: const Text('Info über Push'),
content: const SingleChildScrollView(child: Text(''
"Aufgrund technischer Limitationen müssen Push-Nachrichten über einen externen Server - hier 'mhsl.eu' (Author dieser App) - erfolgen.\n\n"
'Wenn Push aktiviert wird, werden deine Zugangsdaten und ein Token verschlüsselt an den Betreiber gesendet und von ihm unverschlüsselt gespeichert.\n\n'
'Der extene Server verwendet die Zugangsdaten um sich maschinell in Nextcloud Talk anzumelden und via Websockets auf neue Nachrichten zu warten.\n\n'
'Wenn eine neue Nachricht eintrifft wird dein Telefon via FBC-Messaging (Google Firebase Push) vom externen Server benachrichtigt.\n\n'
'Behalte im Hinterkopf, dass deine Zugangsdaten auf einem externen Server gespeichert werden und dies trotz bester Absichten ein Sicherheitsrisiko sein kann!'
)),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Zurück'))
],
)),
),
const Divider(),
ListTile(
leading: const Icon(Icons.drive_folder_upload_outlined),
title: const Text('Ordner in Dateien nach oben sortieren'),
trailing: Checkbox(
value: settings.val().fileSettings.sortFoldersToTop,
onChanged: (e) {
settings.val(write: true).fileSettings.sortFoldersToTop = e!;
},
),
),
ListTile(
leading: const Icon(Icons.open_in_new_outlined),
title: const Text('Dateien immer mit Systemdialog öffnen'),
trailing: Checkbox(
value: settings.val().fileViewSettings.alwaysOpenExternally,
onChanged: (e) {
settings.val(write: true).fileViewSettings.alwaysOpenExternally = e!;
},
),
),
const Divider(),
ListTile(
leading: const Icon(Icons.live_help_outlined),
title: const Text('Informationen und Lizenzen'),
onTap: () {
PackageInfo.fromPlatform().then((appInfo) {
showAboutDialog(
context: context,
applicationIcon: const Icon(Icons.apps),
applicationName: 'MarianumMobile',
applicationVersion: '${appInfo.appName}\n\nPackage: ${appInfo.packageName}\nVersion: ${appInfo.version}\nBuild: ${appInfo.buildNumber}',
applicationLegalese: 'Dies ist ein Inoffizieller Nextcloud & Webuntis Client und wird nicht vom Marianum selbst betrieben.\n'
'Keinerlei Gewähr für Vollständigkeit, Richtigkeit und Aktualität!\n\n'
"${kReleaseMode ? "Production" : "Development"} build\n"
'Marianum Fulda 2023-${Jiffy.now().year}\nElias Müller',
);
});
},
trailing: const Icon(Icons.arrow_right),
),
ListTile(
leading: const Icon(Icons.policy_outlined),
title: const Text('Impressum & Datenschutz'),
onTap: () {
showDialog(context: context, builder: (context) => SimpleDialog(
children: [
ListTile(
leading: const CenteredLeading(Icon(Icons.school_outlined)),
title: const Text('Infos zum Marianum Fulda'),
subtitle: const Text('Für Talk-Chats und Dateien'),
trailing: const Icon(Icons.arrow_right),
onTap: () => PrivacyInfo(providerText: 'Marianum', imprintUrl: 'https://www.marianum-fulda.de/impressum', privacyUrl: 'https://www.marianum-fulda.de/datenschutz').showPopup(context)
),
ListTile(
leading: const CenteredLeading(Icon(Icons.date_range_outlined)),
title: const Text('Infos zu Web-/ Untis'),
subtitle: const Text('Für den Vertretungsplan'),
trailing: const Icon(Icons.arrow_right),
onTap: () => PrivacyInfo(providerText: 'Untis', imprintUrl: 'https://www.untis.at/impressum', privacyUrl: 'https://www.untis.at/datenschutz-wu-apps').showPopup(context)
),
ListTile(
leading: const CenteredLeading(Icon(Icons.send_time_extension_outlined)),
title: const Text('Infos zu mhsl'),
subtitle: const Text('Für Countdowns, Marianum Message und mehr'),
trailing: const Icon(Icons.arrow_right),
onTap: () => PrivacyInfo(providerText: 'mhsl', imprintUrl: 'https://mhsl.eu/id.html', privacyUrl: 'https://mhsl.eu/datenschutz.html').showPopup(context),
),
],
));
},
trailing: const Icon(Icons.arrow_right),
),
const Divider(),
ListTile(
leading: const CenteredLeading(Icon(Icons.code)),
title: const Text('Quellcode MarianumMobile/Client'),
subtitle: const Text('GNU GPL v3'),
onTap: () => ConfirmDialog.openBrowser(context, 'https://mhsl.eu/gitea/MarianumMobile/Client'),
),
ListTile(
leading: const Icon(Icons.developer_mode_outlined),
title: const Text('Entwicklermodus'),
trailing: Checkbox(
value: settings.val().devToolsEnabled,
onChanged: (state) {
changeView() {
var enabled = state ?? false;
settings.val(write: true).devToolsEnabled = enabled;
if(!enabled) settings.val(write: true).devToolsSettings = DefaultSettings.get().devToolsSettings;
}
if(!state!) {
changeView();
return;
}
ConfirmDialog(
title: 'Entwicklermodus',
content: ''
'Die Entwickleransicht bietet erweiterte Funktionen, die für den üblichen Gebrauch nicht benötigt werden.\n\nDie Verwendung der Tools kann darüber hinaus bei falscher Verwendung zu Fehlern führen.\n\n'
'Aktivieren auf eigene Verantwortung.',
confirmButton: 'Ja, ich verstehe das Risiko',
cancelButton: 'Nein, zurück zur App',
onConfirm: changeView,
).asDialog(context);
},
),
),
Visibility(
visible: settings.val().devToolsEnabled,
child: DevToolsSettings(settings: settings),
),
],
),
));
}