~emersion/goguma

ffd9c10b7852430678d2850c0462ba2660e9faba — Simon Ser 8 days ago e92ac5f android-13-notif-permission
wip: Add support for Android 13 notification permission
3 files changed, 81 insertions(+), 3 deletions(-)

M android/app/build.gradle
M lib/notification_controller.dart
M lib/page/buffer_list.dart
M android/app/build.gradle => android/app/build.gradle +9 -2
@@ 32,9 32,11 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    // TODO: revert to flutter.compileSdkVersion
    compileSdkVersion 33

    compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }


@@ 51,10 53,12 @@ android {
        applicationId "fr.emersion.goguma"
        // TODO: make firebase_messaging optional and revert to `flutter.minSdkVersion`
        minSdkVersion 19
        targetSdkVersion flutter.targetSdkVersion
        // TODO: revert to flutter.targetSdkVersion
        targetSdkVersion 33
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        applicationIdSuffix project.findProperty('applicationIdSuffix')
        multiDexEnabled true
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
        }


@@ 87,4 91,7 @@ flutter {

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.window:window:1.0.0'
    implementation 'androidx.window:window-java:1.0.0'
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}

M lib/notification_controller.dart => lib/notification_controller.dart +16 -0
@@ 31,10 31,12 @@ class NotificationController {
	final FlutterLocalNotificationsPlugin _plugin = FlutterLocalNotificationsPlugin();
	final StreamController<String?> _selectionsController = StreamController(sync: true);
	List<_ActiveNotification> _active = [];
	bool _needsPermission = false;

	static NotificationController? _instance;

	Stream<String?> get selections => _selectionsController.stream;
	bool get needsPermission => _needsPermission;

	NotificationController._();



@@ 52,6 54,12 @@ class NotificationController {
			} on Exception catch (err) {
				print('Failed to list active notifications: $err');
			}

			try {
				_needsPermission = await androidPlugin.areNotificationsEnabled() == null;
			} on Exception catch (err) {
				print('Failed to check whether notification permission is required: $err');
			}
		}
	}



@@ 301,4 309,12 @@ class NotificationController {
			),
		), payload: tag);
	}

	Future<void> requestPermission() async {
		var androidPlugin = _plugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
		if (androidPlugin == null) {
			return;
		}
		_needsPermission = await androidPlugin.requestPermission() == null;
	}
}

M lib/page/buffer_list.dart => lib/page/buffer_list.dart +56 -1
@@ 5,6 5,7 @@ import '../ansi.dart';
import '../client_controller.dart';
import '../database.dart';
import '../models.dart';
import '../notification_controller.dart';
import '../page/join.dart';
import '../page/edit_bouncer_network.dart';
import '../page/settings.dart';


@@ 211,7 212,9 @@ class _BufferListPageState extends State<BufferListPage> {
				],
			),
			body: NetworkListIndicator(
				child: _BackgroundServicePermissionBanner(child: body)
				child: _BackgroundServicePermissionBanner(
					child: _NotificationPermissionBanner(child: body),
				)
			),
		);
	}


@@ 260,6 263,58 @@ class _BackgroundServicePermissionBanner extends StatelessWidget {
	}
}

class _NotificationPermissionBanner extends StatefulWidget {
	final Widget child;

	const _NotificationPermissionBanner({
		Key? key,
		required this.child,
	}) : super(key: key);

	@override
	State<_NotificationPermissionBanner> createState() => _NotificationPermissionBannerState();
}

class _NotificationPermissionBannerState extends State<_NotificationPermissionBanner> {
	bool _needsPermission = false;

	@override
	void initState() {
		super.initState();
		_update();
	}

	void _update() {
		var notificationController = context.read<NotificationController>();
		setState(() {
			_needsPermission = notificationController.needsPermission;
		});
	}

	@override
	Widget build(BuildContext context) {
		var notificationController = context.read<NotificationController>();
		if (!_needsPermission) {
			return widget.child!;
		}
		return Column(children: [
			MaterialBanner(
				content: Text('Allow Goguma to display notifications to avoid missing important messages.'),
				actions: [
					TextButton(
						child: Text('CONTINUE'),
						onPressed: () async {
							await notificationController.requestPermission();
							_update();
						},
					),
				],
			),
			Expanded(child: widget.child!),
		]);
	}
}

class _BufferItem extends AnimatedWidget {
	final BufferModel buffer;
	final bool showNetworkName;