diff --git a/app/src/main/kotlin/net/primal/android/auth/login/LoginScreen.kt b/app/src/main/kotlin/net/primal/android/auth/login/LoginScreen.kt index f326066a..63654f15 100644 --- a/app/src/main/kotlin/net/primal/android/auth/login/LoginScreen.kt +++ b/app/src/main/kotlin/net/primal/android/auth/login/LoginScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults @@ -62,6 +63,7 @@ import net.primal.android.core.compose.detectUiDensityModeFromMaxHeight import net.primal.android.core.compose.foundation.keyboardVisibilityAsState import net.primal.android.core.compose.icons.PrimalIcons import net.primal.android.core.compose.icons.primaliconpack.ArrowBack +import net.primal.android.core.compose.icons.primaliconpack.AvatarDefault import net.primal.android.core.compose.isCompactOrLower import net.primal.android.core.utils.isValidNostrPrivateKey import net.primal.android.core.utils.isValidNostrPublicKey @@ -75,6 +77,7 @@ fun LoginScreen( onClose: () -> Unit, onLoginSuccess: (String) -> Unit, ) { + val keyboardController = LocalSoftwareKeyboardController.current LaunchedEffect(viewModel, onLoginSuccess) { viewModel.effect.collect { when (it) { @@ -89,7 +92,10 @@ fun LoginScreen( LoginScreen( state = uiState.value, eventPublisher = { viewModel.setEvent(it) }, - onClose = onClose, + onClose = { + keyboardController?.hide() + onClose() + }, ) } @@ -202,8 +208,10 @@ fun LoginContent( AvatarThumbnail( avatarCdnImage = profileDetails.avatarCdnImage, avatarSize = 100.dp, - hasBorder = true, + hasBorder = profileDetails.avatarCdnImage != null, borderColor = Color.White, + backgroundColor = defaultAvatarBackground, + defaultAvatar = { DefaultAvatar() }, ) Spacer(modifier = Modifier.height(16.dp)) @@ -373,6 +381,26 @@ fun LoginContent( } } +private val defaultAvatarBackground = Color(0xFF7E382C) +private val defaultAvatarForeground = Color(0xFFFDB7AB) + +@Composable +private fun DefaultAvatar() { + Box( + modifier = Modifier + .background(color = defaultAvatarBackground) + .fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = PrimalIcons.AvatarDefault, + contentDescription = null, + modifier = Modifier.fillMaxSize(), + tint = defaultAvatarForeground, + ) + } +} + @Composable fun LaunchedErrorHandler(viewModel: LoginViewModel) { val genericMessage = stringResource(id = R.string.app_generic_error) diff --git a/app/src/main/kotlin/net/primal/android/core/compose/AvatarThumbnailListItemImage.kt b/app/src/main/kotlin/net/primal/android/core/compose/AvatarThumbnailListItemImage.kt index 443309d1..d1703c43 100644 --- a/app/src/main/kotlin/net/primal/android/core/compose/AvatarThumbnailListItemImage.kt +++ b/app/src/main/kotlin/net/primal/android/core/compose/AvatarThumbnailListItemImage.kt @@ -32,7 +32,9 @@ fun AvatarThumbnail( avatarSize: Dp = 48.dp, hasBorder: Boolean = false, borderColor: Color = AppTheme.colorScheme.primary, + backgroundColor: Color = AppTheme.extraColorScheme.surfaceVariantAlt1, onClick: (() -> Unit)? = null, + defaultAvatar: @Composable () -> Unit = { DefaultAvatarThumbnailPlaceholderListItemImage() }, ) { val variant = avatarCdnImage?.variants?.minByOrNull { it.width } val imageSource = variant?.mediaUrl ?: avatarCdnImage?.sourceUrl @@ -42,7 +44,9 @@ fun AvatarThumbnail( source = imageSource, hasBorder = hasBorder, borderColor = borderColor, + backgroundColor = backgroundColor, onClick = onClick, + defaultAvatar = defaultAvatar, ) } @@ -53,7 +57,9 @@ private fun AvatarThumbnailListItemImage( avatarSize: Dp = 48.dp, hasBorder: Boolean = false, borderColor: Color = AppTheme.colorScheme.primary, + backgroundColor: Color = AppTheme.extraColorScheme.surfaceVariantAlt1, onClick: (() -> Unit)? = null, + defaultAvatar: @Composable () -> Unit, ) { SubcomposeAsyncImage( model = source, @@ -70,10 +76,10 @@ private fun AvatarThumbnailListItemImage( Box( modifier = Modifier .fillMaxSize() - .background(color = AppTheme.extraColorScheme.surfaceVariantAlt1), + .background(color = backgroundColor), ) }, - error = { DefaultAvatarThumbnailPlaceholderListItemImage() }, + error = { defaultAvatar() }, ) } diff --git a/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt b/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt index 25c25c3d..96f44992 100644 --- a/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt +++ b/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt @@ -78,7 +78,6 @@ import net.primal.android.theme.PrimalTheme import net.primal.android.theme.domain.PrimalTheme import net.primal.android.thread.ThreadScreen import net.primal.android.thread.ThreadViewModel -import timber.log.Timber private fun NavController.navigateToWelcome() = navigate( @@ -428,14 +427,18 @@ private fun NavGraphBuilder.welcome(route: String, navController: NavController) composable( route = route, enterTransition = { - Timber.e("Enter initialState = ${this.initialState.destination}") - Timber.e("Enter targetState = ${this.targetState.destination}") - slideInHorizontally(initialOffsetX = { -it }) + if (initialState.destination.route in listOf("login", "create_account")) { + slideInHorizontally(initialOffsetX = { -it }) + } else { + null + } }, exitTransition = { - Timber.e("Exit initialState = ${this.initialState.destination}") - Timber.e("Exit targetState = ${this.targetState.destination}") - slideOutHorizontally(targetOffsetX = { -it }) + if (targetState.destination.route in listOf("login", "create_account")) { + slideOutHorizontally(targetOffsetX = { -it }) + } else { + null + } }, ) { LockToOrientationPortrait() @@ -453,14 +456,18 @@ private fun NavGraphBuilder.login(route: String, navController: NavController) = composable( route = route, enterTransition = { - Timber.e("Enter initialState = ${this.initialState.destination}") - Timber.e("Enter targetState = ${this.targetState.destination}") - slideInHorizontally(initialOffsetX = { it }) + if (initialState.destination.route == "welcome") { + slideInHorizontally(initialOffsetX = { it }) + } else { + null + } }, exitTransition = { - Timber.e("Exit initialState = ${this.initialState.destination}") - Timber.e("Exit targetState = ${this.targetState.destination}") - slideOutHorizontally(targetOffsetX = { it }) + if (targetState.destination.route == "welcome") { + slideOutHorizontally(targetOffsetX = { it }) + } else { + null + } }, ) { val viewModel: LoginViewModel = hiltViewModel(it) @@ -478,8 +485,20 @@ private fun NavGraphBuilder.login(route: String, navController: NavController) = private fun NavGraphBuilder.createAccount(route: String, navController: NavController) = composable( route = route, - enterTransition = { slideInHorizontally(initialOffsetX = { it }) }, - exitTransition = { slideOutHorizontally(targetOffsetX = { it }) }, + enterTransition = { + if (initialState.destination.route == "welcome") { + slideInHorizontally(initialOffsetX = { it }) + } else { + null + } + }, + exitTransition = { + if (targetState.destination.route == "welcome") { + slideOutHorizontally(targetOffsetX = { it }) + } else { + null + } + }, ) { val viewModel: CreateAccountViewModel = hiltViewModel(it) PrimalTheme(PrimalTheme.Sunset) { @@ -502,8 +521,8 @@ private fun NavGraphBuilder.feed( arguments = arguments, ) { navBackEntry -> val viewModel = hiltViewModel(navBackEntry) - AdjustSystemColors(primalTheme = LocalPrimalTheme.current) LockToOrientationPortrait() + AdjustSystemColors(primalTheme = LocalPrimalTheme.current) FeedScreen( viewModel = viewModel, onFeedsClick = { navController.navigateToFeedList() },