craft-native 0.0.89 → 0.0.91
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/dist/android/src/index.js +285 -44
- package/dist/android/src/promise-runtime.d.ts +3 -0
- package/dist/android/templates/CraftBridge.kt.template +1951 -1193
- package/dist/android/templates/CraftHealthConnect.kt.template +45 -6
- package/dist/android/templates/CraftHealthConnectStub.kt.template +7 -1
- package/dist/android/templates/CraftNative.kt.template +2231 -0
- package/dist/android/templates/LocationRecordingService.kt.template +34 -9
- package/dist/android/templates/MainActivity.kt.template +25 -2
- package/dist/android/templates/proguard-rules.pro.template +4 -1
- package/dist/android/templates/test-bridges.html +10 -33
- package/dist/api/index.d.ts +1 -1
- package/dist/api/ios-advanced.d.ts +8 -5
- package/dist/api/live-activity-handle.d.ts +6 -0
- package/dist/api/mobile.d.ts +13 -5
- package/dist/api/window.d.ts +2 -0
- package/dist/cli.js +404 -128
- package/dist/index.cjs +65 -17
- package/dist/index.js +65 -17
- package/dist/ios/src/index.js +22 -4
- package/dist/ios/templates/CraftApp.swift +473 -60
- package/dist/ios/templates/CraftWatchApp.swift.template +8 -0
- package/dist/ios/templates/WatchApp.Info.plist.template +2 -0
- package/dist/ios/templates/WatchExtension.Info.plist.template +34 -0
- package/dist/ios/templates/project.yml.template +10 -4
- package/dist/mobile.js +36 -13
- package/dist/scaffold-version.d.ts +5 -0
- package/package.json +1 -1
- package/dist/android/templates/CraftBridgeExtensions.kt.template +0 -383
- package/dist/android/templates/CraftWidgetProvider.kt.template +0 -246
|
@@ -102,6 +102,14 @@ extension CraftWatchSession: WCSessionDelegate {
|
|
|
102
102
|
nonisolated func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
|
|
103
103
|
Task { @MainActor in apply(userInfo) }
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
#if os(iOS)
|
|
107
|
+
nonisolated func sessionDidBecomeInactive(_ session: WCSession) {}
|
|
108
|
+
|
|
109
|
+
nonisolated func sessionDidDeactivate(_ session: WCSession) {
|
|
110
|
+
session.activate()
|
|
111
|
+
}
|
|
112
|
+
#endif
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
struct CraftWatchRecordingView: View {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleDisplayName</key>
|
|
8
|
+
<string>{{APP_NAME}}</string>
|
|
9
|
+
<key>CFBundleExecutable</key>
|
|
10
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
11
|
+
<key>CFBundleIdentifier</key>
|
|
12
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
13
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
14
|
+
<string>6.0</string>
|
|
15
|
+
<key>CFBundleName</key>
|
|
16
|
+
<string>$(PRODUCT_NAME)</string>
|
|
17
|
+
<key>CFBundlePackageType</key>
|
|
18
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
19
|
+
<key>CFBundleShortVersionString</key>
|
|
20
|
+
<string>$(MARKETING_VERSION)</string>
|
|
21
|
+
<key>CFBundleVersion</key>
|
|
22
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
23
|
+
<key>NSExtension</key>
|
|
24
|
+
<dict>
|
|
25
|
+
<key>NSExtensionAttributes</key>
|
|
26
|
+
<dict>
|
|
27
|
+
<key>WKAppBundleIdentifier</key>
|
|
28
|
+
<string>{{BUNDLE_ID}}.watchkitapp</string>
|
|
29
|
+
</dict>
|
|
30
|
+
<key>NSExtensionPointIdentifier</key>
|
|
31
|
+
<string>com.apple.watchkit</string>
|
|
32
|
+
</dict>
|
|
33
|
+
</dict>
|
|
34
|
+
</plist>
|
|
@@ -4,10 +4,16 @@ options:
|
|
|
4
4
|
deploymentTarget:
|
|
5
5
|
iOS: "{{IOS_VERSION}}"
|
|
6
6
|
settings:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
base:
|
|
8
|
+
MARKETING_VERSION: "{{VERSION}}"
|
|
9
|
+
CURRENT_PROJECT_VERSION: "{{BUILD_NUMBER}}"
|
|
10
|
+
CODE_SIGN_STYLE: Automatic
|
|
11
|
+
DEVELOPMENT_TEAM: "{{TEAM_ID}}"
|
|
12
|
+
configs:
|
|
13
|
+
debug:
|
|
14
|
+
CRAFT_APNS_ENVIRONMENT: development
|
|
15
|
+
release:
|
|
16
|
+
CRAFT_APNS_ENVIRONMENT: production
|
|
11
17
|
targets:
|
|
12
18
|
{{APP_NAME}}:
|
|
13
19
|
type: application
|
package/dist/mobile.js
CHANGED
|
@@ -15,6 +15,15 @@ function secureUUID() {
|
|
|
15
15
|
throw new Error("[Craft] No Web Crypto available; cannot generate secure IDs");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
// src/api/live-activity-handle.ts
|
|
19
|
+
function createLiveActivityHandle(id, update, end) {
|
|
20
|
+
return {
|
|
21
|
+
id,
|
|
22
|
+
update,
|
|
23
|
+
end
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
18
27
|
// src/api/mobile.ts
|
|
19
28
|
var WEB_DEVICE_ID_KEY = "__craft_web_device_id__";
|
|
20
29
|
function _webFallbackDeviceId() {
|
|
@@ -637,25 +646,39 @@ var health = {
|
|
|
637
646
|
return craft.health.saveWorkout(workout);
|
|
638
647
|
}
|
|
639
648
|
};
|
|
649
|
+
async function updateLiveActivity(idOrState, state) {
|
|
650
|
+
const craft = getCraftRoot();
|
|
651
|
+
if (!craft?.liveActivity?.update)
|
|
652
|
+
return;
|
|
653
|
+
if (typeof idOrState === "string") {
|
|
654
|
+
await craft.liveActivity.update(idOrState, state ?? {});
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
await craft.liveActivity.update(idOrState);
|
|
658
|
+
}
|
|
659
|
+
async function endLiveActivity(id, finalState) {
|
|
660
|
+
const craft = getCraftRoot();
|
|
661
|
+
if (!craft?.liveActivity?.end)
|
|
662
|
+
return;
|
|
663
|
+
if (id !== undefined) {
|
|
664
|
+
await craft.liveActivity.end(id, finalState);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
await craft.liveActivity.end();
|
|
668
|
+
}
|
|
640
669
|
var liveActivities = {
|
|
641
670
|
async start(options) {
|
|
642
671
|
const craft = getCraftRoot();
|
|
643
672
|
if (!craft?.liveActivity?.start)
|
|
644
673
|
throw new Error("Live Activities are unavailable");
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
return;
|
|
651
|
-
await craft.liveActivity.update(state);
|
|
674
|
+
const result = await craft.liveActivity.start(options);
|
|
675
|
+
if (!result || typeof result.id !== "string" || result.id.length === 0) {
|
|
676
|
+
throw new Error("Live Activities returned an invalid activity id");
|
|
677
|
+
}
|
|
678
|
+
return createLiveActivityHandle(result.id, (state) => updateLiveActivity(result.id, state), (finalState) => endLiveActivity(result.id, finalState));
|
|
652
679
|
},
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
if (!craft?.liveActivity?.end)
|
|
656
|
-
return;
|
|
657
|
-
await craft.liveActivity.end();
|
|
658
|
-
}
|
|
680
|
+
update: updateLiveActivity,
|
|
681
|
+
end: endLiveActivity
|
|
659
682
|
};
|
|
660
683
|
var watchConnectivity = {
|
|
661
684
|
async send(message) {
|
package/package.json
CHANGED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
package {{PACKAGE_NAME}}
|
|
2
|
-
|
|
3
|
-
import android.app.Activity
|
|
4
|
-
import android.content.Context
|
|
5
|
-
import androidx.compose.foundation.layout.*
|
|
6
|
-
import androidx.compose.material3.*
|
|
7
|
-
import androidx.compose.runtime.*
|
|
8
|
-
import androidx.compose.ui.Modifier
|
|
9
|
-
import androidx.work.*
|
|
10
|
-
import com.google.android.material.color.DynamicColors
|
|
11
|
-
import com.google.firebase.analytics.FirebaseAnalytics
|
|
12
|
-
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|
13
|
-
import com.google.firebase.messaging.FirebaseMessaging
|
|
14
|
-
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
|
|
15
|
-
import java.util.concurrent.TimeUnit
|
|
16
|
-
|
|
17
|
-
/// Android 13+ Advanced Features
|
|
18
|
-
|
|
19
|
-
// MARK: - Jetpack Compose Integration
|
|
20
|
-
|
|
21
|
-
@Composable
|
|
22
|
-
fun CraftComposeApp(content: @Composable () -> Unit) {
|
|
23
|
-
MaterialTheme(
|
|
24
|
-
colorScheme = dynamicColorScheme(),
|
|
25
|
-
typography = Typography(),
|
|
26
|
-
content = content
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@Composable
|
|
31
|
-
fun dynamicColorScheme(): ColorScheme {
|
|
32
|
-
return if (DynamicColors.isDynamicColorAvailable()) {
|
|
33
|
-
dynamicDarkColorScheme()
|
|
34
|
-
} else {
|
|
35
|
-
darkColorScheme()
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@Composable
|
|
40
|
-
fun CraftWebViewComposable(
|
|
41
|
-
url: String,
|
|
42
|
-
modifier: Modifier = Modifier
|
|
43
|
-
) {
|
|
44
|
-
AndroidView(
|
|
45
|
-
factory = { context ->
|
|
46
|
-
android.webkit.WebView(context).apply {
|
|
47
|
-
settings.javaScriptEnabled = true
|
|
48
|
-
loadUrl(url)
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
modifier = modifier.fillMaxSize()
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// MARK: - Material You Dynamic Colors
|
|
56
|
-
|
|
57
|
-
class DynamicColorManager(private val activity: Activity) {
|
|
58
|
-
|
|
59
|
-
fun applyDynamicColors() {
|
|
60
|
-
if (DynamicColors.isDynamicColorAvailable()) {
|
|
61
|
-
DynamicColors.applyToActivityIfAvailable(activity)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
fun isDynamicColorAvailable(): Boolean {
|
|
66
|
-
return DynamicColors.isDynamicColorAvailable()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// MARK: - Predictive Back Gesture (Android 13+)
|
|
71
|
-
|
|
72
|
-
class PredictiveBackHandler(private val activity: Activity) {
|
|
73
|
-
|
|
74
|
-
fun enablePredictiveBack() {
|
|
75
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
76
|
-
activity.onBackPressedDispatcher.addCallback(activity, object : androidx.activity.OnBackPressedCallback(true) {
|
|
77
|
-
override fun handleOnBackPressed() {
|
|
78
|
-
// Handle predictive back gesture
|
|
79
|
-
// Can animate the exit transition
|
|
80
|
-
isEnabled = false
|
|
81
|
-
activity.onBackPressedDispatcher.onBackPressed()
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// MARK: - Per-App Language Preferences (Android 13+)
|
|
89
|
-
|
|
90
|
-
class LanguageManager(private val context: Context) {
|
|
91
|
-
|
|
92
|
-
fun setAppLanguage(languageCode: String) {
|
|
93
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
94
|
-
val localeList = android.os.LocaleList(java.util.Locale.forLanguageTag(languageCode))
|
|
95
|
-
context.getSystemService(android.app.LocaleManager::class.java)
|
|
96
|
-
?.applicationLocales = localeList
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
fun getAppLanguage(): String? {
|
|
101
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
102
|
-
val locales = context.getSystemService(android.app.LocaleManager::class.java)
|
|
103
|
-
?.applicationLocales
|
|
104
|
-
return locales?.get(0)?.toLanguageTag()
|
|
105
|
-
}
|
|
106
|
-
return null
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// MARK: - Photo Picker (Android 13+)
|
|
111
|
-
|
|
112
|
-
class PhotoPickerManager(private val activity: Activity) {
|
|
113
|
-
|
|
114
|
-
fun launchPhotoPicker(maxItems: Int = 1, callback: (List<android.net.Uri>) -> Unit) {
|
|
115
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
116
|
-
val intent = android.content.Intent(android.provider.MediaStore.ACTION_PICK_IMAGES).apply {
|
|
117
|
-
putExtra(android.provider.MediaStore.EXTRA_PICK_IMAGES_MAX, maxItems)
|
|
118
|
-
}
|
|
119
|
-
// Launch intent and handle result
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// MARK: - Notification Permission (Android 13+)
|
|
125
|
-
|
|
126
|
-
class NotificationPermissionManager(private val activity: Activity) {
|
|
127
|
-
|
|
128
|
-
fun requestNotificationPermission(callback: (Boolean) -> Unit) {
|
|
129
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
130
|
-
if (androidx.core.app.ActivityCompat.checkSelfPermission(
|
|
131
|
-
activity,
|
|
132
|
-
android.Manifest.permission.POST_NOTIFICATIONS
|
|
133
|
-
) != android.content.pm.PackageManager.PERMISSION_GRANTED
|
|
134
|
-
) {
|
|
135
|
-
androidx.core.app.ActivityCompat.requestPermissions(
|
|
136
|
-
activity,
|
|
137
|
-
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),
|
|
138
|
-
100
|
|
139
|
-
)
|
|
140
|
-
} else {
|
|
141
|
-
callback(true)
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
callback(true)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
fun hasNotificationPermission(): Boolean {
|
|
149
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
150
|
-
return androidx.core.app.ActivityCompat.checkSelfPermission(
|
|
151
|
-
activity,
|
|
152
|
-
android.Manifest.permission.POST_NOTIFICATIONS
|
|
153
|
-
) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
|
154
|
-
}
|
|
155
|
-
return true
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// MARK: - Foreground Services
|
|
160
|
-
|
|
161
|
-
class ForegroundServiceManager(private val context: Context) {
|
|
162
|
-
|
|
163
|
-
fun startForegroundService(
|
|
164
|
-
serviceClass: Class<*>,
|
|
165
|
-
notificationTitle: String,
|
|
166
|
-
notificationText: String
|
|
167
|
-
) {
|
|
168
|
-
val intent = android.content.Intent(context, serviceClass)
|
|
169
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
170
|
-
context.startForegroundService(intent)
|
|
171
|
-
} else {
|
|
172
|
-
context.startService(intent)
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
fun stopForegroundService(serviceClass: Class<*>) {
|
|
177
|
-
val intent = android.content.Intent(context, serviceClass)
|
|
178
|
-
context.stopService(intent)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// MARK: - WorkManager for Background Tasks
|
|
183
|
-
|
|
184
|
-
class BackgroundTaskManager(private val context: Context) {
|
|
185
|
-
|
|
186
|
-
fun scheduleOneTimeWork(
|
|
187
|
-
tag: String,
|
|
188
|
-
initialDelay: Long = 0,
|
|
189
|
-
requiresCharging: Boolean = false,
|
|
190
|
-
requiresWifi: Boolean = false
|
|
191
|
-
) {
|
|
192
|
-
val constraints = Constraints.Builder()
|
|
193
|
-
.setRequiresCharging(requiresCharging)
|
|
194
|
-
.setRequiredNetworkType(if (requiresWifi) NetworkType.UNMETERED else NetworkType.CONNECTED)
|
|
195
|
-
.build()
|
|
196
|
-
|
|
197
|
-
val workRequest = OneTimeWorkRequestBuilder<CraftWorker>()
|
|
198
|
-
.setConstraints(constraints)
|
|
199
|
-
.setInitialDelay(initialDelay, TimeUnit.MILLISECONDS)
|
|
200
|
-
.addTag(tag)
|
|
201
|
-
.build()
|
|
202
|
-
|
|
203
|
-
WorkManager.getInstance(context).enqueue(workRequest)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
fun schedulePeriodicWork(
|
|
207
|
-
tag: String,
|
|
208
|
-
intervalMinutes: Long,
|
|
209
|
-
requiresCharging: Boolean = false
|
|
210
|
-
) {
|
|
211
|
-
val constraints = Constraints.Builder()
|
|
212
|
-
.setRequiresCharging(requiresCharging)
|
|
213
|
-
.build()
|
|
214
|
-
|
|
215
|
-
val workRequest = PeriodicWorkRequestBuilder<CraftWorker>(
|
|
216
|
-
intervalMinutes, TimeUnit.MINUTES
|
|
217
|
-
)
|
|
218
|
-
.setConstraints(constraints)
|
|
219
|
-
.addTag(tag)
|
|
220
|
-
.build()
|
|
221
|
-
|
|
222
|
-
WorkManager.getInstance(context).enqueue(workRequest)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
fun cancelWork(tag: String) {
|
|
226
|
-
WorkManager.getInstance(context).cancelAllWorkByTag(tag)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
class CraftWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
|
|
230
|
-
override fun doWork(): Result {
|
|
231
|
-
// Perform background task
|
|
232
|
-
return Result.success()
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// MARK: - Firebase Integration
|
|
238
|
-
|
|
239
|
-
class FirebaseManager(private val context: Context) {
|
|
240
|
-
|
|
241
|
-
private val analytics: FirebaseAnalytics by lazy {
|
|
242
|
-
FirebaseAnalytics.getInstance(context)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private val crashlytics: FirebaseCrashlytics by lazy {
|
|
246
|
-
FirebaseCrashlytics.getInstance()
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
private val remoteConfig: FirebaseRemoteConfig by lazy {
|
|
250
|
-
FirebaseRemoteConfig.getInstance()
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Analytics
|
|
254
|
-
fun logEvent(eventName: String, params: Map<String, Any>) {
|
|
255
|
-
val bundle = android.os.Bundle().apply {
|
|
256
|
-
params.forEach { (key, value) ->
|
|
257
|
-
when (value) {
|
|
258
|
-
is String -> putString(key, value)
|
|
259
|
-
is Int -> putInt(key, value)
|
|
260
|
-
is Long -> putLong(key, value)
|
|
261
|
-
is Double -> putDouble(key, value)
|
|
262
|
-
is Boolean -> putBoolean(key, value)
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
analytics.logEvent(eventName, bundle)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
fun setUserProperty(name: String, value: String) {
|
|
270
|
-
analytics.setUserProperty(name, value)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Crashlytics
|
|
274
|
-
fun logCrash(message: String) {
|
|
275
|
-
crashlytics.log(message)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
fun recordException(throwable: Throwable) {
|
|
279
|
-
crashlytics.recordException(throwable)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
fun setUserId(userId: String) {
|
|
283
|
-
crashlytics.setUserId(userId)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Remote Config
|
|
287
|
-
fun fetchRemoteConfig(callback: (Boolean) -> Unit) {
|
|
288
|
-
remoteConfig.fetchAndActivate()
|
|
289
|
-
.addOnCompleteListener { task ->
|
|
290
|
-
callback(task.isSuccessful)
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
fun getString(key: String): String {
|
|
295
|
-
return remoteConfig.getString(key)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
fun getBoolean(key: String): Boolean {
|
|
299
|
-
return remoteConfig.getBoolean(key)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
fun getLong(key: String): Long {
|
|
303
|
-
return remoteConfig.getLong(key)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// FCM
|
|
307
|
-
fun getFirebaseToken(callback: (String?) -> Unit) {
|
|
308
|
-
FirebaseMessaging.getInstance().token
|
|
309
|
-
.addOnCompleteListener { task ->
|
|
310
|
-
if (task.isSuccessful) {
|
|
311
|
-
callback(task.result)
|
|
312
|
-
} else {
|
|
313
|
-
callback(null)
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
fun subscribeToTopic(topic: String) {
|
|
319
|
-
FirebaseMessaging.getInstance().subscribeToTopic(topic)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
fun unsubscribeFromTopic(topic: String) {
|
|
323
|
-
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic)
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// MARK: - Bottom Sheet
|
|
328
|
-
|
|
329
|
-
@OptIn(ExperimentalMaterial3Api::class)
|
|
330
|
-
@Composable
|
|
331
|
-
fun CraftBottomSheet(
|
|
332
|
-
sheetContent: @Composable ColumnScope.() -> Unit,
|
|
333
|
-
content: @Composable () -> Unit
|
|
334
|
-
) {
|
|
335
|
-
val sheetState = rememberModalBottomSheetState()
|
|
336
|
-
var showBottomSheet by remember { mutableStateOf(false) }
|
|
337
|
-
|
|
338
|
-
if (showBottomSheet) {
|
|
339
|
-
ModalBottomSheet(
|
|
340
|
-
onDismissRequest = { showBottomSheet = false },
|
|
341
|
-
sheetState = sheetState
|
|
342
|
-
) {
|
|
343
|
-
sheetContent()
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
content()
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// MARK: - Navigation Drawer
|
|
351
|
-
|
|
352
|
-
@Composable
|
|
353
|
-
fun CraftNavigationDrawer(
|
|
354
|
-
drawerContent: @Composable ColumnScope.() -> Unit,
|
|
355
|
-
content: @Composable () -> Unit
|
|
356
|
-
) {
|
|
357
|
-
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
|
358
|
-
val scope = rememberCoroutineScope()
|
|
359
|
-
|
|
360
|
-
ModalNavigationDrawer(
|
|
361
|
-
drawerState = drawerState,
|
|
362
|
-
drawerContent = {
|
|
363
|
-
ModalDrawerSheet {
|
|
364
|
-
drawerContent()
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
) {
|
|
368
|
-
content()
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// MARK: - Bridge Integration
|
|
373
|
-
|
|
374
|
-
fun CraftBridge.initializeAdvancedFeatures() {
|
|
375
|
-
// Initialize all advanced Android features
|
|
376
|
-
DynamicColorManager(activity).applyDynamicColors()
|
|
377
|
-
PredictiveBackHandler(activity).enablePredictiveBack()
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
fun CraftBridge.setupFirebase() {
|
|
381
|
-
// Setup Firebase services
|
|
382
|
-
// Called from MainActivity onCreate
|
|
383
|
-
}
|