feat: add admin page

This commit is contained in:
2026-08-07 03:09:59 +02:00
parent 2c734493cf
commit 1dd7e69aa8
19 changed files with 891 additions and 65 deletions
+67 -2
View File
@@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import '../models/settings.dart';
import '../viewmodels/admin_pin_view_model.dart';
import '../utils/app_update_util.dart';
import '../utils/navigation.dart';
import '../viewmodels/pin_lock_view_model.dart';
@@ -33,6 +34,7 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<SettingsViewModel>().ensureLoaded();
context.read<PinLockViewModel>().ensureLoaded();
context.read<AdminPinViewModel>().ensureLoaded();
_loadVersion();
});
}
@@ -190,11 +192,62 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
}
}
Future<void> _configureAdminPin() async {
final l10n = AppLocalizations.of(context);
final adminPinViewModel = context.read<AdminPinViewModel>();
if (!adminPinViewModel.isPinSet) {
final pin = await _promptPin(l10n.setAdminPin, hint: l10n.fourDigits);
if (pin == null) return;
if (pin.length != 4) {
_showError(l10n.pinExactlyFour);
return;
}
final success = await adminPinViewModel.setPin(pin);
if (!success) {
_showError(l10n.localizedError(adminPinViewModel.errorMessage));
return;
}
adminPinViewModel.lock();
return;
}
final current = await _promptPin(l10n.enterCurrentAdminPin);
if (current == null) return;
final newPin = await _promptPin(
l10n.enterNewAdminPin,
hint: l10n.fourDigits,
);
if (newPin == null) return;
if (newPin.length != 4) {
_showError(l10n.pinExactlyFour);
return;
}
final success = await adminPinViewModel.changePin(
currentPin: current,
newPin: newPin,
);
if (!success) {
_showError(l10n.localizedError(adminPinViewModel.errorMessage));
return;
}
adminPinViewModel.lock();
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final settingsViewModel = context.watch<SettingsViewModel>();
final pinLockViewModel = context.watch<PinLockViewModel>();
final adminPinViewModel = context.watch<AdminPinViewModel>();
return Scaffold(
appBar: AppBar(
@@ -207,9 +260,13 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
body: Builder(
builder: (context) {
final isLoading =
settingsViewModel.isLoading || pinLockViewModel.isLoading;
settingsViewModel.isLoading ||
pinLockViewModel.isLoading ||
adminPinViewModel.isLoading;
final hasLoaded =
settingsViewModel.hasLoaded && pinLockViewModel.hasLoaded;
settingsViewModel.hasLoaded &&
pinLockViewModel.hasLoaded &&
adminPinViewModel.hasLoaded;
if (isLoading && !hasLoaded) {
return const Center(
@@ -251,6 +308,14 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
title: l10n.changePin,
onTap: _changePin,
),
_SettingsTile(
icon: Icons.admin_panel_settings_outlined,
title: l10n.adminPin,
subtitle: adminPinViewModel.isPinSet
? l10n.adminPinConfigured
: l10n.adminPinNotSet,
onTap: _configureAdminPin,
),
],
),
_SettingsSection(