189 lines
6.5 KiB
Dart
189 lines
6.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../../../../api/errors/error_mapper.dart';
|
|
import '../../../../api/marianumconnect/queries/push_device_test/push_device_test.dart';
|
|
import '../../../../push/push_registration.dart';
|
|
import '../../../../push/push_registration_store.dart';
|
|
import '../../../../routing/app_routes.dart';
|
|
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
|
import '../../../../utils/haptics.dart';
|
|
import '../../../../widget/centered_leading.dart';
|
|
|
|
class TalkSection extends StatelessWidget {
|
|
const TalkSection({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final settings = context.watch<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) {
|
|
Haptics.selection();
|
|
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) {
|
|
Haptics.selection();
|
|
settings.val(write: true).talkSettings.sortUnreadToTop = e!;
|
|
},
|
|
),
|
|
),
|
|
ListTile(
|
|
leading: const Icon(Icons.wallpaper_outlined),
|
|
title: const Text('Chat-Hintergrund'),
|
|
subtitle: const Text('Bild, Farbe und Darstellung anpassen'),
|
|
trailing: const Icon(Icons.arrow_right),
|
|
onTap: () => AppRoutes.openChatBackgroundSettings(context),
|
|
),
|
|
ListTile(
|
|
leading: const CenteredLeading(
|
|
Icon(Icons.notifications_active_outlined),
|
|
),
|
|
title: const Text('Push-Benachrichtigungen'),
|
|
subtitle: const Text('Neue Talk-Nachrichten direkt aufs Gerät'),
|
|
trailing: Checkbox(
|
|
value: notificationSettings.enabled,
|
|
onChanged: (e) {
|
|
Haptics.selection();
|
|
final enabled = e ?? false;
|
|
settings.val(write: true).notificationSettings.enabled = enabled;
|
|
if (enabled) {
|
|
final messenger = ScaffoldMessenger.of(context);
|
|
unawaited(() async {
|
|
// Only register when the OS permission isn't explicitly
|
|
// denied — otherwise NC + proxy would push into the void.
|
|
if (await PushRegistration.requestOsPermission()) {
|
|
await PushRegistration().register();
|
|
} else {
|
|
messenger.showSnackBar(
|
|
const SnackBar(
|
|
content: Text(
|
|
'Benachrichtigungen sind in den Systemeinstellungen '
|
|
'deaktiviert — bitte dort erlauben.',
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}());
|
|
} else {
|
|
unawaited(PushRegistration().unregister());
|
|
}
|
|
},
|
|
),
|
|
),
|
|
if (notificationSettings.enabled) const _TestNotificationTile(),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// "Send a test notification" action, shown only while push is enabled. The
|
|
/// button stays disabled until a registration is confirmed present, then calls
|
|
/// the backend and reports the result via a SnackBar.
|
|
class _TestNotificationTile extends StatefulWidget {
|
|
const _TestNotificationTile();
|
|
|
|
@override
|
|
State<_TestNotificationTile> createState() => _TestNotificationTileState();
|
|
}
|
|
|
|
class _TestNotificationTileState extends State<_TestNotificationTile> {
|
|
static const _permissionDeniedHint =
|
|
'Benachrichtigungen sind in den Systemeinstellungen deaktiviert';
|
|
|
|
bool _registered = false;
|
|
bool _permissionDenied = false;
|
|
bool _sending = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadState();
|
|
}
|
|
|
|
Future<void> _loadState() async {
|
|
final registered = await const PushRegistrationStore().isRegistered();
|
|
final denied = await PushRegistration.isOsPermissionDenied();
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_registered = registered;
|
|
_permissionDenied = denied;
|
|
});
|
|
}
|
|
|
|
Future<void> _sendTest() async {
|
|
if (_sending) return;
|
|
Haptics.selection();
|
|
final messenger = ScaffoldMessenger.of(context);
|
|
// Re-check right before sending: the user may have flipped the OS
|
|
// permission in the system settings since this tile was built.
|
|
final denied = await PushRegistration.isOsPermissionDenied();
|
|
if (!mounted) return;
|
|
if (denied) {
|
|
setState(() => _permissionDenied = true);
|
|
messenger.showSnackBar(
|
|
const SnackBar(
|
|
content: Text('$_permissionDeniedHint — bitte dort erlauben.'),
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
setState(() {
|
|
_permissionDenied = false;
|
|
_sending = true;
|
|
});
|
|
String message;
|
|
try {
|
|
final devices = await PushDeviceTest().run();
|
|
message = devices >= 1
|
|
? 'Testbenachrichtigung an $devices Gerät(e) gesendet'
|
|
: 'Kein Gerät registriert — Push-Registrierung prüfen';
|
|
} on Object catch (e) {
|
|
message = errorToUserMessage(e);
|
|
}
|
|
if (!mounted) return;
|
|
setState(() => _sending = false);
|
|
messenger.showSnackBar(SnackBar(content: Text(message)));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (!_registered) return const SizedBox.shrink();
|
|
return ListTile(
|
|
leading: const CenteredLeading(Icon(Icons.send_outlined)),
|
|
title: const Text('Testbenachrichtigung senden'),
|
|
subtitle: _permissionDenied
|
|
? Text(
|
|
_permissionDeniedHint,
|
|
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
|
)
|
|
: const Text('Prüft, ob Push auf diesem Gerät ankommt'),
|
|
trailing: _sending
|
|
? const SizedBox(
|
|
width: 20,
|
|
height: 20,
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
)
|
|
: const Icon(Icons.arrow_right),
|
|
enabled: !_sending,
|
|
onTap: _sending ? null : _sendTest,
|
|
);
|
|
}
|
|
}
|