diff --git a/ios/Podfile b/ios/Podfile index 2e353a9..8f9ec71 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -38,11 +38,23 @@ target 'Runner' do target 'SolarNotifyService' do inherit! :search_paths + use_frameworks! + use_modular_headers! + + pod 'home_widget', :path => '.symlinks/plugins/home_widget/ios' + pod 'shared_preferences_foundation', :path => '.symlinks/plugins/shared_preferences_foundation/darwin' + pod 'Kingfisher', '~> 8.0' end target 'SolarWidgetExtension' do inherit! :search_paths + use_frameworks! + use_modular_headers! + + pod 'home_widget', :path => '.symlinks/plugins/home_widget/ios' + pod 'shared_preferences_foundation', :path => '.symlinks/plugins/shared_preferences_foundation/darwin' + pod 'Kingfisher', '~> 8.0' end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6cad00e..052aaf2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -394,6 +394,6 @@ SPEC CHECKSUMS: WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 -PODFILE CHECKSUM: 91f63c7518ec23e05bec109c56194c4b282abbd1 +PODFILE CHECKSUM: c287205af8b370f21f61cbff93ce745f0157a3c8 COCOAPODS: 1.16.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7231167..b006d1b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,13 +3,12 @@ archiveVersion = 1; classes = { }; - objectVersion = 77; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 0B21A2B78F1AE403D3BE143E /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26CC8DE2338798EAB472B62D /* Pods_RunnerTests.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2630F2992106E991467A6FC4 /* Pods_SolarWidgetExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F357CFDA89A0D9E5692846D4 /* Pods_SolarWidgetExtension.framework */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */; }; @@ -23,8 +22,9 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - A0DA907BED0C7BC1351253EC /* Pods_SolarNotifyService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B83A5C5D84D0F730A80A03E3 /* Pods_SolarNotifyService.framework */; }; CED170BFB6A72CDDAC285637 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDF483E994343CDFBF9BA347 /* Pods_Runner.framework */; }; + D5125CF12F159F0B8BC7641D /* Pods_SolarNotifyService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02469D286F48D84300484B1E /* Pods_SolarNotifyService.framework */; }; + D962B51F682FBDEC00AC7281 /* Pods_SolarWidgetExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B1A159F5551E280D0EFC129 /* Pods_SolarWidgetExtension.framework */; }; F51C4E3C8FA95426C91FC0A4 /* Pods_SolarShare.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */; }; /* End PBXBuildFile section */ @@ -86,6 +86,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 02469D286F48D84300484B1E /* Pods_SolarNotifyService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarNotifyService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1077EFD9ACF793E9DA5D5B63 /* Pods-Runner-SolarNotifyService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarNotifyService.release.xcconfig"; path = "Target Support Files/Pods-Runner-SolarNotifyService/Pods-Runner-SolarNotifyService.release.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarShare.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -96,6 +98,7 @@ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 40B53769EB464E54DACA7CE4 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 430F31F96B82659CBEAD4326 /* Pods-Runner-SolarWidgetExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarWidgetExtension.profile.xcconfig"; path = "Target Support Files/Pods-Runner-SolarWidgetExtension/Pods-Runner-SolarWidgetExtension.profile.xcconfig"; sourceTree = ""; }; 48AE73F9950AF4FB02B5E9F4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 4A2F84B6033057E3BD2C7CB8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 4CBF45ABD292EE527D0A4D1E /* Pods-SolarNotifyService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarNotifyService.profile.xcconfig"; path = "Target Support Files/Pods-SolarNotifyService/Pods-SolarNotifyService.profile.xcconfig"; sourceTree = ""; }; @@ -114,6 +117,9 @@ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7B1A159F5551E280D0EFC129 /* Pods_SolarWidgetExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarWidgetExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8E44A071621D5CAF864FB2F1 /* Pods-Runner-SolarNotifyService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarNotifyService.debug.xcconfig"; path = "Target Support Files/Pods-Runner-SolarNotifyService/Pods-Runner-SolarNotifyService.debug.xcconfig"; sourceTree = ""; }; + 931FBE9EDB99B3AD8B1FFB00 /* Pods-Runner-SolarWidgetExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarWidgetExtension.release.xcconfig"; path = "Target Support Files/Pods-Runner-SolarWidgetExtension/Pods-Runner-SolarWidgetExtension.release.xcconfig"; sourceTree = ""; }; 96081771773FA019A97CCC3F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -124,12 +130,12 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A2C24C5238FAC44EA2CCF738 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; B1763F1D7318A2745CA7EDFE /* Pods-SolarShare.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.release.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.release.xcconfig"; sourceTree = ""; }; - B83A5C5D84D0F730A80A03E3 /* Pods_SolarNotifyService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarNotifyService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B4550C68292419CDC580808B /* Pods-Runner-SolarNotifyService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarNotifyService.profile.xcconfig"; path = "Target Support Files/Pods-Runner-SolarNotifyService/Pods-Runner-SolarNotifyService.profile.xcconfig"; sourceTree = ""; }; BCE0C4086B776A27B202B373 /* Pods-SolarWidgetExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarWidgetExtension.profile.xcconfig"; path = "Target Support Files/Pods-SolarWidgetExtension/Pods-SolarWidgetExtension.profile.xcconfig"; sourceTree = ""; }; + BFF3B436D74FA8CBFFE34A27 /* Pods-Runner-SolarWidgetExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarWidgetExtension.debug.xcconfig"; path = "Target Support Files/Pods-Runner-SolarWidgetExtension/Pods-Runner-SolarWidgetExtension.debug.xcconfig"; sourceTree = ""; }; D7E1FA77FDA53439DB2C0E75 /* Pods-SolarNotifyService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarNotifyService.release.xcconfig"; path = "Target Support Files/Pods-SolarNotifyService/Pods-SolarNotifyService.release.xcconfig"; sourceTree = ""; }; D96D1DB4ED46A2640C1B9D34 /* Pods-SolarNotifyService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarNotifyService.debug.xcconfig"; path = "Target Support Files/Pods-SolarNotifyService/Pods-SolarNotifyService.debug.xcconfig"; sourceTree = ""; }; EDF483E994343CDFBF9BA347 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F357CFDA89A0D9E5692846D4 /* Pods_SolarWidgetExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarWidgetExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ @@ -229,7 +235,7 @@ files = ( 738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */, 738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */, - 2630F2992106E991467A6FC4 /* Pods_SolarWidgetExtension.framework in Frameworks */, + D962B51F682FBDEC00AC7281 /* Pods_SolarWidgetExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -245,7 +251,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A0DA907BED0C7BC1351253EC /* Pods_SolarNotifyService.framework in Frameworks */, + D5125CF12F159F0B8BC7641D /* Pods_SolarNotifyService.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -276,8 +282,8 @@ 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */, 731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */, 16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */, - F357CFDA89A0D9E5692846D4 /* Pods_SolarWidgetExtension.framework */, - B83A5C5D84D0F730A80A03E3 /* Pods_SolarNotifyService.framework */, + 02469D286F48D84300484B1E /* Pods_SolarNotifyService.framework */, + 7B1A159F5551E280D0EFC129 /* Pods_SolarWidgetExtension.framework */, ); name = Frameworks; sourceTree = ""; @@ -367,6 +373,12 @@ D96D1DB4ED46A2640C1B9D34 /* Pods-SolarNotifyService.debug.xcconfig */, D7E1FA77FDA53439DB2C0E75 /* Pods-SolarNotifyService.release.xcconfig */, 4CBF45ABD292EE527D0A4D1E /* Pods-SolarNotifyService.profile.xcconfig */, + 8E44A071621D5CAF864FB2F1 /* Pods-Runner-SolarNotifyService.debug.xcconfig */, + 1077EFD9ACF793E9DA5D5B63 /* Pods-Runner-SolarNotifyService.release.xcconfig */, + B4550C68292419CDC580808B /* Pods-Runner-SolarNotifyService.profile.xcconfig */, + BFF3B436D74FA8CBFFE34A27 /* Pods-Runner-SolarWidgetExtension.debug.xcconfig */, + 931FBE9EDB99B3AD8B1FFB00 /* Pods-Runner-SolarWidgetExtension.release.xcconfig */, + 430F31F96B82659CBEAD4326 /* Pods-Runner-SolarWidgetExtension.profile.xcconfig */, ); path = Pods; sourceTree = ""; diff --git a/ios/Runner/AppIntent.swift b/ios/Runner/AppIntent.swift new file mode 100644 index 0000000..3db3b48 --- /dev/null +++ b/ios/Runner/AppIntent.swift @@ -0,0 +1,39 @@ +// +// AppIntent.swift +// Runner +// +// Created by LittleSheep on 2024/12/21. +// + +import AppIntents +import Flutter +import Foundation +import home_widget + +@available(iOS 17, *) +public struct AppBackgroundIntent: AppIntent { + static public var title: LocalizedStringResource = "Solar Network Background Intent" + + @Parameter(title: "Widget URI") + var url: URL? + + @Parameter(title: "AppGroup") + var appGroup: String? + + public init() {} + + public init(url: URL?, appGroup: String?) { + self.url = url + self.appGroup = appGroup + } + + public func perform() async throws -> some IntentResult { + await HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!) + + return .result() + } +} + +@available(iOS 17, *) +@available(iOSApplicationExtension, unavailable) +extension AppBackgroundIntent: ForegroundContinuableIntent {} diff --git a/ios/Runner/NotifyDelegate.swift b/ios/Runner/NotifyDelegate.swift index 31aadf3..a61f3b2 100644 --- a/ios/Runner/NotifyDelegate.swift +++ b/ios/Runner/NotifyDelegate.swift @@ -6,13 +6,34 @@ // import Foundation +import home_widget class NotifyDelegate: UIResponder, UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { if let textResponse = response as? UNTextInputNotificationResponse { - let userText = textResponse.userText - print("User replied: \(userText)") - // Handle the reply text + let content = response.notification.request.content + guard let metadata = content.userInfo["metadata"] as? [AnyHashable: Any] else { + return + } + + let channelId = metadata["channel_id"] as? Int + let eventId = metadata["event_id"] as? Int + + + if #available(iOS 17, *) { + Task { + await HomeWidgetBackgroundWorker.run( + url: URL(string: "solink:///chat/reply")?.appending(queryItems: [ + URLQueryItem(name: "channel_id", value: String(channelId ?? 0)), + URLQueryItem(name: "event_id", value: String(eventId ?? 0)), + URLQueryItem(name: "text", value: textResponse.userText) + ]), + appGroup: "group.solsynth.solian" + ) + } + } else { + // Fallback on earlier versions + } } completionHandler() diff --git a/ios/SolarNotifyService/NotificationService.swift b/ios/SolarNotifyService/NotificationService.swift index 9049602..262284f 100644 --- a/ios/SolarNotifyService/NotificationService.swift +++ b/ios/SolarNotifyService/NotificationService.swift @@ -61,7 +61,7 @@ class NotificationService: UNNotificationServiceExtension { guard let avatarIdentifier = metadata["avatar"] as? String else { throw ParseNotificationPayloadError.missingAvatarUrl("The notification has no avatar.") } - + let replyableMessageCategory = UNNotificationCategory( identifier: content.categoryIdentifier, actions: [ @@ -88,7 +88,7 @@ class NotificationService: UNNotificationServiceExtension { case .failure(let error): print("Unable to get avatar url: \(error)") } - + let handle = INPersonHandle(value: "\(metadataCopy["user_id"] ?? "")", type: .unknown) let sender = INPerson( personHandle: handle, @@ -164,7 +164,7 @@ class NotificationService: UNNotificationServiceExtension { } } } - + private func attachLocalMedia(to content: UNMutableNotificationContent, fileType type: String?, from localUrl: URL, withIdentifier identifier: String) { do { let attachment = try UNNotificationAttachment(identifier: identifier, url: localUrl, options: [ diff --git a/lib/main.dart b/lib/main.dart index 716fe0f..9a2a3d3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -51,14 +51,29 @@ void appBackgroundDispatcher() { case "WidgetUpdateRandomPost": await widgetUpdateRandomPost(); return true; - case "ChatReplyMessage": - return true; default: return true; } }); } +@pragma("vm:entry-point") +FutureOr appInteractiveBackgroundDispatcher(Uri? data) async { + print('Interactive background dispatcher called with $data'); + switch (data?.path) { + case "/chat/reply": + final channelId = data?.queryParameters['channel_id']; + final eventId = data?.queryParameters['event_id']; + final message = data?.queryParameters['text']; + if (channelId != null && eventId != null && (message?.isNotEmpty ?? false)) { + await chatReplyMessage(channelId, eventId, message!); + } + break; + default: + break; + } +} + void main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); @@ -90,13 +105,15 @@ void main() async { appBackgroundDispatcher, isInDebugMode: kDebugMode, ); - Workmanager().registerPeriodicTask( - "widget-update-random-post", - "WidgetUpdateRandomPost", - frequency: Duration(minutes: 1), - constraints: Constraints(networkType: NetworkType.connected), - tag: "widget-update", - ); + if (Platform.isAndroid) { + Workmanager().registerPeriodicTask( + "widget-update-random-post", + "WidgetUpdateRandomPost", + frequency: Duration(minutes: 1), + constraints: Constraints(networkType: NetworkType.connected), + tag: "widget-update", + ); + } } runApp(const SolianApp()); diff --git a/lib/providers/channel.dart b/lib/providers/channel.dart index 5c8ad7e..3f9f3ec 100644 --- a/lib/providers/channel.dart +++ b/lib/providers/channel.dart @@ -125,10 +125,8 @@ class ChatChannelProvider extends ChangeNotifier { final channelBox = await Hive.openBox( '${ChatMessageController.kChatMessageBoxPrefix}${channel.id}', ); - final lastMessage = channelBox.isNotEmpty - ? channelBox.values - .reduce((a, b) => a.createdAt.isAfter(b.createdAt) ? a : b) - : null; + final lastMessage = + channelBox.isNotEmpty ? channelBox.values.reduce((a, b) => a.createdAt.isAfter(b.createdAt) ? a : b) : null; if (lastMessage != null) result.add(lastMessage); channelBox.close(); } @@ -142,3 +140,19 @@ class ChatChannelProvider extends ChangeNotifier { super.dispose(); } } + +Future chatReplyMessage(channelId, eventId, String message) async { + print('Chat reply message called with $channelId $eventId $message'); + try { + final snc = await SnNetworkProvider.createOffContextClient(); + await snc.post('/cgi/im/quick/$channelId/reply/$eventId', data: { + 'type': 'messages.new', + 'body': { + 'text': message, + 'algorithm': 'plain', + }, + }); + } catch (err) { + print('Failed to send chat reply message: $err'); + } +} diff --git a/lib/providers/sn_network.dart b/lib/providers/sn_network.dart index b79d01f..76eaadd 100644 --- a/lib/providers/sn_network.dart +++ b/lib/providers/sn_network.dart @@ -92,7 +92,7 @@ class SnNetworkProvider { RequestOptions options, RequestInterceptorHandler handler, ) async { - final atk = await _getFreshAtk(client, prefs.getString(kAtkStoreKey), (atk, rtk) { + final atk = await _getFreshAtk(client, prefs.getString(kAtkStoreKey), prefs.getString(kRtkStoreKey), (atk, rtk) { prefs.setString(kAtkStoreKey, atk); prefs.setString(kRtkStoreKey, rtk); }); @@ -145,12 +145,12 @@ class SnNetworkProvider { final tkLock = Lock(); Future getFreshAtk() async { - return await _getFreshAtk(client, _prefs.getString(kAtkStoreKey), (atk, rtk) { + return await _getFreshAtk(client, _prefs.getString(kAtkStoreKey), _prefs.getString(kRtkStoreKey), (atk, rtk) { setTokenPair(atk, rtk); }); } - static Future _getFreshAtk(Dio client, String? atk, Function(String atk, String rtk)? onRefresh) async { + static Future _getFreshAtk(Dio client, String? atk, String? rtk, Function(String atk, String rtk)? onRefresh) async { if (_refreshCompleter != null) { return await _refreshCompleter!.future; } else { @@ -183,7 +183,7 @@ class SnNetworkProvider { final exp = jsonDecode(payload)['exp']; if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) { log('Access token need refresh, doing it at ${DateTime.now()}'); - final result = await _refreshToken(client.options.baseUrl, atk); + final result = await _refreshToken(client.options.baseUrl, rtk); if (result == null) { atk = null; } else { diff --git a/lib/providers/widget.dart b/lib/providers/widget.dart index 56e47dd..430ef5b 100644 --- a/lib/providers/widget.dart +++ b/lib/providers/widget.dart @@ -1,9 +1,11 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; +import 'package:surface/main.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/types/post.dart'; @@ -15,6 +17,8 @@ class HomeWidgetProvider { if (!kIsWeb && Platform.isIOS) { await HomeWidget.setAppGroupId("group.solsynth.solian"); } + + await HomeWidget.registerInteractivityCallback(appInteractiveBackgroundDispatcher); } Future saveWidgetData(String id, dynamic data, {bool update = true}) async { diff --git a/pubspec.lock b/pubspec.lock index b81c854..58bb7b0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2003,10 +2003,10 @@ packages: dependency: "direct main" description: name: wakelock_plus - sha256: "1aeab49f24aec1e5ab417d7cdfc47c7bbcb815353f1840667ffe68c89a0cd2e6" + sha256: "36c88af0b930121941345306d259ec4cc4ecca3b151c02e3a9e71aede83c615e" url: "https://pub.dev" source: hosted - version: "1.2.9" + version: "1.2.10" wakelock_plus_platform_interface: dependency: transitive description: