Files
mobile-android/app/src/main/java/com/rosetta/messenger/MainActivity.kt

250 lines
11 KiB
Kotlin

package com.rosetta.messenger
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.rosetta.messenger.data.AccountManager
import com.rosetta.messenger.data.DecryptedAccount
import com.rosetta.messenger.data.PreferencesManager
import com.rosetta.messenger.ui.auth.AccountInfo
import com.rosetta.messenger.ui.auth.AuthFlow
import com.rosetta.messenger.ui.chats.ChatsListScreen
import com.rosetta.messenger.ui.onboarding.OnboardingScreen
import com.rosetta.messenger.ui.splash.SplashScreen
import com.rosetta.messenger.ui.theme.RosettaAndroidTheme
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private lateinit var preferencesManager: PreferencesManager
private lateinit var accountManager: AccountManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
preferencesManager = PreferencesManager(this)
accountManager = AccountManager(this)
setContent {
val scope = rememberCoroutineScope()
val isDarkTheme by preferencesManager.isDarkTheme.collectAsState(initial = true)
val isLoggedIn by accountManager.isLoggedIn.collectAsState(initial = null)
var showSplash by remember { mutableStateOf(true) }
var showOnboarding by remember { mutableStateOf(true) }
var hasExistingAccount by remember { mutableStateOf<Boolean?>(null) }
var currentAccount by remember { mutableStateOf<DecryptedAccount?>(null) }
var accountInfoList by remember { mutableStateOf<List<AccountInfo>>(emptyList()) }
// Check for existing accounts and build AccountInfo list
// Also force logout so user always sees unlock screen on app restart
LaunchedEffect(Unit) {
accountManager.logout() // Always start logged out
val accounts = accountManager.getAllAccounts()
hasExistingAccount = accounts.isNotEmpty()
accountInfoList = accounts.map { account ->
val shortKey = account.publicKey.take(7)
val displayName = account.name ?: shortKey
val initials = displayName.trim().split(Regex("\\s+"))
.filter { it.isNotEmpty() }
.let { words ->
when {
words.isEmpty() -> "??"
words.size == 1 -> words[0].take(2).uppercase()
else -> "${words[0].first()}${words[1].first()}".uppercase()
}
}
AccountInfo(
id = account.publicKey,
name = displayName,
initials = initials,
publicKey = account.publicKey
)
}
}
// Wait for initial load
if (hasExistingAccount == null) {
Box(
modifier = Modifier
.fillMaxSize()
.background(if (isDarkTheme) Color(0xFF1B1B1B) else Color.White)
)
return@setContent
}
RosettaAndroidTheme(
darkTheme = isDarkTheme,
animated = true
) {
Surface(
modifier = Modifier.fillMaxSize(),
color = if (isDarkTheme) Color(0xFF1B1B1B) else Color.White
) {
AnimatedContent(
targetState = when {
showSplash -> "splash"
showOnboarding && hasExistingAccount == false -> "onboarding"
isLoggedIn != true && hasExistingAccount == false -> "auth_new"
isLoggedIn != true && hasExistingAccount == true -> "auth_unlock"
else -> "main"
},
transitionSpec = {
fadeIn(animationSpec = tween(600)) togetherWith
fadeOut(animationSpec = tween(600))
},
label = "screenTransition"
) { screen ->
when (screen) {
"splash" -> {
SplashScreen(
isDarkTheme = isDarkTheme,
onSplashComplete = { showSplash = false }
)
}
"onboarding" -> {
OnboardingScreen(
isDarkTheme = isDarkTheme,
onThemeToggle = {
scope.launch {
preferencesManager.setDarkTheme(!isDarkTheme)
}
},
onStartMessaging = {
showOnboarding = false
}
)
}
"auth_new", "auth_new", "auth_unlock" -> {
AuthFlow(
isDarkTheme = isDarkTheme,
hasExistingAccount = screen == "auth_unlock",
accounts = accountInfoList,
onAuthComplete = { account ->
currentAccount = account
hasExistingAccount = true
// Reload accounts list
scope.launch {
val accounts = accountManager.getAllAccounts()
accountInfoList = accounts.map { acc ->
val shortKey = acc.publicKey.take(7)
val displayName = acc.name ?: shortKey
val initials = displayName.trim().split(Regex("\\s+"))
.filter { it.isNotEmpty() }
.let { words ->
when {
words.isEmpty() -> "??"
words.size == 1 -> words[0].take(2).uppercase()
else -> "${words[0].first()}${words[1].first()}".uppercase()
}
}
AccountInfo(
id = acc.publicKey,
name = displayName,
initials = initials,
publicKey = acc.publicKey
)
}
}
},
onLogout = {
scope.launch {
com.rosetta.messenger.network.ProtocolManager.disconnect()
accountManager.logout()
currentAccount = null
}
}
)
}
"main" -> {
MainScreen(
account = currentAccount,
isDarkTheme = isDarkTheme,
onToggleTheme = {
scope.launch {
preferencesManager.setDarkTheme(!isDarkTheme)
}
},
onLogout = {
scope.launch {
com.rosetta.messenger.network.ProtocolManager.disconnect()
accountManager.logout()
currentAccount = null
}
}
)
}
}
}
}
}
}
}
}
@Composable
fun MainScreen(
account: DecryptedAccount? = null,
isDarkTheme: Boolean = true,
onToggleTheme: () -> Unit = {},
onLogout: () -> Unit = {}
) {
val accountName = account?.publicKey ?: "04c266b98ae5"
val accountPhone = account?.publicKey?.take(16)?.let {
"+${it.take(1)} ${it.substring(1, 4)} ${it.substring(4, 7)}${it.substring(7)}"
} ?: "+7 775 9932587"
val accountPublicKey = account?.publicKey ?: "04c266b98ae5"
ChatsListScreen(
isDarkTheme = isDarkTheme,
accountName = accountName,
accountPhone = accountPhone,
accountPublicKey = accountPublicKey,
onToggleTheme = onToggleTheme,
onProfileClick = {
// TODO: Navigate to profile
},
onNewGroupClick = {
// TODO: Navigate to new group
},
onContactsClick = {
// TODO: Navigate to contacts
},
onCallsClick = {
// TODO: Navigate to calls
},
onSavedMessagesClick = {
// TODO: Navigate to saved messages
},
onSettingsClick = {
// TODO: Navigate to settings
},
onInviteFriendsClick = {
// TODO: Share invite link
},
onSearchClick = {
// TODO: Show search
},
onNewChat = {
// TODO: Show new chat screen
},
onLogout = onLogout
)
}