implemented a guided notification permission flow triggered on the first Talk visit

This commit is contained in:
2026-07-06 20:01:45 +02:00
parent 3be0113f93
commit 38a271929c
11 changed files with 211 additions and 30 deletions
@@ -1,3 +1,6 @@
import 'dart:async';
import 'package:app_settings/app_settings.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -42,16 +45,41 @@ class _PushStatusBody extends StatefulWidget {
State<_PushStatusBody> createState() => _PushStatusBodyState();
}
class _PushStatusBodyState extends State<_PushStatusBody> {
class _PushStatusBodyState extends State<_PushStatusBody>
with WidgetsBindingObserver {
PushStatusReport? _report;
bool _busy = false;
/// Set while the user is in the OS settings — the next `resumed` lifecycle
/// event then re-collects the status so a just-changed permission shows up.
bool _reloadOnResume = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_load();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed && _reloadOnResume) {
_reloadOnResume = false;
unawaited(_load());
}
}
Future<void> _openNotificationSettings() async {
_reloadOnResume = true;
await AppSettings.openAppSettings(type: AppSettingsType.notification);
}
Future<void> _load() async {
final capabilitiesState = widget.capabilities.state;
final report = await collectPushStatus(
@@ -117,14 +145,24 @@ class _PushStatusBodyState extends State<_PushStatusBody> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
...rows.map(
(row) => ListTile(
...rows.map((row) {
// Offer the OS-settings shortcut on the permission row whenever it
// isn't granted — after a denial that's the only place to fix it.
final canOpenSettings =
row.opensNotificationSettings && row.state != PushCheck.ok;
return ListTile(
dense: true,
leading: _stateIcon(row.state, theme),
title: Text(row.label),
subtitle: row.detail == null ? null : Text(row.detail!),
),
),
trailing: canOpenSettings
? TextButton(
onPressed: _openNotificationSettings,
child: const Text('Einstellungen'),
)
: null,
);
}),
if (report.general.lastRegistrationAt != null ||
report.talk.lastRegistrationAt != null)
const Divider(height: 1),