diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8cf6749..7231167 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 77; objects = { /* Begin PBXBuildFile section */ @@ -15,6 +15,7 @@ 738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */; }; 738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */; }; 738C1EB82D0D76A500A215F3 /* SolarWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 738C1EAB2D0D76A400A215F3 /* SolarWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 7396A3522D16BD890095F4A8 /* NotifyDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7396A3512D16BD890095F4A8 /* NotifyDelegate.swift */; }; 73B7746E2D0E869200A789CE /* SolarShare.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73B774642D0E869200A789CE /* SolarShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 73DA8A012D05C7620024A03E /* SolarNotifyService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73DA89FA2D05C7620024A03E /* SolarNotifyService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; @@ -107,6 +108,7 @@ 731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 738C1EAB2D0D76A400A215F3 /* SolarWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 738C1F132D0D7DDC00A215F3 /* SolarWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SolarWidgetExtension.entitlements; sourceTree = ""; }; + 7396A3512D16BD890095F4A8 /* NotifyDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyDelegate.swift; sourceTree = ""; }; 73B774642D0E869200A789CE /* SolarShare.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarShare.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 73DA89FA2D05C7620024A03E /* SolarNotifyService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarNotifyService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; @@ -342,6 +344,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + 7396A3512D16BD890095F4A8 /* NotifyDelegate.swift */, ); path = Runner; sourceTree = ""; @@ -831,6 +834,7 @@ files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7396A3522D16BD890095F4A8 /* NotifyDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 007814d..098f43b 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -5,18 +5,22 @@ import workmanager @main @objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - - WorkmanagerPlugin.setPluginRegistrantCallback { registry in - GeneratedPluginRegistrant.register(with: registry) - } + let notifyDelegate = NotifyDelegate() - UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*5)) - - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + WorkmanagerPlugin.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) + } + + UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*5)) + + UNUserNotificationCenter.current().delegate = notifyDelegate + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + } diff --git a/ios/Runner/NotifyDelegate.swift b/ios/Runner/NotifyDelegate.swift new file mode 100644 index 0000000..31aadf3 --- /dev/null +++ b/ios/Runner/NotifyDelegate.swift @@ -0,0 +1,20 @@ +// +// NotifyDelegate.swift +// Runner +// +// Created by LittleSheep on 2024/12/21. +// + +import Foundation + +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 + } + + completionHandler() + } +} diff --git a/ios/SolarNotifyService/NotificationService.swift b/ios/SolarNotifyService/NotificationService.swift index 923acbd..9049602 100644 --- a/ios/SolarNotifyService/NotificationService.swift +++ b/ios/SolarNotifyService/NotificationService.swift @@ -61,6 +61,22 @@ 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: [ + UNTextInputNotificationAction( + identifier: "reply_action", + title: "Reply", + options: [] + ), + ], + intentIdentifiers: [], + options: [] + ) + + UNUserNotificationCenter.current().setNotificationCategories([replyableMessageCategory]) + content.categoryIdentifier = replyableMessageCategory.identifier let metadataCopy = metadata as? [String: String] ?? [:] let avatarUrl = getAttachmentUrl(for: avatarIdentifier) diff --git a/ios/SolarWidget/RandomPostWidget.swift b/ios/SolarWidget/RandomPostWidget.swift index 130111c..48cba96 100644 --- a/ios/SolarWidget/RandomPostWidget.swift +++ b/ios/SolarWidget/RandomPostWidget.swift @@ -78,7 +78,7 @@ struct RandomPostWidgetEntryView : View { KFImage.url(URL(string: avatarUrl)) .resizable() .setProcessor(scaleProcessor) - .transition(.opacity) + .fade(duration: 0.25) .aspectRatio(contentMode: .fit) .frame(width: size, height: size) .cornerRadius(size / 2)