Rebrand from MyCrib to Casera
- Rename Kotlin package from com.example.mycrib to com.example.casera - Update Android app name, namespace, and application ID - Update iOS bundle identifiers and project settings - Rename iOS directories (MyCribTests -> CaseraTests, etc.) - Update deep link schemes from mycrib:// to casera:// - Update app group identifiers - Update subscription product IDs - Update all UI strings and branding 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
package com.example.casera
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import coil3.ImageLoader
|
||||
import coil3.PlatformContext
|
||||
import coil3.SingletonImageLoader
|
||||
import coil3.network.ktor3.KtorNetworkFetcherFactory
|
||||
import coil3.disk.DiskCache
|
||||
import coil3.memory.MemoryCache
|
||||
import coil3.request.crossfade
|
||||
import coil3.util.DebugLogger
|
||||
import okio.FileSystem
|
||||
import com.example.casera.storage.TokenManager
|
||||
import com.example.casera.storage.TokenStorage
|
||||
import com.example.casera.storage.TaskCacheManager
|
||||
import com.example.casera.storage.TaskCacheStorage
|
||||
import com.example.casera.storage.ThemeStorage
|
||||
import com.example.casera.storage.ThemeStorageManager
|
||||
import com.example.casera.ui.theme.ThemeManager
|
||||
import com.example.casera.fcm.FCMManager
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainActivity : ComponentActivity(), SingletonImageLoader.Factory {
|
||||
private var deepLinkResetToken by mutableStateOf<String?>(null)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Initialize TokenStorage with Android TokenManager
|
||||
TokenStorage.initialize(TokenManager.getInstance(applicationContext))
|
||||
|
||||
// Initialize TaskCacheStorage for offline task caching
|
||||
TaskCacheStorage.initialize(TaskCacheManager.getInstance(applicationContext))
|
||||
|
||||
// Initialize ThemeStorage and ThemeManager
|
||||
ThemeStorage.initialize(ThemeStorageManager.getInstance(applicationContext))
|
||||
ThemeManager.initialize()
|
||||
|
||||
// Handle deep link from intent
|
||||
handleDeepLink(intent)
|
||||
|
||||
// Request notification permission and setup FCM
|
||||
setupFCM()
|
||||
|
||||
setContent {
|
||||
App(
|
||||
deepLinkResetToken = deepLinkResetToken,
|
||||
onClearDeepLinkToken = {
|
||||
deepLinkResetToken = null
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupFCM() {
|
||||
// Request notification permission if needed
|
||||
if (!FCMManager.isNotificationPermissionGranted(this)) {
|
||||
FCMManager.requestNotificationPermission(this)
|
||||
}
|
||||
|
||||
// Get FCM token and register with backend
|
||||
lifecycleScope.launch {
|
||||
val fcmToken = FCMManager.getFCMToken()
|
||||
if (fcmToken != null) {
|
||||
Log.d("MainActivity", "FCM Token: $fcmToken")
|
||||
registerDeviceWithBackend(fcmToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun registerDeviceWithBackend(fcmToken: String) {
|
||||
try {
|
||||
val authToken = TokenStorage.getToken()
|
||||
if (authToken != null) {
|
||||
val notificationApi = com.example.casera.network.NotificationApi()
|
||||
val request = com.example.casera.models.DeviceRegistrationRequest(
|
||||
registrationId = fcmToken,
|
||||
platform = "android"
|
||||
)
|
||||
|
||||
when (val result = notificationApi.registerDevice(authToken, request)) {
|
||||
is com.example.casera.network.ApiResult.Success -> {
|
||||
Log.d("MainActivity", "Device registered successfully: ${result.data}")
|
||||
}
|
||||
is com.example.casera.network.ApiResult.Error -> {
|
||||
Log.e("MainActivity", "Failed to register device: ${result.message}")
|
||||
}
|
||||
is com.example.casera.network.ApiResult.Loading,
|
||||
is com.example.casera.network.ApiResult.Idle -> {
|
||||
// These states shouldn't occur for direct API calls
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.d("MainActivity", "No auth token available, will register device after login")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainActivity", "Error registering device", e)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
when (requestCode) {
|
||||
FCMManager.NOTIFICATION_PERMISSION_REQUEST_CODE -> {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d("MainActivity", "Notification permission granted")
|
||||
// Get FCM token now that permission is granted
|
||||
lifecycleScope.launch {
|
||||
FCMManager.getFCMToken()
|
||||
}
|
||||
} else {
|
||||
Log.d("MainActivity", "Notification permission denied")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
handleDeepLink(intent)
|
||||
}
|
||||
|
||||
private fun handleDeepLink(intent: Intent?) {
|
||||
val data: Uri? = intent?.data
|
||||
if (data != null && data.scheme == "mycrib" && data.host == "reset-password") {
|
||||
// Extract token from query parameter
|
||||
val token = data.getQueryParameter("token")
|
||||
if (token != null) {
|
||||
deepLinkResetToken = token
|
||||
println("Deep link received with token: $token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newImageLoader(context: PlatformContext): ImageLoader {
|
||||
return ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(KtorNetworkFetcherFactory())
|
||||
}
|
||||
.memoryCache {
|
||||
MemoryCache.Builder()
|
||||
.maxSizePercent(context, 0.25)
|
||||
.build()
|
||||
}
|
||||
.diskCache {
|
||||
DiskCache.Builder()
|
||||
.directory(FileSystem.SYSTEM_TEMPORARY_DIRECTORY / "image_cache")
|
||||
.maxSizeBytes(512L * 1024 * 1024) // 512MB
|
||||
.build()
|
||||
}
|
||||
.crossfade(true)
|
||||
.logger(DebugLogger())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AppAndroidPreview() {
|
||||
App(deepLinkResetToken = null)
|
||||
}
|
||||
Reference in New Issue
Block a user