forked from melod1n/fast-messenger
improve visuals for Logo & Login screens for compact devices
This commit is contained in:
@@ -181,4 +181,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation(libs.androidx.navigation.compose)
|
implementation(libs.androidx.navigation.compose)
|
||||||
implementation(libs.kotlin.serialization)
|
implementation(libs.kotlin.serialization)
|
||||||
|
|
||||||
|
implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-beta04")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.activity.compose.setContent
|
|||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -28,6 +29,7 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import androidx.window.core.layout.WindowWidthSizeClass
|
||||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.rememberPermissionState
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import com.meloda.app.fast.MainViewModel
|
import com.meloda.app.fast.MainViewModel
|
||||||
@@ -57,7 +59,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||||
val systemBarStyle = when (currentNightMode) {
|
val systemBarStyle = when (currentNightMode) {
|
||||||
Configuration.UI_MODE_NIGHT_NO -> SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb())
|
Configuration.UI_MODE_NIGHT_NO -> SystemBarStyle.light(
|
||||||
|
Color.Transparent.toArgb(),
|
||||||
|
Color.Transparent.toArgb()
|
||||||
|
)
|
||||||
|
|
||||||
Configuration.UI_MODE_NIGHT_YES -> SystemBarStyle.dark(Color.Transparent.toArgb())
|
Configuration.UI_MODE_NIGHT_YES -> SystemBarStyle.dark(Color.Transparent.toArgb())
|
||||||
else -> error("Illegal State, current mode is $currentNightMode")
|
else -> error("Illegal State, current mode is $currentNightMode")
|
||||||
}
|
}
|
||||||
@@ -104,6 +110,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val windowAdaptiveInfo = currentWindowAdaptiveInfo()
|
||||||
|
|
||||||
|
val isDeviceCompact by remember(windowAdaptiveInfo) {
|
||||||
|
derivedStateOf {
|
||||||
|
windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val theme by userSettings.theme.collectAsStateWithLifecycle()
|
val theme by userSettings.theme.collectAsStateWithLifecycle()
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalTheme provides ThemeConfig(
|
LocalTheme provides ThemeConfig(
|
||||||
@@ -112,7 +126,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
selectedColorScheme = theme.selectedColorScheme,
|
selectedColorScheme = theme.selectedColorScheme,
|
||||||
usingAmoledBackground = theme.usingAmoledBackground,
|
usingAmoledBackground = theme.usingAmoledBackground,
|
||||||
usingBlur = theme.usingBlur,
|
usingBlur = theme.usingBlur,
|
||||||
multiline = theme.multiline
|
multiline = theme.multiline,
|
||||||
|
isDeviceCompact = isDeviceCompact
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalTheme.current
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ class UserSettingsImpl(
|
|||||||
selectedColorScheme = selectedColorScheme(),
|
selectedColorScheme = selectedColorScheme(),
|
||||||
usingAmoledBackground = isUsingAmoledBackground(),
|
usingAmoledBackground = isUsingAmoledBackground(),
|
||||||
usingBlur = isUsingBlur(),
|
usingBlur = isUsingBlur(),
|
||||||
multiline = isMultiline()
|
multiline = isMultiline(),
|
||||||
|
isDeviceCompact = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ data class ThemeConfig(
|
|||||||
val usingAmoledBackground: Boolean,
|
val usingAmoledBackground: Boolean,
|
||||||
val usingBlur: Boolean,
|
val usingBlur: Boolean,
|
||||||
val multiline: Boolean,
|
val multiline: Boolean,
|
||||||
val bubblesWithPinch: Boolean = true
|
val isDeviceCompact: Boolean
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ val LocalTheme = compositionLocalOf {
|
|||||||
selectedColorScheme = 0,
|
selectedColorScheme = 0,
|
||||||
usingAmoledBackground = false,
|
usingAmoledBackground = false,
|
||||||
usingBlur = false,
|
usingBlur = false,
|
||||||
multiline = false
|
multiline = false,
|
||||||
|
isDeviceCompact = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-13
@@ -6,11 +6,13 @@ import androidx.compose.animation.fadeOut
|
|||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.ime
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.union
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
@@ -20,6 +22,7 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.ScaffoldDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -48,6 +51,7 @@ import androidx.compose.ui.text.input.VisualTransformation
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.UiText
|
||||||
|
import com.meloda.app.fast.designsystem.LocalTheme
|
||||||
import com.meloda.app.fast.designsystem.MaterialDialog
|
import com.meloda.app.fast.designsystem.MaterialDialog
|
||||||
import com.meloda.app.fast.designsystem.TextFieldErrorText
|
import com.meloda.app.fast.designsystem.TextFieldErrorText
|
||||||
import com.meloda.app.fast.designsystem.autoFillRequestHandler
|
import com.meloda.app.fast.designsystem.autoFillRequestHandler
|
||||||
@@ -60,8 +64,8 @@ import com.meloda.fast.auth.login.LoginViewModelImpl
|
|||||||
import com.meloda.fast.auth.login.model.CaptchaArguments
|
import com.meloda.fast.auth.login.model.CaptchaArguments
|
||||||
import com.meloda.fast.auth.login.model.LoginError
|
import com.meloda.fast.auth.login.model.LoginError
|
||||||
import com.meloda.fast.auth.login.model.LoginScreenState
|
import com.meloda.fast.auth.login.model.LoginScreenState
|
||||||
import com.meloda.fast.auth.login.model.LoginValidationArguments
|
|
||||||
import com.meloda.fast.auth.login.model.LoginUserBannedArguments
|
import com.meloda.fast.auth.login.model.LoginUserBannedArguments
|
||||||
|
import com.meloda.fast.auth.login.model.LoginValidationArguments
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
import com.meloda.app.fast.designsystem.R as UiR
|
import com.meloda.app.fast.designsystem.R as UiR
|
||||||
|
|
||||||
@@ -153,6 +157,7 @@ fun LoginScreen(
|
|||||||
onPasswordFieldGoAction: () -> Unit = {},
|
onPasswordFieldGoAction: () -> Unit = {},
|
||||||
onSignInButtonClicked: () -> Unit = {}
|
onSignInButtonClicked: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
val currentTheme = LocalTheme.current
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val (loginFocusable, passwordFocusable) = FocusRequester.createRefs()
|
val (loginFocusable, passwordFocusable) = FocusRequester.createRefs()
|
||||||
|
|
||||||
@@ -181,17 +186,34 @@ fun LoginScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Scaffold { padding ->
|
val titleStyle = if (currentTheme.isDeviceCompact) {
|
||||||
|
MaterialTheme.typography.displaySmall
|
||||||
|
} else {
|
||||||
|
MaterialTheme.typography.displayMedium
|
||||||
|
}
|
||||||
|
|
||||||
|
val titleSpacerSize = if (currentTheme.isDeviceCompact) {
|
||||||
|
24.dp
|
||||||
|
} else {
|
||||||
|
58.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
val bottomPadding = if (currentTheme.isDeviceCompact) {
|
||||||
|
10.dp
|
||||||
|
} else {
|
||||||
|
30.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.union(WindowInsets.ime)
|
||||||
|
) { padding ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(padding)
|
.padding(padding)
|
||||||
) {
|
.padding(top = 30.dp)
|
||||||
Box(
|
.padding(horizontal = 30.dp)
|
||||||
modifier = Modifier
|
.padding(bottom = bottomPadding)
|
||||||
.fillMaxSize()
|
|
||||||
.padding(30.dp)
|
|
||||||
.imePadding()
|
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -201,10 +223,10 @@ fun LoginScreen(
|
|||||||
Text(
|
Text(
|
||||||
text = stringResource(id = UiR.string.sign_in_to_vk),
|
text = stringResource(id = UiR.string.sign_in_to_vk),
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
style = MaterialTheme.typography.displayMedium
|
style = titleStyle
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(58.dp))
|
Spacer(modifier = Modifier.height(titleSpacerSize))
|
||||||
|
|
||||||
TextField(
|
TextField(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -336,7 +358,6 @@ fun LoginScreen(
|
|||||||
modifier = Modifier.align(Alignment.BottomCenter),
|
modifier = Modifier.align(Alignment.BottomCenter),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
|
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
focusManager.clearFocus()
|
focusManager.clearFocus()
|
||||||
@@ -361,7 +382,6 @@ fun LoginScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
+29
-3
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -30,6 +31,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.meloda.app.fast.designsystem.LocalTheme
|
||||||
import com.meloda.fast.auth.login.LoginViewModel
|
import com.meloda.fast.auth.login.LoginViewModel
|
||||||
import com.meloda.fast.auth.login.LoginViewModelImpl
|
import com.meloda.fast.auth.login.LoginViewModelImpl
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
@@ -64,6 +66,8 @@ fun LogoScreen(
|
|||||||
onLogoLongClicked: () -> Unit = {},
|
onLogoLongClicked: () -> Unit = {},
|
||||||
onGoNextButtonClicked: () -> Unit = {}
|
onGoNextButtonClicked: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
val currentTheme = LocalTheme.current
|
||||||
|
|
||||||
Scaffold { padding ->
|
Scaffold { padding ->
|
||||||
val topPadding by animateDpAsState(
|
val topPadding by animateDpAsState(
|
||||||
targetValue = padding.calculateTopPadding(),
|
targetValue = padding.calculateTopPadding(),
|
||||||
@@ -83,6 +87,24 @@ fun LogoScreen(
|
|||||||
label = "startPaddingAnimation"
|
label = "startPaddingAnimation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val iconWidth = if (currentTheme.isDeviceCompact) {
|
||||||
|
100.dp
|
||||||
|
} else {
|
||||||
|
134.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
val appNameTextStyle = if (currentTheme.isDeviceCompact) {
|
||||||
|
MaterialTheme.typography.displaySmall
|
||||||
|
} else {
|
||||||
|
MaterialTheme.typography.displayMedium
|
||||||
|
}
|
||||||
|
|
||||||
|
val bottomAdditionalPadding = if (currentTheme.isDeviceCompact) {
|
||||||
|
10.dp
|
||||||
|
} else {
|
||||||
|
30.dp
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -92,7 +114,9 @@ fun LogoScreen(
|
|||||||
end = endPadding,
|
end = endPadding,
|
||||||
bottom = bottomPadding
|
bottom = bottomPadding
|
||||||
)
|
)
|
||||||
.padding(30.dp)
|
.padding(top = 30.dp)
|
||||||
|
.padding(horizontal = 30.dp)
|
||||||
|
.padding(bottom = bottomAdditionalPadding)
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -104,7 +128,9 @@ fun LogoScreen(
|
|||||||
painter = painterResource(id = UiR.drawable.ic_logo_big),
|
painter = painterResource(id = UiR.drawable.ic_logo_big),
|
||||||
contentDescription = "Application Logo",
|
contentDescription = "Application Logo",
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier.combinedClickable(
|
modifier = Modifier
|
||||||
|
.width(iconWidth)
|
||||||
|
.combinedClickable(
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
indication = null,
|
indication = null,
|
||||||
onLongClick = onLogoLongClicked,
|
onLongClick = onLogoLongClicked,
|
||||||
@@ -114,7 +140,7 @@ fun LogoScreen(
|
|||||||
Spacer(modifier = Modifier.height(46.dp))
|
Spacer(modifier = Modifier.height(46.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = UiR.string.fast_messenger),
|
text = stringResource(id = UiR.string.fast_messenger),
|
||||||
style = MaterialTheme.typography.displayMedium,
|
style = appNameTextStyle,
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -60,6 +60,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -163,16 +164,16 @@ fun MessagesHistoryScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentWindowInsets = WindowInsets.statusBars,
|
|
||||||
topBar = {
|
|
||||||
val toolbarColorAlpha by animateFloatAsState(
|
val toolbarColorAlpha by animateFloatAsState(
|
||||||
targetValue = if (!listState.canScrollForward) 1f else 0f,
|
targetValue = if (!listState.canScrollForward) 1f else 0f,
|
||||||
label = "toolbarColorAlpha",
|
label = "toolbarColorAlpha",
|
||||||
animationSpec = tween(durationMillis = 50)
|
animationSpec = tween(durationMillis = 50)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentWindowInsets = WindowInsets.statusBars,
|
||||||
|
topBar = {
|
||||||
Column(modifier = Modifier.fillMaxWidth()) {
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -370,7 +371,13 @@ fun MessagesHistoryScreen(
|
|||||||
unfocusedIndicatorColor = Color.Transparent,
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
focusedIndicatorColor = Color.Transparent,
|
focusedIndicatorColor = Color.Transparent,
|
||||||
),
|
),
|
||||||
placeholder = { Text(text = stringResource(id = UiR.string.message_input_hint)) }
|
placeholder = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = UiR.string.message_input_hint),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
IconButton(onClick = onAttachmentButtonClicked) {
|
IconButton(onClick = onAttachmentButtonClicked) {
|
||||||
|
|||||||
Reference in New Issue
Block a user