add wip deregistering
This commit is contained in:
parent
0122feae1d
commit
129f0794f2
7 changed files with 113 additions and 40 deletions
|
|
@ -22,6 +22,7 @@ import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/oauth_auth_code_response.dart";
|
import "package:nexus/models/oauth_auth_code_response.dart";
|
||||||
import "package:nexus/models/open_graph_data.dart";
|
import "package:nexus/models/open_graph_data.dart";
|
||||||
import "package:nexus/models/paginate.dart";
|
import "package:nexus/models/paginate.dart";
|
||||||
|
import "package:nexus/models/requests/deregister_pusher.dart";
|
||||||
import "package:nexus/models/requests/download_media.dart";
|
import "package:nexus/models/requests/download_media.dart";
|
||||||
import "package:nexus/models/requests/get_event.dart";
|
import "package:nexus/models/requests/get_event.dart";
|
||||||
import "package:nexus/models/requests/get_related_events.dart";
|
import "package:nexus/models/requests/get_related_events.dart";
|
||||||
|
|
@ -178,13 +179,15 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Event> handlePush(Map<String, dynamic> data) async => .fromJson(
|
Future<Event?> handlePush(Map<String, dynamic> data) async {
|
||||||
await callGomuksMethod(
|
final response = await callGomuksMethod(
|
||||||
data,
|
data,
|
||||||
(handle, data) async => GomuksHandlePush(handle, data),
|
(handle, data) async => GomuksHandlePush(handle, data),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return response == null ? null : .fromJson(response);
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> _sendCommand(
|
Future<dynamic> _sendCommand(
|
||||||
String command, [
|
String command, [
|
||||||
Map<String, dynamic> data = const {},
|
Map<String, dynamic> data = const {},
|
||||||
|
|
@ -293,6 +296,12 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
Future<void> registerPusher(RegisterPusherRequest request) =>
|
Future<void> registerPusher(RegisterPusherRequest request) =>
|
||||||
_sendCommand("register_homeserver_push", request.toJson());
|
_sendCommand("register_homeserver_push", request.toJson());
|
||||||
|
|
||||||
|
Future<void> deregisterPusher(DeregisterPusherRequest request) =>
|
||||||
|
_sendCommand("register_homeserver_push", {
|
||||||
|
...request.toJson(),
|
||||||
|
"kind": null,
|
||||||
|
});
|
||||||
|
|
||||||
Future<MessageContent> uploadMedia(UploadMediaRequest request) async =>
|
Future<MessageContent> uploadMedia(UploadMediaRequest request) async =>
|
||||||
.fromJson(await _sendCommand("upload_media", request.toJson()));
|
.fromJson(await _sendCommand("upload_media", request.toJson()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import "dart:convert";
|
|
||||||
import "dart:io";
|
import "dart:io";
|
||||||
|
|
||||||
|
import "package:material_ui/material_ui.dart";
|
||||||
|
import "package:nexus/main.dart";
|
||||||
import "package:flutter_local_notifications/flutter_local_notifications.dart";
|
import "package:flutter_local_notifications/flutter_local_notifications.dart";
|
||||||
// ignore: implementation_imports
|
// ignore: implementation_imports
|
||||||
import "package:flutter_local_notifications_linux/src/model/hint.dart";
|
import "package:flutter_local_notifications_linux/src/model/hint.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/event.dart";
|
import "package:nexus/pages/notifications.dart";
|
||||||
|
|
||||||
class NotificationsController
|
class NotificationsController
|
||||||
extends AsyncNotifier<FlutterLocalNotificationsPlugin> {
|
extends AsyncNotifier<FlutterLocalNotificationsPlugin> {
|
||||||
|
|
@ -22,17 +23,21 @@ class NotificationsController
|
||||||
appUserModelId: "nexus.federated.nexus",
|
appUserModelId: "nexus.federated.nexus",
|
||||||
guid: "dde78daf-130f-4e46-a80a-e31deeab45d7",
|
guid: "dde78daf-130f-4e46-a80a-e31deeab45d7",
|
||||||
),
|
),
|
||||||
android: .new("ic_launcher"),
|
android: .new("ic_launcher_foreground"),
|
||||||
iOS: darwin,
|
iOS: darwin,
|
||||||
macOS: darwin,
|
macOS: darwin,
|
||||||
linux: .new(defaultActionName: "Open"),
|
linux: .new(defaultActionName: "Open"),
|
||||||
),
|
),
|
||||||
onDidReceiveNotificationResponse: (details) {
|
onDidReceiveNotificationResponse: (details) {
|
||||||
if (details.payload case final payload?) {
|
if (details.payload case final eventId?) {
|
||||||
final event = ref.watch(
|
if (navigatorKey.currentContext case final context?) {
|
||||||
EventController.provider(.fromJson(json.decode(payload))),
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => NotificationsPage(eventId: eventId),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import "dart:io";
|
import "dart:io";
|
||||||
|
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
|
||||||
import "package:intl/intl.dart";
|
import "package:intl/intl.dart";
|
||||||
import "package:m3e_buttons/m3e_buttons.dart";
|
import "package:m3e_buttons/m3e_buttons.dart";
|
||||||
import "package:nexus/controllers/account_data.dart";
|
import "package:nexus/controllers/account_data.dart";
|
||||||
|
|
@ -105,14 +106,16 @@ class SettingsSectionsController
|
||||||
.new(
|
.new(
|
||||||
title: "Push notifications",
|
title: "Push notifications",
|
||||||
description: "Enable push notifications using Web Push",
|
description: "Enable push notifications using Web Push",
|
||||||
builder: (title, description, icon) => Consumer(
|
builder: (title, description, icon) => HookConsumer(
|
||||||
builder: (context, ref, _) {
|
builder: (context, ref, _) {
|
||||||
|
final loading = useState(false);
|
||||||
final pusherRegistered = ref.watch(
|
final pusherRegistered = ref.watch(
|
||||||
UnifiedPushController.provider,
|
UnifiedPushController.provider,
|
||||||
);
|
);
|
||||||
final unifiedPushAllowed = ref.watch(
|
final unifiedPushAllowed = ref.watch(
|
||||||
UnifiedPushAllowedController.provider,
|
UnifiedPushAllowedController.provider,
|
||||||
);
|
);
|
||||||
|
|
||||||
return SwitchListTile(
|
return SwitchListTile(
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
|
|
@ -127,13 +130,16 @@ class SettingsSectionsController
|
||||||
data: (value) => value,
|
data: (value) => value,
|
||||||
orElse: () => false,
|
orElse: () => false,
|
||||||
),
|
),
|
||||||
onChanged:
|
onChanged: loading.value
|
||||||
unifiedPushAllowed.maybeWhen(
|
? null
|
||||||
|
: unifiedPushAllowed.maybeWhen(
|
||||||
data: (data) => data == null,
|
data: (data) => data == null,
|
||||||
orElse: () => false,
|
orElse: () => false,
|
||||||
)
|
)
|
||||||
? pusherRegistered.maybeWhen(
|
? pusherRegistered.maybeWhen(
|
||||||
data: (_) => (value) async {
|
data: (_) => (value) async {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
if (value) {
|
if (value) {
|
||||||
if (await ref
|
if (await ref
|
||||||
.watch(
|
.watch(
|
||||||
|
|
@ -142,19 +148,29 @@ class SettingsSectionsController
|
||||||
.notifier,
|
.notifier,
|
||||||
)
|
)
|
||||||
.requestPermissions()) {
|
.requestPermissions()) {
|
||||||
ref
|
await ref
|
||||||
.watch(
|
.watch(
|
||||||
UnifiedPushController
|
UnifiedPushController
|
||||||
.provider
|
.provider
|
||||||
.notifier,
|
.notifier,
|
||||||
)
|
)
|
||||||
.register()
|
.register();
|
||||||
.onError(showError);
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: Handle not granted
|
// TODO: Handle not granted
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: Deregister
|
await ref
|
||||||
|
.watch(
|
||||||
|
UnifiedPushController
|
||||||
|
.provider
|
||||||
|
.notifier,
|
||||||
|
)
|
||||||
|
.deregister();
|
||||||
|
}
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
showError(error, stackTrace);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
orElse: () => null,
|
orElse: () => null,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import "package:nexus/controllers/client.dart";
|
||||||
import "package:nexus/controllers/client_state.dart";
|
import "package:nexus/controllers/client_state.dart";
|
||||||
import "package:nexus/models/content/message.dart";
|
import "package:nexus/models/content/message.dart";
|
||||||
import "package:nexus/models/content/sticker.dart";
|
import "package:nexus/models/content/sticker.dart";
|
||||||
import "package:nexus/models/requests/get_event.dart";
|
|
||||||
import "package:nexus/models/requests/register_pusher.dart";
|
import "package:nexus/models/requests/register_pusher.dart";
|
||||||
import "package:unifiedpush/unifiedpush.dart";
|
import "package:unifiedpush/unifiedpush.dart";
|
||||||
import "package:unifiedpush_storage_shared_preferences/storage.dart";
|
import "package:unifiedpush_storage_shared_preferences/storage.dart";
|
||||||
|
|
@ -52,9 +51,10 @@ class UnifiedPushController extends AsyncNotifier<bool> {
|
||||||
json.decode(String.fromCharCodes(message.content)),
|
json.decode(String.fromCharCodes(message.content)),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (event.unreadType?.shouldNotify != true ||
|
if (event == null ||
|
||||||
|
event.unreadType?.shouldNotify != true ||
|
||||||
(!isInBackground &&
|
(!isInBackground &&
|
||||||
await windowManager.isFocused() &&
|
await windowManager.isFocused().onError((_, _) => false) &&
|
||||||
ref.watch(KeyController.provider(KeyController.roomKey)) ==
|
ref.watch(KeyController.provider(KeyController.roomKey)) ==
|
||||||
event.roomId)) {
|
event.roomId)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -77,9 +77,7 @@ class UnifiedPushController extends AsyncNotifier<bool> {
|
||||||
id: event.eventId.hashCode & 0x7fffffff,
|
id: event.eventId.hashCode & 0x7fffffff,
|
||||||
title: room?.metadata?.name ?? "New Event",
|
title: room?.metadata?.name ?? "New Event",
|
||||||
icon: icon,
|
icon: icon,
|
||||||
payload: json.encode(
|
payload: event.eventId,
|
||||||
GetEventRequest(eventId: event.eventId, roomId: event.roomId),
|
|
||||||
),
|
|
||||||
body: switch (event.content) {
|
body: switch (event.content) {
|
||||||
MessageContent(:final body?) ||
|
MessageContent(:final body?) ||
|
||||||
StickerContent(:final body) => body,
|
StickerContent(:final body) => body,
|
||||||
|
|
@ -128,6 +126,24 @@ class UnifiedPushController extends AsyncNotifier<bool> {
|
||||||
if (!alreadyRegistered) ref.invalidateSelf();
|
if (!alreadyRegistered) ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> deregister() async {
|
||||||
|
final clientState = ref.watch(ClientStateController.provider);
|
||||||
|
final key = await UnifiedPushStorageSharedPreferences().keys.get(
|
||||||
|
clientState!.deviceId!,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (key == null) return;
|
||||||
|
|
||||||
|
await ref
|
||||||
|
.watch(ClientController.provider.notifier)
|
||||||
|
.deregisterPusher(
|
||||||
|
.new(appId: "nexus.federated.nexus", pushKey: key.split("=").first),
|
||||||
|
);
|
||||||
|
|
||||||
|
await UnifiedPush.unregister(clientState.deviceId!);
|
||||||
|
ref.invalidateSelf();
|
||||||
|
}
|
||||||
|
|
||||||
static final provider = AsyncNotifierProvider<UnifiedPushController, bool>(
|
static final provider = AsyncNotifierProvider<UnifiedPushController, bool>(
|
||||||
UnifiedPushController.new,
|
UnifiedPushController.new,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
13
lib/models/requests/deregister_pusher.dart
Normal file
13
lib/models/requests/deregister_pusher.dart
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
|
||||||
|
part "deregister_pusher.freezed.dart";
|
||||||
|
part "deregister_pusher.g.dart";
|
||||||
|
|
||||||
|
@Freezed(toJson: false, fromJson: false)
|
||||||
|
@JsonSerializable()
|
||||||
|
class const DeregisterPusherRequest({
|
||||||
|
required final String appId,
|
||||||
|
@JsonKey(name: "pushkey") required final String pushKey,
|
||||||
|
}) with _$DeregisterPusherRequest {
|
||||||
|
Map<String, Object?> toJson() => _$DeregisterPusherRequestToJson(this);
|
||||||
|
}
|
||||||
14
lib/pages/notifications.dart
Normal file
14
lib/pages/notifications.dart
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import "package:material_ui/material_ui.dart";
|
||||||
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:nexus/widgets/appbar.dart";
|
||||||
|
|
||||||
|
class const NotificationsPage({final String? eventId, super.key})
|
||||||
|
extends HookConsumerWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: Appbar(title: Text("Notifications")),
|
||||||
|
body: Placeholder(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,7 +39,7 @@ final class const Appbar({
|
||||||
: (_) => windowManager.startDragging(),
|
: (_) => windowManager.startDragging(),
|
||||||
),
|
),
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
leading: InkWell(onTap: onTap, child: leading),
|
leading: leading == null ? null : InkWell(onTap: onTap, child: leading),
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
scrolledUnderElevation: scrolledUnderElevation,
|
scrolledUnderElevation: scrolledUnderElevation,
|
||||||
actionsPadding: const .symmetric(horizontal: 8),
|
actionsPadding: const .symmetric(horizontal: 8),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue