<lambda>null1 package expo.modules.notifications.notifications.categories
2 
3 import android.content.Context
4 import android.os.Bundle
5 import expo.modules.core.errors.InvalidArgumentException
6 import expo.modules.kotlin.Promise
7 import expo.modules.kotlin.exception.Exceptions
8 import expo.modules.kotlin.modules.Module
9 import expo.modules.kotlin.modules.ModuleDefinition
10 import expo.modules.kotlin.records.Field
11 import expo.modules.kotlin.records.Record
12 import expo.modules.kotlin.records.Required
13 import expo.modules.notifications.ModuleNotFoundException
14 import expo.modules.notifications.ResultReceiverBody
15 import expo.modules.notifications.createDefaultResultReceiver
16 import expo.modules.notifications.notifications.categories.serializers.NotificationsCategoriesSerializer
17 import expo.modules.notifications.notifications.model.NotificationAction
18 import expo.modules.notifications.notifications.model.NotificationCategory
19 import expo.modules.notifications.notifications.model.TextInputNotificationAction
20 import expo.modules.notifications.service.NotificationsService
21 import expo.modules.notifications.service.NotificationsService.Companion.deleteCategory
22 import expo.modules.notifications.service.NotificationsService.Companion.getCategories
23 import expo.modules.notifications.service.NotificationsService.Companion.setCategory
24 
25 class NotificationActionRecord : Record {
26   @Field
27   @Required
28   val identifier: String = ""
29 
30   @Field
31   @Required
32   val buttonTitle: String = ""
33 
34   @Field
35   val textInput: TextInput? = null
36 
37   @Field
38   val options = Options()
39 
40   class TextInput : Record {
41     @Field
42     @Required
43     val placeholder: String = ""
44   }
45 
46   class Options : Record {
47     @Field
48     val opensAppToForeground = true
49   }
50 }
51 
52 open class ExpoNotificationCategoriesModule : Module() {
53 
<lambda>null54   protected val serializer by lazy {
55     appContext.legacyModule<NotificationsCategoriesSerializer>()
56       ?: throw ModuleNotFoundException(NotificationsCategoriesSerializer::class)
57   }
58 
59   private val context: Context
60     get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
61 
<lambda>null62   override fun definition() = ModuleDefinition {
63     Name("ExpoNotificationCategoriesModule")
64 
65     AsyncFunction("getNotificationCategoriesAsync") { promise: Promise ->
66       getCategories(
67         context,
68         createResultReceiver { resultCode: Int, resultData: Bundle? ->
69           val categories = resultData?.getParcelableArrayList<NotificationCategory>(NotificationsService.NOTIFICATION_CATEGORIES_KEY)
70           if (resultCode == NotificationsService.SUCCESS_CODE && categories != null) {
71             promise.resolve(serializeCategories(categories))
72           } else {
73             promise.reject("ERR_CATEGORIES_FETCH_FAILED", "A list of notification categories could not be fetched.", null)
74           }
75         }
76       )
77     }
78 
79     AsyncFunction("setNotificationCategoryAsync", this@ExpoNotificationCategoriesModule::setNotificationCategoryAsync)
80 
81     AsyncFunction("deleteNotificationCategoryAsync", this@ExpoNotificationCategoriesModule::deleteNotificationCategoryAsync)
82   }
83 
createResultReceivernull84   private fun createResultReceiver(body: ResultReceiverBody) =
85     createDefaultResultReceiver(null, body)
86 
87   open fun setNotificationCategoryAsync(
88     identifier: String,
89     actionArguments: List<NotificationActionRecord>,
90     categoryOptions: Map<String, Any?>?,
91     promise: Promise
92   ) {
93     val actions = mutableListOf<NotificationAction>()
94     for (actionMap in actionArguments) {
95       val textInputOptions = actionMap.textInput
96       if (textInputOptions != null) {
97         actions.add(
98           TextInputNotificationAction(
99             actionMap.identifier,
100             actionMap.buttonTitle,
101             actionMap.options.opensAppToForeground,
102             textInputOptions.placeholder
103           )
104         )
105       } else {
106         actions.add(
107           NotificationAction(
108             actionMap.identifier,
109             actionMap.buttonTitle,
110             actionMap.options.opensAppToForeground,
111           )
112         )
113       }
114     }
115     if (actions.isEmpty()) {
116       throw InvalidArgumentException("Invalid arguments provided for notification category. Must provide at least one action.")
117     }
118     setCategory(
119       context,
120       NotificationCategory(identifier, actions),
121       createResultReceiver { resultCode: Int, resultData: Bundle? ->
122         val category = resultData?.getParcelable<NotificationCategory>(NotificationsService.NOTIFICATION_CATEGORY_KEY)
123         if (resultCode == NotificationsService.SUCCESS_CODE && category != null) {
124           promise.resolve(serializer.toBundle(category))
125         } else {
126           promise.reject("ERR_CATEGORY_SET_FAILED", "The provided category could not be set.", null)
127         }
128       }
129     )
130   }
131 
deleteNotificationCategoryAsyncnull132   open fun deleteNotificationCategoryAsync(identifier: String, promise: Promise) {
133     deleteCategory(
134       context,
135       identifier,
136       createResultReceiver { resultCode: Int, resultData: Bundle? ->
137         if (resultCode == NotificationsService.SUCCESS_CODE) {
138           promise.resolve(resultData?.getBoolean(NotificationsService.SUCCEEDED_KEY))
139         } else {
140           promise.reject("ERR_CATEGORY_DELETE_FAILED", "The category could not be deleted.", null)
141         }
142       }
143     )
144   }
145 
serializeCategoriesnull146   protected open fun serializeCategories(categories: Collection<NotificationCategory>): List<Bundle?> {
147     return categories.map(serializer::toBundle)
148   }
149 }
150