folder restructuring
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../state/app/modules/app_modules.dart';
|
||||
import '../../../../storage/base/settings.dart';
|
||||
import '../../../../storage/devTools/devToolsSettings.dart';
|
||||
import '../../../../storage/file/fileSettings.dart';
|
||||
import '../../../../storage/fileView/fileViewSettings.dart';
|
||||
import '../../../../storage/general/modulesSettings.dart';
|
||||
import '../../../../storage/holidays/holidaysSettings.dart';
|
||||
import '../../../../storage/notification/notificationSettings.dart';
|
||||
import '../../../../storage/talk/talkSettings.dart';
|
||||
import '../../../../storage/timetable/timetable_name_mode.dart';
|
||||
import '../../../../storage/timetable/timetableSettings.dart';
|
||||
import '../../files/files.dart';
|
||||
|
||||
class DefaultSettings {
|
||||
static Settings get() => Settings(
|
||||
appTheme: ThemeMode.system,
|
||||
devToolsEnabled: false,
|
||||
modulesSettings: ModulesSettings(
|
||||
moduleOrder: [
|
||||
Modules.timetable,
|
||||
Modules.talk,
|
||||
Modules.files,
|
||||
Modules.marianumMessage,
|
||||
Modules.roomPlan,
|
||||
Modules.gradeAveragesCalculator,
|
||||
Modules.holidays,
|
||||
Modules.marianumDates,
|
||||
],
|
||||
hiddenModules: [],
|
||||
),
|
||||
timetableSettings: TimetableSettings(
|
||||
connectDoubleLessons: true,
|
||||
timetableNameMode: TimetableNameMode.name
|
||||
),
|
||||
talkSettings: TalkSettings(
|
||||
sortFavoritesToTop: true,
|
||||
sortUnreadToTop: false,
|
||||
drafts: {},
|
||||
draftReplies: {},
|
||||
),
|
||||
fileSettings: FileSettings(
|
||||
sortFoldersToTop: true,
|
||||
ascending: true,
|
||||
sortBy: SortOption.name
|
||||
),
|
||||
holidaysSettings: HolidaysSettings(
|
||||
dismissedDisclaimer: false,
|
||||
showPastEvents: false,
|
||||
),
|
||||
fileViewSettings: FileViewSettings(
|
||||
alwaysOpenExternally: Platform.isIOS,
|
||||
),
|
||||
notificationSettings: NotificationSettings(
|
||||
askUsageDismissed: false,
|
||||
enabled: false,
|
||||
),
|
||||
devToolsSettings: DevToolsSettings(
|
||||
checkerboardOffscreenLayers: false,
|
||||
checkerboardRasterCacheImages: false,
|
||||
showPerformanceOverlay: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../widget/centered_leading.dart';
|
||||
import '../../../../widget/confirm_dialog.dart';
|
||||
import '../data/default_settings.dart';
|
||||
import '../widgets/privacy_info.dart';
|
||||
import 'dev_tools_section.dart';
|
||||
|
||||
class AboutSection extends StatelessWidget {
|
||||
const AboutSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = context.read<SettingsCubit>();
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.live_help_outlined),
|
||||
title: const Text('Informationen und Lizenzen'),
|
||||
onTap: () => _showAppInfo(context),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.policy_outlined),
|
||||
title: const Text('Impressum & Datenschutz'),
|
||||
onTap: () => _showPrivacyDialog(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) => _toggleDeveloperMode(context, settings, state),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: settings.val().devToolsEnabled,
|
||||
child: DevToolsSection(settings: settings),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showAppInfo(BuildContext context) async {
|
||||
final appInfo = await PackageInfo.fromPlatform();
|
||||
if (!context.mounted) return;
|
||||
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',
|
||||
);
|
||||
}
|
||||
|
||||
void _showPrivacyDialog(BuildContext context) => 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 Stundenplan'),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
void _toggleDeveloperMode(BuildContext context, SettingsCubit settings, bool? state) {
|
||||
void apply() {
|
||||
final enabled = state ?? false;
|
||||
settings.val(write: true).devToolsEnabled = enabled;
|
||||
if (!enabled) settings.val(write: true).devToolsSettings = DefaultSettings.get().devToolsSettings;
|
||||
}
|
||||
|
||||
if (!state!) {
|
||||
apply();
|
||||
return;
|
||||
}
|
||||
|
||||
ConfirmDialog(
|
||||
title: 'Entwicklermodus',
|
||||
content: 'Die Entwickleransicht bietet erweiterte Funktionen, die für den üblichen Gebrauch nicht benötigt werden.\n\n'
|
||||
'Die 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: apply,
|
||||
).asDialog(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../../model/account_data.dart';
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../widget/centered_leading.dart';
|
||||
import '../../../../widget/confirm_dialog.dart';
|
||||
import '../../../../widget/debug/cache_view.dart';
|
||||
|
||||
class AccountSection extends StatelessWidget {
|
||||
const AccountSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.logout_outlined)),
|
||||
title: const Text('Konto abmelden'),
|
||||
subtitle: Text('Angemeldet als ${AccountData().getUsername()}'),
|
||||
onTap: () => _showLogoutDialog(context),
|
||||
);
|
||||
|
||||
void _showLogoutDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ConfirmDialog(
|
||||
title: 'Abmelden?',
|
||||
content: 'Möchtest du dich wirklich abmelden?',
|
||||
confirmButton: 'Abmelden',
|
||||
onConfirm: () async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.clear();
|
||||
PaintingBinding.instance.imageCache.clear();
|
||||
if (!context.mounted) return;
|
||||
context.read<SettingsCubit>().reset();
|
||||
const CacheView().clear();
|
||||
AccountData().removeData(context: context);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../theming/app_theme.dart';
|
||||
|
||||
class AppearanceSection extends StatelessWidget {
|
||||
const AppearanceSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = context.read<SettingsCubit>();
|
||||
return 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!,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../routing/app_routes.dart';
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../widget/centered_leading.dart';
|
||||
import '../../../../widget/confirm_dialog.dart';
|
||||
import '../../../../widget/debug/cache_view.dart';
|
||||
import '../../../../widget/debug/json_viewer.dart';
|
||||
|
||||
class DevToolsSection extends StatefulWidget {
|
||||
final SettingsCubit settings;
|
||||
const DevToolsSection({required this.settings, super.key});
|
||||
|
||||
@override
|
||||
State<DevToolsSection> createState() => _DevToolsSectionState();
|
||||
}
|
||||
|
||||
class _DevToolsSectionState extends State<DevToolsSection> {
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.speed_outlined)),
|
||||
title: const Text('Performance overlays'),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () {
|
||||
showDialog(context: context, builder: (context) => SimpleDialog(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.auto_graph_outlined),
|
||||
title: const Text('Performance graph'),
|
||||
trailing: Checkbox(
|
||||
value: widget.settings.val().devToolsSettings.showPerformanceOverlay,
|
||||
onChanged: (e) => widget.settings.val(write: true).devToolsSettings.showPerformanceOverlay = e!,
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.screen_search_desktop_outlined),
|
||||
title: const Text('Indicate offscreen layers'),
|
||||
trailing: Checkbox(
|
||||
value: widget.settings.val().devToolsSettings.checkerboardOffscreenLayers,
|
||||
onChanged: (e) => widget.settings.val(write: true).devToolsSettings.checkerboardOffscreenLayers = e!,
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.imagesearch_roller_outlined),
|
||||
title: const Text('Indicate raster cache images'),
|
||||
trailing: Checkbox(
|
||||
value: widget.settings.val().devToolsSettings.checkerboardRasterCacheImages,
|
||||
onChanged: (e) => widget.settings.val(write: true).devToolsSettings.checkerboardRasterCacheImages = e!,
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.image_outlined)),
|
||||
title: const Text('Thumb-storage'),
|
||||
subtitle: Text('etwa ${filesize(PaintingBinding.instance.imageCache.currentSizeBytes)}\nLange tippen um zu löschen'),
|
||||
onLongPress: () {
|
||||
ConfirmDialog(
|
||||
title: 'Thumbs cache löschen',
|
||||
content: 'Alle zwischengespeicherten Bilder werden gelöscht.',
|
||||
confirmButton: 'Unwiederruflich löschen',
|
||||
onConfirm: () => PaintingBinding.instance.imageCache.clear(),
|
||||
).asDialog(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.settings_applications_outlined)),
|
||||
title: const Text('Settings-storage JSON dump'),
|
||||
subtitle: Text('etwa ${filesize(widget.settings.val().toJson().toString().length * 8)}\nLange tippen um zu löschen'),
|
||||
onTap: () {
|
||||
JsonViewer.asDialog(context, widget.settings.val().toJson());
|
||||
},
|
||||
onLongPress: () {
|
||||
ConfirmDialog(
|
||||
title: 'Einstellungen löschen',
|
||||
content: 'Alle Einstellungen gehen verloren! Accountdaten sowie App-Daten sind nicht betroffen.',
|
||||
confirmButton: 'Unwiederruflich Löschen',
|
||||
onConfirm: () {
|
||||
context.read<SettingsCubit>().reset();
|
||||
},
|
||||
).asDialog(context);
|
||||
},
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
),
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.data_object)),
|
||||
title: const Text('Cache-storage JSON dump'),
|
||||
subtitle: FutureBuilder(
|
||||
future: const CacheView().totalSize(),
|
||||
builder: (context, snapshot) => Text("etwa ${snapshot.hasError ? "?" : snapshot.hasData ? filesize(snapshot.data) : "..."}\nLange tippen um zu löschen"),
|
||||
),
|
||||
onTap: () => AppRoutes.openCacheView(context),
|
||||
onLongPress: () {
|
||||
ConfirmDialog(
|
||||
title: 'App-Cache löschen',
|
||||
content: 'Alle cache Einträge werden gelöscht. Der Cache wird bei Nutzung der App automatisch erneut aufgebaut',
|
||||
confirmButton: 'Unwiederruflich löschen',
|
||||
onConfirm: () => const CacheView().clear().then((value) => setState((){})),
|
||||
).asDialog(context);
|
||||
},
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
),
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.data_object)),
|
||||
title: const Text('BLOC-storage state cache'),
|
||||
subtitle: const Text('Lange tippen um zu löschen'),
|
||||
onTap: () {
|
||||
// Navigator.push(context, MaterialPageRoute(builder: (context) => const CacheView()));
|
||||
},
|
||||
onLongPress: () {
|
||||
ConfirmDialog(
|
||||
title: 'BLOC-Cache löschen',
|
||||
content: 'Alle cache Einträge werden gelöscht. Der Cache wird bei Nutzung der App automatisch erneut aufgebaut',
|
||||
confirmButton: 'Unwiederruflich löschen',
|
||||
onConfirm: () => HydratedBloc.storage.clear(),
|
||||
).asDialog(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
|
||||
class FilesSection extends StatelessWidget {
|
||||
const FilesSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = context.read<SettingsCubit>();
|
||||
return Column(
|
||||
children: [
|
||||
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!,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../notification/notify_updater.dart';
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../widget/centered_leading.dart';
|
||||
|
||||
class TalkSection extends StatelessWidget {
|
||||
const TalkSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = context.read<SettingsCubit>();
|
||||
final talkSettings = settings.val().talkSettings;
|
||||
final notificationSettings = settings.val().notificationSettings;
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.star_border),
|
||||
title: const Text('Favoriten im Talk nach oben sortieren'),
|
||||
trailing: Checkbox(
|
||||
value: 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: 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: notificationSettings.enabled,
|
||||
onChanged: (e) {
|
||||
if (e!) {
|
||||
NotifyUpdater.enableAfterDisclaimer(settings).asDialog(context);
|
||||
} else {
|
||||
settings.val(write: true).notificationSettings.enabled = e;
|
||||
}
|
||||
},
|
||||
),
|
||||
onLongPress: () => _showInfoDialog(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _showInfoDialog(BuildContext context) => 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')),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../state/app/modules/timetable/bloc/timetable_bloc.dart';
|
||||
import '../../../../storage/timetable/timetable_name_mode.dart';
|
||||
|
||||
class TimetableSection extends StatelessWidget {
|
||||
const TimetableSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = context.read<SettingsCubit>();
|
||||
final timetableBloc = context.read<TimetableBloc>();
|
||||
final timetableSettings = settings.val().timetableSettings;
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.abc_outlined),
|
||||
title: const Text('Fachbezeichnung'),
|
||||
trailing: DropdownButton<TimetableNameMode>(
|
||||
value: timetableSettings.timetableNameMode,
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
items: TimetableNameMode.values
|
||||
.map((e) => DropdownMenuItem(
|
||||
value: e,
|
||||
enabled: e != 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!;
|
||||
timetableBloc.refresh();
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.calendar_view_day_outlined),
|
||||
title: const Text('Doppelstunden zusammenhängend anzeigen'),
|
||||
trailing: Checkbox(
|
||||
value: timetableSettings.connectDoubleLessons,
|
||||
onChanged: (e) {
|
||||
settings.val(write: true).timetableSettings.connectDoubleLessons = e!;
|
||||
timetableBloc.refresh();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../storage/base/settings.dart' as model;
|
||||
import 'sections/about_section.dart';
|
||||
import 'sections/account_section.dart';
|
||||
import 'sections/appearance_section.dart';
|
||||
import 'sections/files_section.dart';
|
||||
import 'sections/talk_section.dart';
|
||||
import 'sections/timetable_section.dart';
|
||||
|
||||
class Settings extends StatelessWidget {
|
||||
const Settings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocBuilder<SettingsCubit, model.Settings>(
|
||||
builder: (context, _) => Scaffold(
|
||||
appBar: AppBar(title: const Text('Einstellungen')),
|
||||
body: ListView(
|
||||
children: const [
|
||||
AccountSection(),
|
||||
Divider(),
|
||||
AppearanceSection(),
|
||||
Divider(),
|
||||
TimetableSection(),
|
||||
Divider(),
|
||||
TalkSection(),
|
||||
Divider(),
|
||||
FilesSection(),
|
||||
Divider(),
|
||||
AboutSection(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../widget/centered_leading.dart';
|
||||
import '../../../../widget/confirm_dialog.dart';
|
||||
|
||||
class PrivacyInfo {
|
||||
String providerText;
|
||||
String privacyUrl;
|
||||
String imprintUrl;
|
||||
|
||||
PrivacyInfo({required this.providerText, required this.imprintUrl, required this.privacyUrl});
|
||||
|
||||
void showPopup(BuildContext context) {
|
||||
showDialog(context: context, builder: (context) => SimpleDialog(
|
||||
title: Text('Betreiberinformation | $providerText'),
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.person_pin_outlined)),
|
||||
title: const Text('Impressum'),
|
||||
subtitle: Text(imprintUrl),
|
||||
onTap: () => ConfirmDialog.openBrowser(context, imprintUrl),
|
||||
),
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.privacy_tip_outlined)),
|
||||
title: const Text('Datenschutzerklärung'),
|
||||
subtitle: Text(privacyUrl),
|
||||
onTap: () => ConfirmDialog.openBrowser(context, privacyUrl),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user