implemented a backend-independent emergency notice system
This commit is contained in:
@@ -75,6 +75,7 @@ class DefaultSettings {
|
||||
showPerformanceOverlay: false,
|
||||
marianumConnectEndpoint: MarianumConnectEndpoint.live,
|
||||
marianumConnectCustomUrl: '',
|
||||
emergencyNoticeUrl: '',
|
||||
),
|
||||
hapticSettings: HapticSettings(level: HapticLevel.full),
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
|
||||
import '../../../../routing/app_routes.dart';
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../../storage/dev_tools_settings.dart';
|
||||
import '../../../../storage/settings.dart' as model;
|
||||
import '../../../../widget/centered_leading.dart';
|
||||
import '../../../../widget/confirm_dialog.dart';
|
||||
@@ -88,6 +89,27 @@ class _DevToolsSectionState extends State<DevToolsSection> {
|
||||
onTap: () =>
|
||||
MarianumConnectEndpointPicker.show(context, widget.settings),
|
||||
),
|
||||
BlocBuilder<SettingsCubit, model.Settings>(
|
||||
bloc: widget.settings,
|
||||
builder: (_, _) {
|
||||
final override = widget.settings
|
||||
.val()
|
||||
.devToolsSettings
|
||||
.emergencyNoticeUrl
|
||||
.trim();
|
||||
return ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.emergency_outlined)),
|
||||
title: const Text('Notfall-Nachricht (Quelle)'),
|
||||
subtitle: Text(
|
||||
override.isEmpty
|
||||
? 'Standardquelle (im Code hinterlegt)'
|
||||
: override,
|
||||
),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () => _EmergencyNoticeUrlEditor.show(context, widget.settings),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const CenteredLeading(Icon(Icons.image_outlined)),
|
||||
title: const Text('Thumb-storage'),
|
||||
@@ -170,3 +192,94 @@ class _DevToolsSectionState extends State<DevToolsSection> {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Bottom-sheet editor for the backend-independent emergency-notice override
|
||||
/// URL. Empty clears the override so the compiled-in default source is used.
|
||||
class _EmergencyNoticeUrlEditor extends StatefulWidget {
|
||||
final SettingsCubit settings;
|
||||
const _EmergencyNoticeUrlEditor({required this.settings});
|
||||
|
||||
static void show(BuildContext context, SettingsCubit settings) {
|
||||
showDetailsBottomSheet(
|
||||
context,
|
||||
header: const ListTile(title: Text('Notfall-Nachricht (Quelle)')),
|
||||
children: (sheetCtx) => [_EmergencyNoticeUrlEditor(settings: settings)],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
State<_EmergencyNoticeUrlEditor> createState() =>
|
||||
_EmergencyNoticeUrlEditorState();
|
||||
}
|
||||
|
||||
class _EmergencyNoticeUrlEditorState extends State<_EmergencyNoticeUrlEditor> {
|
||||
late final TextEditingController _controller;
|
||||
String? _error;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController(
|
||||
text: widget.settings.val().devToolsSettings.emergencyNoticeUrl,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _save() {
|
||||
final raw = _controller.text.trim();
|
||||
// Empty is valid: it clears the override and falls back to the default.
|
||||
if (raw.isNotEmpty &&
|
||||
DevToolsSettings.sanitizeCustomUrl(raw) == null) {
|
||||
setState(
|
||||
() => _error = DevToolsSettings.allowsHttpCustomEndpoint
|
||||
? 'Ungültige URL (http(s)://host[:port]/...)'
|
||||
: 'Ungültige URL — nur HTTPS erlaubt',
|
||||
);
|
||||
return;
|
||||
}
|
||||
widget.settings.val(write: true).devToolsSettings.emergencyNoticeUrl = raw;
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: Text(
|
||||
'Überschreibt die im Code hinterlegte Standardquelle. Leer '
|
||||
'lassen, um die Standardquelle zu verwenden.',
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
controller: _controller,
|
||||
keyboardType: TextInputType.url,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'https://...',
|
||||
errorText: _error,
|
||||
),
|
||||
onChanged: (_) {
|
||||
if (_error != null) setState(() => _error = null);
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: FilledButton(
|
||||
onPressed: _save,
|
||||
child: const Text('Übernehmen'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user