From bf7b66d5c1c0d7f7bdcc1c1aa43b6881d797d1e8 Mon Sep 17 00:00:00 2001 From: Hailey Date: Wed, 15 May 2024 11:49:07 -0700 Subject: Add push notification extensions (#4005) * add wav * add sound to config * add extension to `updateExtensions.sh` * add ios source files * add a build extension * add a new module * use correct type on ios * update the build plugin * add android handler * create a patch for expo-notifications * basic android implementation * add entitlements for notifications extension * add some generic logic for ios * add age check logic * add extension to app config * remove dash * move directory * rename again * update privacy manifest * add prefs storage ios * better types * create interface for setting and getting prefs * add notifications prefs for android * add functions to module * add types to js * add prefs context * add web stub * wrap the app * fix types * more preferences for ios * add a test toggle * swap vars * update patch * fix patch error * fix typo * sigh * sigh * get stored prefs on launch * anotehr type * simplify * about finished * comment * adjust plugin * use supported file types * update NSE * futureproof ios * futureproof android * update sound file name * handle initialization * more cleanup * update js types * strict js types * set the notification channel * rm * add silent channel * add mute logic * update patch * podfile * adjust channels * fix android channel * update readme * oreo or higher * nit * don't use getValue * nit --- .../ExpoBackgroundNotificationHandlerModule.swift | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift (limited to 'modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift') diff --git a/modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift b/modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift new file mode 100644 index 000000000..08972a04c --- /dev/null +++ b/modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift @@ -0,0 +1,116 @@ +import ExpoModulesCore + +let APP_GROUP = "group.app.bsky" + +let DEFAULTS: [String:Any] = [ + "playSoundChat" : true, + "playSoundFollow": false, + "playSoundLike": false, + "playSoundMention": false, + "playSoundQuote": false, + "playSoundReply": false, + "playSoundRepost": false, + "mutedThreads": [:] as! [String:[String]] +] + +/* + * The purpose of this module is to store values that are needed by the notification service + * extension. Since we would rather get and store values such as age or user mute state + * while the app is foregrounded, we should use this module liberally. We should aim to keep + * background fetches to a minimum (two or three times per hour) while the app is backgrounded + * or killed + */ +public class ExpoBackgroundNotificationHandlerModule: Module { + let userDefaults = UserDefaults(suiteName: APP_GROUP) + + public func definition() -> ModuleDefinition { + Name("ExpoBackgroundNotificationHandler") + + OnCreate { + DEFAULTS.forEach { p in + if userDefaults?.value(forKey: p.key) == nil { + userDefaults?.setValue(p.value, forKey: p.key) + } + } + } + + AsyncFunction("getAllPrefsAsync") { () -> [String:Any]? in + var keys: [String] = [] + DEFAULTS.forEach { p in + keys.append(p.key) + } + return userDefaults?.dictionaryWithValues(forKeys: keys) + } + + AsyncFunction("getBoolAsync") { (forKey: String) -> Bool in + if let pref = userDefaults?.bool(forKey: forKey) { + return pref + } + return false + } + + AsyncFunction("getStringAsync") { (forKey: String) -> String? in + if let pref = userDefaults?.string(forKey: forKey) { + return pref + } + return nil + } + + AsyncFunction("getStringArrayAsync") { (forKey: String) -> [String]? in + if let pref = userDefaults?.stringArray(forKey: forKey) { + return pref + } + return nil + } + + AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) -> Void in + userDefaults?.setValue(value, forKey: forKey) + } + + AsyncFunction("setStringAsync") { (forKey: String, value: String) -> Void in + userDefaults?.setValue(value, forKey: forKey) + } + + AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) -> Void in + userDefaults?.setValue(value, forKey: forKey) + } + + AsyncFunction("addToStringArrayAsync") { (forKey: String, string: String) in + if var curr = userDefaults?.stringArray(forKey: forKey), + !curr.contains(string) + { + curr.append(string) + userDefaults?.setValue(curr, forKey: forKey) + } + } + + AsyncFunction("removeFromStringArrayAsync") { (forKey: String, string: String) in + if var curr = userDefaults?.stringArray(forKey: forKey) { + curr.removeAll { s in + return s == string + } + userDefaults?.setValue(curr, forKey: forKey) + } + } + + AsyncFunction("addManyToStringArrayAsync") { (forKey: String, strings: [String]) in + if var curr = userDefaults?.stringArray(forKey: forKey) { + strings.forEach { s in + if !curr.contains(s) { + curr.append(s) + } + } + userDefaults?.setValue(curr, forKey: forKey) + } + } + + AsyncFunction("removeManyFromStringArrayAsync") { (forKey: String, strings: [String]) in + if var curr = userDefaults?.stringArray(forKey: forKey) { + strings.forEach { s in + curr.removeAll(where: { $0 == s }) + } + userDefaults?.setValue(curr, forKey: forKey) + } + } + } +} -- cgit 1.4.1