mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
feat(mobile): iOS background sync notifications (#1811)
* adds notification handling logic * notification on background updates for iOS * fixed regression where i accidentally removed load translations from the background sync * fixed ios translations --------- Co-authored-by: Marty Fuhry <marty@fuhry.farm> Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
@@ -37,5 +37,66 @@ end
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
|
||||
# Permission macros for the permission_handler (https://pub.dev/packages/permission_handler)
|
||||
# Start of the permission_handler configuration
|
||||
# Remove the # character in front of the permission you do want to use.
|
||||
target.build_configurations.each do |config|
|
||||
|
||||
# You can enable the permissions needed here. For example to enable camera
|
||||
# permission, just remove the `#` character in front so it looks like this:
|
||||
#
|
||||
# ## dart: PermissionGroup.camera
|
||||
# 'PERMISSION_CAMERA=1'
|
||||
#
|
||||
# Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
|
||||
'$(inherited)',
|
||||
|
||||
## dart: PermissionGroup.calendar
|
||||
# 'PERMISSION_EVENTS=1',
|
||||
|
||||
## dart: PermissionGroup.reminders
|
||||
# 'PERMISSION_REMINDERS=1',
|
||||
|
||||
## dart: PermissionGroup.contacts
|
||||
# 'PERMISSION_CONTACTS=1',
|
||||
|
||||
## dart: PermissionGroup.camera
|
||||
# 'PERMISSION_CAMERA=1',
|
||||
|
||||
## dart: PermissionGroup.microphone
|
||||
# 'PERMISSION_MICROPHONE=1',
|
||||
|
||||
## dart: PermissionGroup.speech
|
||||
# 'PERMISSION_SPEECH_RECOGNIZER=1',
|
||||
|
||||
## dart: PermissionGroup.photos
|
||||
# 'PERMISSION_PHOTOS=1',
|
||||
|
||||
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
|
||||
# 'PERMISSION_LOCATION=1',
|
||||
|
||||
## dart: PermissionGroup.notification
|
||||
'PERMISSION_NOTIFICATIONS=1',
|
||||
|
||||
## dart: PermissionGroup.mediaLibrary
|
||||
# 'PERMISSION_MEDIA_LIBRARY=1',
|
||||
|
||||
## dart: PermissionGroup.sensors
|
||||
# 'PERMISSION_SENSORS=1',
|
||||
|
||||
## dart: PermissionGroup.bluetooth
|
||||
# 'PERMISSION_BLUETOOTH=1',
|
||||
|
||||
## dart: PermissionGroup.appTrackingTransparency
|
||||
# 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',
|
||||
|
||||
## dart: PermissionGroup.criticalAlerts
|
||||
# 'PERMISSION_CRITICAL_ALERTS=1'
|
||||
]
|
||||
|
||||
end
|
||||
# End of the permission_handler configuration
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,6 +26,8 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- path_provider_ios (0.0.1):
|
||||
- Flutter
|
||||
- permission_handler_apple (9.0.4):
|
||||
- Flutter
|
||||
- photo_manager (2.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
@@ -58,6 +60,7 @@ DEPENDENCIES:
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
|
||||
@@ -95,6 +98,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/ios"
|
||||
path_provider_ios:
|
||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
photo_manager:
|
||||
:path: ".symlinks/plugins/photo_manager/ios"
|
||||
share_plus:
|
||||
@@ -123,6 +128,7 @@ SPEC CHECKSUMS:
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
|
||||
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
|
||||
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
|
||||
photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
@@ -133,6 +139,6 @@ SPEC CHECKSUMS:
|
||||
video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
|
||||
PODFILE CHECKSUM: c798208781ca5116c4a3d5927d689946791f0189
|
||||
PODFILE CHECKSUM: 4a7e0475ea85ab7bf89955bc4c7ea9d18b54dfd8
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import UIKit
|
||||
import shared_preferences_foundation
|
||||
import Flutter
|
||||
import BackgroundTasks
|
||||
import path_provider_ios
|
||||
@@ -25,6 +26,10 @@ import photo_manager
|
||||
if !registry.hasPlugin("org.cocoapods.photo-manager") {
|
||||
PhotoManagerPlugin.register(with: registry.registrar(forPlugin: "org.cocoapods.photo-manager")!)
|
||||
}
|
||||
|
||||
if !registry.hasPlugin("org.cocoapods.shared-preferences-foundation") {
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "org.cocoapods.shared-preferences-foundation")!)
|
||||
}
|
||||
}
|
||||
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
|
||||
@@ -25,6 +25,7 @@ class BackgroundSyncWorker {
|
||||
name: "BackgroundImmich"
|
||||
)
|
||||
|
||||
let notificationId = "com.alextran.immich/backgroundNotifications"
|
||||
// The background message passing channel
|
||||
var channel: FlutterMethodChannel?
|
||||
|
||||
@@ -67,15 +68,15 @@ class BackgroundSyncWorker {
|
||||
})
|
||||
break
|
||||
case "updateNotification":
|
||||
// TODO: implement update notification
|
||||
result(true)
|
||||
let handled = self.handleNotification(call)
|
||||
result(handled)
|
||||
break
|
||||
case "showError":
|
||||
// TODO: implement show error
|
||||
result(true)
|
||||
let handled = self.handleError(call)
|
||||
result(handled)
|
||||
break
|
||||
case "clearErrorNotifications":
|
||||
// TODO: implement clear error notifications
|
||||
self.handleClearErrorNotifications()
|
||||
result(true)
|
||||
break
|
||||
case "hasContentChanged":
|
||||
@@ -184,5 +185,87 @@ class BackgroundSyncWorker {
|
||||
channel = nil
|
||||
completionHandler(fetchResult)
|
||||
}
|
||||
|
||||
private func handleNotification(_ call: FlutterMethodCall) -> Bool {
|
||||
|
||||
// Parse the arguments as an array list
|
||||
guard let args = call.arguments as? Array<Any> else {
|
||||
print("Failed to parse \(call.arguments) as array")
|
||||
return false;
|
||||
}
|
||||
|
||||
// Requires 7 arguments passed or else fail
|
||||
guard args.count == 7 else {
|
||||
print("Needs 7 arguments, but was only passed \(args.count)")
|
||||
return false
|
||||
}
|
||||
|
||||
// Parse the arguments to send the notification update
|
||||
let title = args[0] as? String
|
||||
let content = args[1] as? String
|
||||
let progress = args[2] as? Int
|
||||
let maximum = args[3] as? Int
|
||||
let indeterminate = args[4] as? Bool
|
||||
let isDetail = args[5] as? Bool
|
||||
let onlyIfForeground = args[6] as? Bool
|
||||
|
||||
// Build the notification
|
||||
let notificationContent = UNMutableNotificationContent()
|
||||
notificationContent.body = content ?? "Uploading..."
|
||||
notificationContent.title = title ?? "Immich"
|
||||
|
||||
// Add it to the Notification center
|
||||
let notification = UNNotificationRequest(
|
||||
identifier: notificationId,
|
||||
content: notificationContent,
|
||||
trigger: nil
|
||||
)
|
||||
let center = UNUserNotificationCenter.current()
|
||||
center.add(notification) { (error: Error?) in
|
||||
if let theError = error {
|
||||
print("Error showing notifications: \(theError)")
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private func handleError(_ call: FlutterMethodCall) -> Bool {
|
||||
// Parse the arguments as an array list
|
||||
guard let args = call.arguments as? Array<Any> else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Requires 7 arguments passed or else fail
|
||||
guard args.count == 3 else {
|
||||
return false
|
||||
}
|
||||
|
||||
let title = args[0] as? String
|
||||
let content = args[1] as? String
|
||||
let individualTag = args[2] as? String
|
||||
|
||||
// Build the notification
|
||||
let notificationContent = UNMutableNotificationContent()
|
||||
notificationContent.body = content ?? "Error running the backup job."
|
||||
notificationContent.title = title ?? "Immich"
|
||||
|
||||
// Add it to the Notification center
|
||||
let notification = UNNotificationRequest(
|
||||
identifier: notificationId,
|
||||
content: notificationContent,
|
||||
trigger: nil
|
||||
)
|
||||
let center = UNUserNotificationCenter.current()
|
||||
center.add(notification)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private func handleClearErrorNotifications() {
|
||||
let center = UNUserNotificationCenter.current()
|
||||
center.removeDeliveredNotifications(withIdentifiers: [notificationId])
|
||||
center.removePendingNotificationRequests(withIdentifiers: [notificationId])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user