@octopus-community/react-native 1.0.7 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OctopusReactNativeSdk.podspec +1 -1
- package/README.md +40 -35
- package/android/build.gradle +2 -0
- package/android/gradle.properties +2 -2
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/AndroidManifestNew.xml +2 -1
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusActivity.kt +56 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusContent.kt +396 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusEventEmitter.kt +22 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusEventSerializer.kt +339 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusReactModule.kt +326 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/{OctopusReactNativeSdkPackage.kt → OctopusReactPackage.kt} +3 -3
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSDKInitializer.kt +53 -9
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSSOAuthenticator.kt +5 -15
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIConfiguration.kt +6 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIConfigurationManager.kt +12 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIController.kt +17 -2
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIViewManager.kt +63 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/ProfileFieldMapper.kt +2 -2
- package/ios/OctopusEventManager.swift +27 -0
- package/ios/OctopusEventSerializer.swift +271 -0
- package/ios/OctopusReactNativeSdk.mm +26 -1
- package/ios/OctopusReactNativeSdk.swift +225 -3
- package/ios/OctopusSDKInitializer.swift +32 -0
- package/ios/OctopusSSOAuthenticator.swift +1 -5
- package/ios/OctopusUIConfiguration.swift +6 -0
- package/ios/OctopusUIManager.swift +134 -10
- package/ios/OctopusUIViewManager.m +7 -0
- package/ios/OctopusUIViewManager.swift +37 -0
- package/lib/module/OctopusUIView.js +39 -0
- package/lib/module/OctopusUIView.js.map +1 -0
- package/lib/module/addHasAccessToCommunityListener.js +33 -0
- package/lib/module/addHasAccessToCommunityListener.js.map +1 -0
- package/lib/module/addNavigateToUrlListener.js +41 -0
- package/lib/module/addNavigateToUrlListener.js.map +1 -0
- package/lib/module/addNotSeenNotificationsCountListener.js +30 -0
- package/lib/module/addNotSeenNotificationsCountListener.js.map +1 -0
- package/lib/module/addSDKEventListener.js +48 -0
- package/lib/module/addSDKEventListener.js.map +1 -0
- package/lib/module/connectUser.js +24 -3
- package/lib/module/connectUser.js.map +1 -1
- package/lib/module/index.js +12 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/initialize.js +13 -12
- package/lib/module/initialize.js.map +1 -1
- package/lib/module/openUI.js +23 -2
- package/lib/module/openUI.js.map +1 -1
- package/lib/module/overrideCommunityAccess.js +36 -0
- package/lib/module/overrideCommunityAccess.js.map +1 -0
- package/lib/module/overrideDefaultLocale.js +75 -0
- package/lib/module/overrideDefaultLocale.js.map +1 -0
- package/lib/module/trackCommunityAccess.js +33 -0
- package/lib/module/trackCommunityAccess.js.map +1 -0
- package/lib/module/trackCustomEvent.js +36 -0
- package/lib/module/trackCustomEvent.js.map +1 -0
- package/lib/module/types/sdkEvents.js +2 -0
- package/lib/module/types/sdkEvents.js.map +1 -0
- package/lib/module/types/urlOpeningStrategy.js +23 -0
- package/lib/module/types/urlOpeningStrategy.js.map +1 -0
- package/lib/module/updateNotSeenNotificationsCount.js +33 -0
- package/lib/module/updateNotSeenNotificationsCount.js.map +1 -0
- package/lib/typescript/src/OctopusUIView.d.ts +32 -0
- package/lib/typescript/src/OctopusUIView.d.ts.map +1 -0
- package/lib/typescript/src/addHasAccessToCommunityListener.d.ts +27 -0
- package/lib/typescript/src/addHasAccessToCommunityListener.d.ts.map +1 -0
- package/lib/typescript/src/addNavigateToUrlListener.d.ts +31 -0
- package/lib/typescript/src/addNavigateToUrlListener.d.ts.map +1 -0
- package/lib/typescript/src/addNotSeenNotificationsCountListener.d.ts +24 -0
- package/lib/typescript/src/addNotSeenNotificationsCountListener.d.ts.map +1 -0
- package/lib/typescript/src/addSDKEventListener.d.ts +43 -0
- package/lib/typescript/src/addSDKEventListener.d.ts.map +1 -0
- package/lib/typescript/src/connectUser.d.ts +24 -8
- package/lib/typescript/src/connectUser.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +13 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/initialize.d.ts +22 -12
- package/lib/typescript/src/initialize.d.ts.map +1 -1
- package/lib/typescript/src/openUI.d.ts +28 -1
- package/lib/typescript/src/openUI.d.ts.map +1 -1
- package/lib/typescript/src/overrideCommunityAccess.d.ts +30 -0
- package/lib/typescript/src/overrideCommunityAccess.d.ts.map +1 -0
- package/lib/typescript/src/overrideDefaultLocale.d.ts +37 -0
- package/lib/typescript/src/overrideDefaultLocale.d.ts.map +1 -0
- package/lib/typescript/src/trackCommunityAccess.d.ts +27 -0
- package/lib/typescript/src/trackCommunityAccess.d.ts.map +1 -0
- package/lib/typescript/src/trackCustomEvent.d.ts +30 -0
- package/lib/typescript/src/trackCustomEvent.d.ts.map +1 -0
- package/lib/typescript/src/types/sdkEvents.d.ts +222 -0
- package/lib/typescript/src/types/sdkEvents.d.ts.map +1 -0
- package/lib/typescript/src/types/urlOpeningStrategy.d.ts +20 -0
- package/lib/typescript/src/types/urlOpeningStrategy.d.ts.map +1 -0
- package/lib/typescript/src/updateNotSeenNotificationsCount.d.ts +27 -0
- package/lib/typescript/src/updateNotSeenNotificationsCount.d.ts.map +1 -0
- package/package.json +2 -1
- package/src/OctopusUIView.tsx +57 -0
- package/src/addHasAccessToCommunityListener.ts +38 -0
- package/src/addNavigateToUrlListener.ts +54 -0
- package/src/addNotSeenNotificationsCountListener.ts +35 -0
- package/src/addSDKEventListener.ts +49 -0
- package/src/connectUser.ts +24 -8
- package/src/index.ts +13 -0
- package/src/initialize.ts +23 -12
- package/src/openUI.ts +32 -2
- package/src/overrideCommunityAccess.ts +33 -0
- package/src/overrideDefaultLocale.ts +88 -0
- package/src/trackCommunityAccess.ts +30 -0
- package/src/trackCustomEvent.ts +36 -0
- package/src/types/sdkEvents.ts +315 -0
- package/src/types/urlOpeningStrategy.ts +20 -0
- package/src/updateNotSeenNotificationsCount.ts +30 -0
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusReactNativeSdkModule.kt +0 -155
- package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIActivity.kt +0 -422
package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSDKInitializer.kt
CHANGED
|
@@ -9,11 +9,11 @@ import android.graphics.Color
|
|
|
9
9
|
|
|
10
10
|
class OctopusSDKInitializer {
|
|
11
11
|
|
|
12
|
-
fun initialize(context: ReactApplicationContext, options: ReadableMap, promise: Promise) {
|
|
12
|
+
fun initialize(context: ReactApplicationContext, options: ReadableMap, promise: Promise): Boolean {
|
|
13
13
|
val apiKey = options.getString("apiKey")
|
|
14
14
|
if (apiKey == null) {
|
|
15
15
|
promise.reject("INITIALIZE_ERROR", "Missing API key")
|
|
16
|
-
return
|
|
16
|
+
return false
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
try {
|
|
@@ -23,16 +23,32 @@ class OctopusSDKInitializer {
|
|
|
23
23
|
val themeConfig = parseThemeConfig(options)
|
|
24
24
|
OctopusThemeManager.setThemeConfig(themeConfig)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
26
|
+
// Store UI configuration separately
|
|
27
|
+
val uiConfiguration = parseUIConfiguration(options)
|
|
28
|
+
OctopusUIConfigurationManager.setUIConfiguration(uiConfiguration)
|
|
29
|
+
|
|
30
|
+
// For "octopus" mode, don't pass connectionMode (it's the default)
|
|
31
|
+
// For "sso" mode, pass the ConnectionMode.SSO
|
|
32
|
+
if (connectionMode != null) {
|
|
33
|
+
OctopusSDK.initialize(
|
|
34
|
+
context = context,
|
|
35
|
+
apiKey = apiKey,
|
|
36
|
+
connectionMode = connectionMode
|
|
37
|
+
)
|
|
38
|
+
} else {
|
|
39
|
+
OctopusSDK.initialize(
|
|
40
|
+
context = context,
|
|
41
|
+
apiKey = apiKey
|
|
42
|
+
)
|
|
43
|
+
}
|
|
31
44
|
promise.resolve(null)
|
|
45
|
+
return true
|
|
32
46
|
} catch (e: InvalidConnectionModeException) {
|
|
33
47
|
promise.reject("INITIALIZE_ERROR", e.message, e)
|
|
48
|
+
return false
|
|
34
49
|
} catch (e: Exception) {
|
|
35
50
|
promise.reject("INITIALIZE_ERROR", "Failed to initialize Octopus SDK", e)
|
|
51
|
+
return false
|
|
36
52
|
}
|
|
37
53
|
}
|
|
38
54
|
|
|
@@ -118,6 +134,33 @@ class OctopusSDKInitializer {
|
|
|
118
134
|
return null
|
|
119
135
|
}
|
|
120
136
|
|
|
137
|
+
fun parseUIConfiguration(options: ReadableMap): OctopusUIConfiguration? {
|
|
138
|
+
val uiMap = options.getMap("ui")
|
|
139
|
+
var bottomContentPadding: Double? = null
|
|
140
|
+
|
|
141
|
+
uiMap?.let { uiOptions ->
|
|
142
|
+
val candidateKeys = listOf("bottomSafeAreaInset", "bottomPadding", "contentPadding", "contentPaddingBottom")
|
|
143
|
+
for (key in candidateKeys) {
|
|
144
|
+
if (uiOptions.hasKey(key)) {
|
|
145
|
+
bottomContentPadding = try {
|
|
146
|
+
uiOptions.getDouble(key).coerceAtLeast(0.0)
|
|
147
|
+
} catch (e: Exception) {
|
|
148
|
+
null
|
|
149
|
+
}
|
|
150
|
+
if (bottomContentPadding != null) {
|
|
151
|
+
break
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return if (bottomContentPadding != null) {
|
|
158
|
+
OctopusUIConfiguration(bottomContentPadding = bottomContentPadding)
|
|
159
|
+
} else {
|
|
160
|
+
null
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
121
164
|
private fun parsePreProcessedFontsConfig(parsedConfig: ReadableMap): OctopusFontsConfig? {
|
|
122
165
|
val textStylesMap = parsedConfig.getMap("textStyles")
|
|
123
166
|
val textStyles = mutableMapOf<String, OctopusTextStyleConfig>()
|
|
@@ -178,7 +221,7 @@ class OctopusSDKInitializer {
|
|
|
178
221
|
}
|
|
179
222
|
}
|
|
180
223
|
|
|
181
|
-
private fun parseConnectionMode(options: ReadableMap): ConnectionMode {
|
|
224
|
+
private fun parseConnectionMode(options: ReadableMap): ConnectionMode? {
|
|
182
225
|
val connectionModeMap = options.getMap("connectionMode")
|
|
183
226
|
return when (val connectionModeType = connectionModeMap?.getString("type")) {
|
|
184
227
|
"sso" -> {
|
|
@@ -190,7 +233,8 @@ class OctopusSDKInitializer {
|
|
|
190
233
|
}
|
|
191
234
|
|
|
192
235
|
"octopus" -> {
|
|
193
|
-
|
|
236
|
+
// For "octopus" mode, return null - OctopusSDK.initialize() will use default mode
|
|
237
|
+
null
|
|
194
238
|
}
|
|
195
239
|
|
|
196
240
|
else -> {
|
package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSSOAuthenticator.kt
CHANGED
|
@@ -4,8 +4,7 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
4
4
|
import com.facebook.react.bridge.Promise
|
|
5
5
|
import com.octopuscommunity.sdk.OctopusSDK
|
|
6
6
|
import com.octopuscommunity.sdk.domain.model.ClientUser
|
|
7
|
-
import com.octopuscommunity.sdk.domain.model.
|
|
8
|
-
import com.octopuscommunity.sdk.domain.model.Image
|
|
7
|
+
import com.octopuscommunity.sdk.domain.model.Resource
|
|
9
8
|
import kotlinx.coroutines.CoroutineScope
|
|
10
9
|
import kotlinx.coroutines.Dispatchers
|
|
11
10
|
import kotlinx.coroutines.launch
|
|
@@ -103,24 +102,16 @@ class OctopusSSOAuthenticator(
|
|
|
103
102
|
return ClientUser.Profile()
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
val ageInformation = if (profileParams.hasKey("legalAgeReached")) {
|
|
107
|
-
if (profileParams.getBoolean("legalAgeReached")) {
|
|
108
|
-
AgeInformation.LegalAgeReached
|
|
109
|
-
} else {
|
|
110
|
-
AgeInformation.Underage
|
|
111
|
-
}
|
|
112
|
-
} else null
|
|
113
|
-
|
|
114
105
|
val profilePicture = profileParams.getString("profilePicture")?.let { pictureUrl ->
|
|
115
106
|
if (pictureUrl.startsWith("http://") || pictureUrl.startsWith("https://")) {
|
|
116
|
-
|
|
107
|
+
Resource.Remote(url = pictureUrl)
|
|
117
108
|
} else if (pictureUrl.startsWith("file") || pictureUrl.startsWith("android.resource")) {
|
|
118
|
-
|
|
109
|
+
Resource.Local(pictureUrl)
|
|
119
110
|
} else if(pictureUrl.isNotBlank()) {
|
|
120
111
|
// Asset names like "assets_images_logo" need conversion
|
|
121
112
|
// Convert to drawable resource URI
|
|
122
113
|
val resourceId = context.resources.getIdentifier(pictureUrl, "drawable", context.packageName)
|
|
123
|
-
|
|
114
|
+
Resource.Local(
|
|
124
115
|
if (resourceId != 0) {
|
|
125
116
|
"android.resource://${context.packageName}/$resourceId"
|
|
126
117
|
} else {
|
|
@@ -136,8 +127,7 @@ class OctopusSSOAuthenticator(
|
|
|
136
127
|
return ClientUser.Profile(
|
|
137
128
|
nickname = profileParams.getString("username"),
|
|
138
129
|
bio = profileParams.getString("biography"),
|
|
139
|
-
|
|
140
|
-
avatar = profilePicture
|
|
130
|
+
picture = profilePicture
|
|
141
131
|
)
|
|
142
132
|
}
|
|
143
133
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package com.octopuscommunity.octopusreactnativesdk
|
|
2
|
+
|
|
3
|
+
object OctopusUIConfigurationManager {
|
|
4
|
+
private var uiConfiguration: OctopusUIConfiguration? = null
|
|
5
|
+
|
|
6
|
+
fun setUIConfiguration(config: OctopusUIConfiguration?) {
|
|
7
|
+
uiConfiguration = config
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
fun getUIConfiguration(): OctopusUIConfiguration? = uiConfiguration
|
|
11
|
+
}
|
|
12
|
+
|
package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIController.kt
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
package com.octopuscommunity.octopusreactnativesdk
|
|
2
2
|
|
|
3
3
|
import android.content.Intent
|
|
4
|
+
import android.net.Uri
|
|
4
5
|
import com.facebook.react.bridge.Promise
|
|
5
6
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.bridge.ReadableMap
|
|
6
8
|
|
|
7
9
|
class OctopusUIController(private val reactContext: ReactApplicationContext) {
|
|
8
10
|
|
|
9
|
-
fun openUI(promise: Promise) {
|
|
11
|
+
fun openUI(options: ReadableMap?, promise: Promise) {
|
|
10
12
|
try {
|
|
11
|
-
val intent = Intent(reactContext,
|
|
13
|
+
val intent = Intent(reactContext, OctopusActivity::class.java)
|
|
12
14
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
15
|
+
val interceptUrls = options?.hasKey("interceptUrls") == true &&
|
|
16
|
+
options.getBoolean("interceptUrls")
|
|
17
|
+
intent.putExtra(OctopusActivity.EXTRA_INTERCEPT_URLS, interceptUrls)
|
|
13
18
|
reactContext.startActivity(intent)
|
|
14
19
|
promise.resolve(null)
|
|
15
20
|
} catch (e: Exception) {
|
|
@@ -28,6 +33,16 @@ class OctopusUIController(private val reactContext: ReactApplicationContext) {
|
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
fun openUrlInBrowser(url: String) {
|
|
37
|
+
try {
|
|
38
|
+
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
|
39
|
+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
40
|
+
reactContext.startActivity(intent)
|
|
41
|
+
} catch (e: Exception) {
|
|
42
|
+
// Ignore if no app can handle the URL
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
31
46
|
companion object {
|
|
32
47
|
const val CLOSE_UI_ACTION = "com.octopuscommunity.octopusreactnativesdk.CLOSE_UI"
|
|
33
48
|
}
|
package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIViewManager.kt
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
package com.octopuscommunity.octopusreactnativesdk
|
|
2
|
+
|
|
3
|
+
import android.view.ViewGroup
|
|
4
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
5
|
+
import androidx.compose.foundation.layout.captionBar
|
|
6
|
+
import androidx.compose.foundation.layout.consumeWindowInsets
|
|
7
|
+
import androidx.compose.foundation.layout.displayCutout
|
|
8
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
9
|
+
import androidx.compose.foundation.layout.ime
|
|
10
|
+
import androidx.compose.foundation.layout.mandatorySystemGestures
|
|
11
|
+
import androidx.compose.foundation.layout.navigationBars
|
|
12
|
+
import androidx.compose.foundation.layout.safeContent
|
|
13
|
+
import androidx.compose.foundation.layout.safeDrawing
|
|
14
|
+
import androidx.compose.foundation.layout.safeGestures
|
|
15
|
+
import androidx.compose.foundation.layout.statusBars
|
|
16
|
+
import androidx.compose.foundation.layout.systemBars
|
|
17
|
+
import androidx.compose.foundation.layout.systemGestures
|
|
18
|
+
import androidx.compose.foundation.layout.tappableElement
|
|
19
|
+
import androidx.compose.foundation.layout.waterfall
|
|
20
|
+
import androidx.compose.material3.MaterialTheme
|
|
21
|
+
import androidx.compose.ui.Modifier
|
|
22
|
+
import androidx.compose.ui.platform.ComposeView
|
|
23
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
24
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
25
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
26
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
27
|
+
|
|
28
|
+
class OctopusUIViewManager(private val reactContext: ReactApplicationContext) :
|
|
29
|
+
SimpleViewManager<ComposeView>() {
|
|
30
|
+
|
|
31
|
+
private var interceptUrls: Boolean = false
|
|
32
|
+
|
|
33
|
+
override fun getName(): String = REACT_CLASS_NAME
|
|
34
|
+
|
|
35
|
+
override fun createViewInstance(reactContext: ThemedReactContext) =
|
|
36
|
+
ComposeView(reactContext).apply {
|
|
37
|
+
layoutParams = ViewGroup.LayoutParams(
|
|
38
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
39
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
setContent {
|
|
43
|
+
MaterialTheme {
|
|
44
|
+
OctopusContent(
|
|
45
|
+
modifier = Modifier.fillMaxSize()
|
|
46
|
+
.consumeWindowInsets(WindowInsets.statusBars)
|
|
47
|
+
.consumeWindowInsets(WindowInsets.navigationBars)
|
|
48
|
+
.consumeWindowInsets(WindowInsets.systemBars),
|
|
49
|
+
interceptUrls = interceptUrls
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@ReactProp(name = "interceptUrls")
|
|
56
|
+
fun setInterceptUrls(view: ComposeView, interceptUrls: Boolean) {
|
|
57
|
+
this.interceptUrls = interceptUrls
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
companion object Companion {
|
|
61
|
+
const val REACT_CLASS_NAME = "OctopusUIView"
|
|
62
|
+
}
|
|
63
|
+
}
|
package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/ProfileFieldMapper.kt
CHANGED
|
@@ -23,7 +23,7 @@ object ProfileFieldMapper {
|
|
|
23
23
|
return when (fieldName) {
|
|
24
24
|
"username" -> ProfileField.NICKNAME
|
|
25
25
|
"biography" -> ProfileField.BIO
|
|
26
|
-
"profilePicture" -> ProfileField.
|
|
26
|
+
"profilePicture" -> ProfileField.PICTURE
|
|
27
27
|
else -> null
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -32,7 +32,7 @@ object ProfileFieldMapper {
|
|
|
32
32
|
return when (profileField) {
|
|
33
33
|
ProfileField.NICKNAME -> "username"
|
|
34
34
|
ProfileField.BIO -> "biography"
|
|
35
|
-
ProfileField.
|
|
35
|
+
ProfileField.PICTURE -> "profilePicture"
|
|
36
36
|
else -> null
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -30,6 +30,33 @@ class OctopusEventManager {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
func emitNotSeenNotificationsCountChanged(count: Int) {
|
|
34
|
+
if hasListeners {
|
|
35
|
+
let eventBody = ["count": count]
|
|
36
|
+
bridge?.eventDispatcher().sendAppEvent(withName: "notSeenNotificationsCountChanged", body: eventBody)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func emitHasAccessToCommunityChanged(hasAccess: Bool) {
|
|
41
|
+
if hasListeners {
|
|
42
|
+
let eventBody = ["hasAccess": hasAccess]
|
|
43
|
+
bridge?.eventDispatcher().sendAppEvent(withName: "hasAccessToCommunityChanged", body: eventBody)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func emitSDKEvent(eventData: [String: Any]) {
|
|
48
|
+
if hasListeners {
|
|
49
|
+
bridge?.eventDispatcher().sendAppEvent(withName: "sdkEvent", body: eventData)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func emitNavigateToUrl(url: String) {
|
|
54
|
+
if hasListeners {
|
|
55
|
+
let eventBody = ["url": url]
|
|
56
|
+
bridge?.eventDispatcher().sendAppEvent(withName: "navigateToUrl", body: eventBody)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
33
60
|
func startObserving() {
|
|
34
61
|
hasListeners = true
|
|
35
62
|
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Octopus
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Serializes OctopusEvent objects to dictionaries for React Native bridge.
|
|
6
|
+
*/
|
|
7
|
+
class OctopusEventSerializer {
|
|
8
|
+
|
|
9
|
+
static func serializeEvent(_ event: OctopusEvent) -> [String: Any]? {
|
|
10
|
+
switch event {
|
|
11
|
+
case .postCreated(let context):
|
|
12
|
+
var contentList: [String] = []
|
|
13
|
+
if context.content.contains(.text) { contentList.append("text") }
|
|
14
|
+
if context.content.contains(.image) { contentList.append("image") }
|
|
15
|
+
if context.content.contains(.poll) { contentList.append("poll") }
|
|
16
|
+
return [
|
|
17
|
+
"type": "postCreated",
|
|
18
|
+
"postId": context.postId,
|
|
19
|
+
"content": contentList,
|
|
20
|
+
"topicId": context.topicId,
|
|
21
|
+
"textLength": context.textLength
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
case .commentCreated(let context):
|
|
25
|
+
return [
|
|
26
|
+
"type": "commentCreated",
|
|
27
|
+
"commentId": context.commentId,
|
|
28
|
+
"postId": context.postId,
|
|
29
|
+
"textLength": context.textLength
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
case .replyCreated(let context):
|
|
33
|
+
return [
|
|
34
|
+
"type": "replyCreated",
|
|
35
|
+
"replyId": context.replyId,
|
|
36
|
+
"commentId": context.commentId,
|
|
37
|
+
"textLength": context.textLength
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
case .contentDeleted(let context):
|
|
41
|
+
return [
|
|
42
|
+
"type": "contentDeleted",
|
|
43
|
+
"contentId": context.contentId,
|
|
44
|
+
"contentKind": serializeContentKind(context.kind)
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
case .reactionModified(let context):
|
|
48
|
+
var data: [String: Any] = [
|
|
49
|
+
"type": "reactionModified",
|
|
50
|
+
"contentId": context.contentId,
|
|
51
|
+
"contentKind": serializeContentKind(context.contentKind)
|
|
52
|
+
]
|
|
53
|
+
if let prev = context.previousReaction {
|
|
54
|
+
data["previousReaction"] = serializeReactionKind(prev)
|
|
55
|
+
}
|
|
56
|
+
if let next = context.newReaction {
|
|
57
|
+
data["newReaction"] = serializeReactionKind(next)
|
|
58
|
+
}
|
|
59
|
+
return data
|
|
60
|
+
|
|
61
|
+
case .pollVoted(let context):
|
|
62
|
+
return [
|
|
63
|
+
"type": "pollVoted",
|
|
64
|
+
"contentId": context.contentId,
|
|
65
|
+
"optionId": context.optionId
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
case .contentReported(let context):
|
|
69
|
+
return [
|
|
70
|
+
"type": "contentReported",
|
|
71
|
+
"contentId": context.contentId,
|
|
72
|
+
"reasons": context.reasons.map { serializeReportReason($0) }
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
case .gamificationPointsGained(let context):
|
|
76
|
+
return [
|
|
77
|
+
"type": "gamificationPointsGained",
|
|
78
|
+
"points": context.pointsGained,
|
|
79
|
+
"action": serializeGamificationPointsGainedAction(context.action)
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
case .gamificationPointsRemoved(let context):
|
|
83
|
+
return [
|
|
84
|
+
"type": "gamificationPointsRemoved",
|
|
85
|
+
"points": context.pointsRemoved,
|
|
86
|
+
"action": serializeGamificationPointsRemovedAction(context.action)
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
case .screenDisplayed(let context):
|
|
90
|
+
return [
|
|
91
|
+
"type": "screenDisplayed",
|
|
92
|
+
"screen": serializeScreen(context.screen)
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
case .notificationClicked(let context):
|
|
96
|
+
var data: [String: Any] = [
|
|
97
|
+
"type": "notificationClicked",
|
|
98
|
+
"notificationId": context.notificationId
|
|
99
|
+
]
|
|
100
|
+
if let contentId = context.contentId {
|
|
101
|
+
data["contentId"] = contentId
|
|
102
|
+
}
|
|
103
|
+
return data
|
|
104
|
+
|
|
105
|
+
case .postClicked(let context):
|
|
106
|
+
return [
|
|
107
|
+
"type": "postClicked",
|
|
108
|
+
"postId": context.postId,
|
|
109
|
+
"source": serializePostClickedSource(context.source)
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
case .translationButtonClicked(let context):
|
|
113
|
+
return [
|
|
114
|
+
"type": "translationButtonClicked",
|
|
115
|
+
"contentId": context.contentId,
|
|
116
|
+
"viewTranslated": context.viewTranslated,
|
|
117
|
+
"contentKind": serializeContentKind(context.contentKind)
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
case .commentButtonClicked(let context):
|
|
121
|
+
return [
|
|
122
|
+
"type": "commentButtonClicked",
|
|
123
|
+
"postId": context.postId
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
case .replyButtonClicked(let context):
|
|
127
|
+
return [
|
|
128
|
+
"type": "replyButtonClicked",
|
|
129
|
+
"commentId": context.commentId
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
case .seeRepliesButtonClicked(let context):
|
|
133
|
+
return [
|
|
134
|
+
"type": "seeRepliesButtonClicked",
|
|
135
|
+
"commentId": context.commentId
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
case .profileModified(let context):
|
|
139
|
+
var data: [String: Any] = [
|
|
140
|
+
"type": "profileModified",
|
|
141
|
+
"nicknameUpdated": context.nickname.isUpdated,
|
|
142
|
+
"bioUpdated": context.bio.isUpdated,
|
|
143
|
+
"pictureUpdated": context.picture.isUpdated
|
|
144
|
+
]
|
|
145
|
+
if case .updated(let bioContext) = context.bio {
|
|
146
|
+
data["bioLength"] = bioContext.bioLength
|
|
147
|
+
}
|
|
148
|
+
if case .updated(let pictureContext) = context.picture {
|
|
149
|
+
data["hasPicture"] = pictureContext.hasPicture
|
|
150
|
+
}
|
|
151
|
+
return data
|
|
152
|
+
|
|
153
|
+
case .sessionStarted(let context):
|
|
154
|
+
return [
|
|
155
|
+
"type": "sessionStarted",
|
|
156
|
+
"sessionId": context.sessionId
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
case .sessionStopped(let context):
|
|
160
|
+
return [
|
|
161
|
+
"type": "sessionStopped",
|
|
162
|
+
"sessionId": context.sessionId
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
@unknown default:
|
|
166
|
+
return nil
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private static func serializeContentKind(_ kind: OctopusEvent.ContentKind) -> String {
|
|
171
|
+
switch kind {
|
|
172
|
+
case .post: return "post"
|
|
173
|
+
case .comment: return "comment"
|
|
174
|
+
case .reply: return "reply"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private static func serializeReactionKind(_ kind: OctopusEvent.ReactionKind) -> String {
|
|
179
|
+
switch kind {
|
|
180
|
+
case .heart: return "heart"
|
|
181
|
+
case .joy: return "joy"
|
|
182
|
+
case .mouthOpen: return "mouthOpen"
|
|
183
|
+
case .clap: return "clap"
|
|
184
|
+
case .cry: return "cry"
|
|
185
|
+
case .rage: return "rage"
|
|
186
|
+
case .unknown: return "unknown"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private static func serializeReportReason(_ reason: OctopusEvent.ReportReason) -> String {
|
|
191
|
+
switch reason {
|
|
192
|
+
case .hateSpeechOrDiscriminationOrHarassment: return "hateSpeech"
|
|
193
|
+
case .explicitOrInappropriateContent: return "explicit"
|
|
194
|
+
case .violenceAndTerrorism: return "violence"
|
|
195
|
+
case .spamAndScams: return "spam"
|
|
196
|
+
case .suicideAndSelfHarm: return "suicide"
|
|
197
|
+
case .fakeProfilesAndImpersonation: return "fakeProfile"
|
|
198
|
+
case .childExploitationOrAbuse: return "childExploitation"
|
|
199
|
+
case .intellectualPropertyViolation: return "intellectualProperty"
|
|
200
|
+
case .other: return "other"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private static func serializeGamificationPointsGainedAction(_ action: OctopusEvent.GamificationPointsGainedAction) -> String {
|
|
205
|
+
switch action {
|
|
206
|
+
case .post: return "post"
|
|
207
|
+
case .comment: return "comment"
|
|
208
|
+
case .reply: return "reply"
|
|
209
|
+
case .reaction: return "reaction"
|
|
210
|
+
case .vote: return "vote"
|
|
211
|
+
case .postCommented: return "postCommented"
|
|
212
|
+
case .profileCompleted: return "profileCompleted"
|
|
213
|
+
case .dailySession: return "dailySession"
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private static func serializeGamificationPointsRemovedAction(_ action: OctopusEvent.GamificationPointsRemovedAction) -> String {
|
|
218
|
+
switch action {
|
|
219
|
+
case .postDeleted: return "postDeleted"
|
|
220
|
+
case .commentDeleted: return "commentDeleted"
|
|
221
|
+
case .replyDeleted: return "replyDeleted"
|
|
222
|
+
case .reactionDeleted: return "reactionDeleted"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private static func serializePostClickedSource(_ source: OctopusEvent.PostClickedSource) -> String {
|
|
227
|
+
switch source {
|
|
228
|
+
case .feed: return "feed"
|
|
229
|
+
case .profile: return "profile"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private static func serializeScreen(_ screen: OctopusEvent.Screen) -> [String: Any] {
|
|
234
|
+
switch screen {
|
|
235
|
+
case .postsFeed(let context):
|
|
236
|
+
var data: [String: Any] = ["type": "postsFeed", "feedId": context.feedId]
|
|
237
|
+
if let relatedTopicId = context.relatedTopicId {
|
|
238
|
+
data["relatedTopicId"] = relatedTopicId
|
|
239
|
+
}
|
|
240
|
+
return data
|
|
241
|
+
case .postDetail(let context):
|
|
242
|
+
return ["type": "postDetail", "postId": context.postId]
|
|
243
|
+
case .commentDetail(let context):
|
|
244
|
+
return ["type": "commentDetail", "commentId": context.commentId]
|
|
245
|
+
case .createPost:
|
|
246
|
+
return ["type": "createPost"]
|
|
247
|
+
case .profile:
|
|
248
|
+
return ["type": "profile"]
|
|
249
|
+
case .otherUserProfile(let context):
|
|
250
|
+
return ["type": "otherUserProfile", "profileId": context.profileId]
|
|
251
|
+
case .editProfile:
|
|
252
|
+
return ["type": "editProfile"]
|
|
253
|
+
case .reportContent:
|
|
254
|
+
return ["type": "reportContent"]
|
|
255
|
+
case .reportProfile:
|
|
256
|
+
return ["type": "reportProfile"]
|
|
257
|
+
case .validateNickname:
|
|
258
|
+
return ["type": "validateNickname"]
|
|
259
|
+
case .settingsList:
|
|
260
|
+
return ["type": "settingsList"]
|
|
261
|
+
case .settingsAccount:
|
|
262
|
+
return ["type": "settingsAccount"]
|
|
263
|
+
case .settingsAbout:
|
|
264
|
+
return ["type": "settingsAbout"]
|
|
265
|
+
case .reportExplanation:
|
|
266
|
+
return ["type": "reportExplanation"]
|
|
267
|
+
case .deleteAccount:
|
|
268
|
+
return ["type": "deleteAccount"]
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -6,9 +6,13 @@ RCT_EXTERN_METHOD(initialize:(NSDictionary *)options
|
|
|
6
6
|
withResolver:(RCTPromiseResolveBlock)resolve
|
|
7
7
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
8
8
|
|
|
9
|
-
RCT_EXTERN_METHOD(openUI:(
|
|
9
|
+
RCT_EXTERN_METHOD(openUI:(NSDictionary *)options
|
|
10
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
10
11
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
11
12
|
|
|
13
|
+
RCT_EXTERN_METHOD(handleUrlStrategy:(NSString *)url
|
|
14
|
+
withStrategy:(NSString *)strategy)
|
|
15
|
+
|
|
12
16
|
RCT_EXTERN_METHOD(closeUI:(RCTPromiseResolveBlock)resolve
|
|
13
17
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
14
18
|
|
|
@@ -36,6 +40,27 @@ RCT_EXTERN_METHOD(updateTheme:(NSDictionary *)themeOptions
|
|
|
36
40
|
withResolver:(RCTPromiseResolveBlock)resolve
|
|
37
41
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
38
42
|
|
|
43
|
+
RCT_EXTERN_METHOD(updateNotSeenNotificationsCount:(RCTPromiseResolveBlock)resolve
|
|
44
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
45
|
+
|
|
46
|
+
RCT_EXTERN_METHOD(trackCustomEvent:(NSString *)name
|
|
47
|
+
withProperties:(NSDictionary *)properties
|
|
48
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
49
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
50
|
+
|
|
51
|
+
RCT_EXTERN_METHOD(overrideDefaultLocale:(NSString *)languageCode
|
|
52
|
+
withCountryCode:(NSString *)countryCode
|
|
53
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
54
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
55
|
+
|
|
56
|
+
RCT_EXTERN_METHOD(overrideCommunityAccess:(BOOL)hasAccess
|
|
57
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
58
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
59
|
+
|
|
60
|
+
RCT_EXTERN_METHOD(trackCommunityAccess:(BOOL)hasAccess
|
|
61
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
62
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
63
|
+
|
|
39
64
|
RCT_EXTERN_METHOD(addListener:(NSString *)eventName)
|
|
40
65
|
|
|
41
66
|
RCT_EXTERN_METHOD(removeListeners:(NSInteger)count)
|