313 lines
14 KiB
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),
|
|
),
|
|
],
|
|
),
|
|
));
|
|
}
|