Skip to content

Commit

Permalink
wip binding for flutter_local_notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
gnprice committed Oct 14, 2023
1 parent 536d833 commit 685cc29
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 3 deletions.
7 changes: 7 additions & 0 deletions lib/model/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:device_info_plus/device_info_plus.dart' as device_info_plus;
import 'package:firebase_core/firebase_core.dart' as firebase_core;
import 'package:firebase_messaging/firebase_messaging.dart' as firebase_messaging;
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:url_launcher/url_launcher.dart' as url_launcher;

import '../firebase_options.dart';
Expand Down Expand Up @@ -98,6 +99,9 @@ abstract class ZulipBinding {

/// Wraps [firebase_messaging.FirebaseMessaging.onMessage].
Stream<firebase_messaging.RemoteMessage> get firebaseMessagingOnMessage;

/// Wraps the [FlutterLocalNotificationsPlugin] singleton constructor.
FlutterLocalNotificationsPlugin get notif;
}

/// Like [device_info_plus.BaseDeviceInfo], but without things we don't use.
Expand Down Expand Up @@ -180,4 +184,7 @@ class LiveZulipBinding extends ZulipBinding {
Stream<firebase_messaging.RemoteMessage> get firebaseMessagingOnMessage {
return firebase_messaging.FirebaseMessaging.onMessage;
}

@override
FlutterLocalNotificationsPlugin get notif => FlutterLocalNotificationsPlugin();
}
6 changes: 3 additions & 3 deletions lib/notif.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class NotificationService {
// (in order to avoid calling for permissions)

ZulipBinding.instance.firebaseMessagingOnMessage.listen(_onRemoteMessage);
FlutterLocalNotificationsPlugin().initialize(
ZulipBinding.instance.notif.initialize(
const InitializationSettings(
android: AndroidInitializationSettings('zulip_notification'),
),
Expand Down Expand Up @@ -126,7 +126,7 @@ class NotificationChannelManager {
static final _kVibrationPattern = Int64List.fromList([0, 125, 100, 450]);

static void _ensureChannel() async { // TODO "ensure"
final plugin = FlutterLocalNotificationsPlugin();
final plugin = ZulipBinding.instance.notif;
await plugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(AndroidNotificationChannel(
_kChannelId,
Expand Down Expand Up @@ -157,7 +157,7 @@ class NotificationDisplayManager {
FcmMessageDmRecipient() =>
data.senderFullName,
};
FlutterLocalNotificationsPlugin().show(
ZulipBinding.instance.notif.show(
_kNotificationId,
title,
data.content, // TODO
Expand Down
105 changes: 105 additions & 0 deletions test/model/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import 'dart:async';

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart';
import 'package:test/fake.dart';
import 'package:url_launcher/url_launcher.dart' as url_launcher;
import 'package:zulip/model/binding.dart';
Expand Down Expand Up @@ -63,6 +65,7 @@ class TestZulipBinding extends ZulipBinding {
_resetLaunchUrl();
_resetDeviceInfo();
_resetFirebase();
_resetNotif();
}

/// The current global store offered to a [GlobalStoreWidget].
Expand Down Expand Up @@ -188,6 +191,17 @@ class TestZulipBinding extends ZulipBinding {

@override
Stream<RemoteMessage> get firebaseMessagingOnMessage => firebaseMessaging.onMessage.stream;

void _resetNotif() {
_notifPlugin = null;
}

FakeFlutterLocalNotificationsPlugin? _notifPlugin;

@override
FakeFlutterLocalNotificationsPlugin get notif {
return (_notifPlugin ??= FakeFlutterLocalNotificationsPlugin());
}
}

class FakeFirebaseMessaging extends Fake implements FirebaseMessaging {
Expand Down Expand Up @@ -228,3 +242,94 @@ class FakeFirebaseMessaging extends Fake implements FirebaseMessaging {

StreamController<RemoteMessage> onMessage = StreamController.broadcast();
}

class FakeFlutterLocalNotificationsPlugin extends Fake implements FlutterLocalNotificationsPlugin {
InitializationSettings? initializationSettings;
DidReceiveNotificationResponseCallback? onDidReceiveNotificationResponse;
DidReceiveBackgroundNotificationResponseCallback? onDidReceiveBackgroundNotificationResponse;

@override
Future<bool?> initialize(
InitializationSettings initializationSettings, {
DidReceiveNotificationResponseCallback? onDidReceiveNotificationResponse,
DidReceiveBackgroundNotificationResponseCallback? onDidReceiveBackgroundNotificationResponse,
}) async {
assert(this.initializationSettings == null);
this.initializationSettings = initializationSettings;
this.onDidReceiveNotificationResponse = onDidReceiveNotificationResponse;
this.onDidReceiveBackgroundNotificationResponse = onDidReceiveBackgroundNotificationResponse;
return true;
}

FlutterLocalNotificationsPlatform? _platform;

@override
T? resolvePlatformSpecificImplementation<T extends FlutterLocalNotificationsPlatform>() {
// This follows the logic of the base class's implementation,
// but supplies our fakes for the per-platform classes.
assert(initializationSettings != null);
assert(T != FlutterLocalNotificationsPlatform);
if (kIsWeb) return null;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
assert(_platform == null || _platform is FakeAndroidFlutterLocalNotificationsPlugin);
if (T != AndroidFlutterLocalNotificationsPlugin) return null;
return (_platform ??= FakeAndroidFlutterLocalNotificationsPlugin()) as T?;

case TargetPlatform.iOS:
assert(_platform == null || _platform is FakeIOSFlutterLocalNotificationsPlugin);
if (T != IOSFlutterLocalNotificationsPlugin) return null;
return (_platform ??= FakeIOSFlutterLocalNotificationsPlugin()) as T?;

case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
case TargetPlatform.fuchsia:
return null;
}
}

/// Consume the log of calls made to [show].
///
/// This returns a list of the arguments to all calls made
/// to [show] since the last call to this method.
List<FlutterLocalNotificationsPluginShowCall> takeShowCalls() {
final result = _showCalls;
_showCalls = [];
return result;
}
List<FlutterLocalNotificationsPluginShowCall> _showCalls = [];

@override
Future<void> show(int id, String? title, String? body,
NotificationDetails? notificationDetails, {String? payload}) async {
assert(initializationSettings != null);
_showCalls.add((id, title, body, notificationDetails, payload: payload));
}
}

typedef FlutterLocalNotificationsPluginShowCall = (
int id, String? title, String? body,
NotificationDetails? notificationDetails, {String? payload}
);

class FakeAndroidFlutterLocalNotificationsPlugin extends Fake implements AndroidFlutterLocalNotificationsPlugin {
/// Consume the log of calls made to [createNotificationChannel].
///
/// This returns a list of the arguments to all calls made
/// to [createNotificationChannel] since the last call to this method.
List<AndroidNotificationChannel> takeCreatedChannels() {
final result = _createdChannels;
_createdChannels = [];
return result;
}
List<AndroidNotificationChannel> _createdChannels = [];

@override
Future<void> createNotificationChannel(AndroidNotificationChannel notificationChannel) async {
_createdChannels.add(notificationChannel);
}
}

class FakeIOSFlutterLocalNotificationsPlugin extends Fake implements IOSFlutterLocalNotificationsPlugin {
}

0 comments on commit 685cc29

Please sign in to comment.