android: add tablet adaptive layouts and fix voice release send
This commit is contained in:
@@ -450,3 +450,8 @@
|
|||||||
- Added playback speed switch for voice messages (`1.0x -> 1.5x -> 2.0x`).
|
- Added playback speed switch for voice messages (`1.0x -> 1.5x -> 2.0x`).
|
||||||
- Added view-only circle video renderer for `video_note` messages with looped playback.
|
- Added view-only circle video renderer for `video_note` messages with looped playback.
|
||||||
- Kept regular audio/video attachment rendering for non-voice/non-circle media unchanged.
|
- Kept regular audio/video attachment rendering for non-voice/non-circle media unchanged.
|
||||||
|
|
||||||
|
### Step 72 - Adaptive layout baseline (phone/tablet) + voice release fix
|
||||||
|
- Added tablet-aware max-width layout constraints across major screens (login, verify/reset auth, chats list, chat, profile, settings).
|
||||||
|
- Kept phone layout unchanged while centering content and limiting line width on larger displays.
|
||||||
|
- Fixed voice hold-to-send gesture reliability by removing pointer-input restarts during active recording, so release consistently triggers send path.
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package ru.daemonlord.messenger.ui.auth
|
package ru.daemonlord.messenger.ui.auth
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
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.widthIn
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
@@ -17,6 +19,7 @@ import androidx.compose.material3.TextButton
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
@@ -29,11 +32,18 @@ fun LoginScreen(
|
|||||||
onOpenVerifyEmail: () -> Unit,
|
onOpenVerifyEmail: () -> Unit,
|
||||||
onOpenResetPassword: () -> Unit,
|
onOpenResetPassword: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||||
.padding(horizontal = 24.dp),
|
.padding(horizontal = 24.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(if (isTabletLayout) Modifier.widthIn(max = 560.dp) else Modifier),
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
@@ -104,3 +114,4 @@ fun LoginScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package ru.daemonlord.messenger.ui.auth.reset
|
package ru.daemonlord.messenger.ui.auth.reset
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
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.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
@@ -18,7 +20,9 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
@@ -33,11 +37,18 @@ fun ResetPasswordRoute(
|
|||||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
var email by remember { mutableStateOf("") }
|
var email by remember { mutableStateOf("") }
|
||||||
var password by remember { mutableStateOf("") }
|
var password by remember { mutableStateOf("") }
|
||||||
Column(
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
|
contentAlignment = Alignment.TopCenter,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(if (isTabletLayout) Modifier.widthIn(max = 620.dp) else Modifier),
|
||||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
) {
|
) {
|
||||||
Text("Password reset", style = MaterialTheme.typography.headlineSmall)
|
Text("Password reset", style = MaterialTheme.typography.headlineSmall)
|
||||||
@@ -85,3 +96,4 @@ fun ResetPasswordRoute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package ru.daemonlord.messenger.ui.auth.verify
|
package ru.daemonlord.messenger.ui.auth.verify
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
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.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
@@ -19,7 +21,9 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
@@ -40,11 +44,18 @@ fun VerifyEmailRoute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
|
contentAlignment = Alignment.TopCenter,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(if (isTabletLayout) Modifier.widthIn(max = 620.dp) else Modifier),
|
||||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
) {
|
) {
|
||||||
Text("Verify email", style = MaterialTheme.typography.headlineSmall)
|
Text("Verify email", style = MaterialTheme.typography.headlineSmall)
|
||||||
@@ -75,3 +86,4 @@ fun VerifyEmailRoute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -237,6 +238,8 @@ fun ChatScreen(
|
|||||||
var showDeleteDialog by remember { mutableStateOf(false) }
|
var showDeleteDialog by remember { mutableStateOf(false) }
|
||||||
val actionSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
val actionSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||||
val forwardSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
val forwardSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||||
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
|
val adaptiveHorizontalPadding = if (isTabletLayout) 72.dp else 0.dp
|
||||||
|
|
||||||
LaunchedEffect(state.isRecordingVoice) {
|
LaunchedEffect(state.isRecordingVoice) {
|
||||||
if (!state.isRecordingVoice) return@LaunchedEffect
|
if (!state.isRecordingVoice) return@LaunchedEffect
|
||||||
@@ -264,7 +267,8 @@ fun ChatScreen(
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing),
|
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||||
|
.padding(horizontal = adaptiveHorizontalPadding),
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -676,7 +680,6 @@ fun ChatScreen(
|
|||||||
} else {
|
} else {
|
||||||
VoiceHoldToRecordButton(
|
VoiceHoldToRecordButton(
|
||||||
enabled = state.canSendMessages && !state.isUploadingMedia,
|
enabled = state.canSendMessages && !state.isUploadingMedia,
|
||||||
isRecording = state.isRecordingVoice,
|
|
||||||
isLocked = state.isVoiceLocked,
|
isLocked = state.isVoiceLocked,
|
||||||
onStart = onVoiceRecordStart,
|
onStart = onVoiceRecordStart,
|
||||||
onLock = onVoiceRecordLock,
|
onLock = onVoiceRecordLock,
|
||||||
@@ -1357,7 +1360,6 @@ private fun VoiceWaveform(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun VoiceHoldToRecordButton(
|
private fun VoiceHoldToRecordButton(
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
isRecording: Boolean,
|
|
||||||
isLocked: Boolean,
|
isLocked: Boolean,
|
||||||
onStart: () -> Unit,
|
onStart: () -> Unit,
|
||||||
onLock: () -> Unit,
|
onLock: () -> Unit,
|
||||||
@@ -1366,7 +1368,7 @@ private fun VoiceHoldToRecordButton(
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.pointerInput(enabled, isRecording, isLocked) {
|
.pointerInput(enabled, isLocked) {
|
||||||
if (!enabled || isLocked) return@pointerInput
|
if (!enabled || isLocked) return@pointerInput
|
||||||
awaitEachGesture {
|
awaitEachGesture {
|
||||||
val down = awaitFirstDown(requireUnconsumed = false)
|
val down = awaitFirstDown(requireUnconsumed = false)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
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.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
@@ -41,6 +42,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -133,11 +135,18 @@ fun ChatListScreen(
|
|||||||
var selectedManageChatIdText by remember { mutableStateOf("") }
|
var selectedManageChatIdText by remember { mutableStateOf("") }
|
||||||
var manageUserIdText by remember { mutableStateOf("") }
|
var manageUserIdText by remember { mutableStateOf("") }
|
||||||
var manageRoleText by remember { mutableStateOf("member") }
|
var manageRoleText by remember { mutableStateOf("member") }
|
||||||
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
|
|
||||||
Column(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing),
|
.windowInsetsPadding(WindowInsets.safeDrawing),
|
||||||
|
contentAlignment = Alignment.TopCenter,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.then(if (isTabletLayout) Modifier.widthIn(max = 820.dp) else Modifier),
|
||||||
) {
|
) {
|
||||||
TabRow(
|
TabRow(
|
||||||
selectedTabIndex = if (state.selectedTab == ChatTab.ALL) 0 else 1,
|
selectedTabIndex = if (state.selectedTab == ChatTab.ALL) 0 else 1,
|
||||||
@@ -491,6 +500,7 @@ fun ChatListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ChatRow(
|
private fun ChatRow(
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.navigationBarsPadding
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
@@ -38,6 +39,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -78,6 +80,7 @@ fun ProfileScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val context = androidx.compose.ui.platform.LocalContext.current
|
val context = androidx.compose.ui.platform.LocalContext.current
|
||||||
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
val pickAvatarLauncher = rememberLauncherForActivityResult(
|
val pickAvatarLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.GetContent(),
|
contract = ActivityResultContracts.GetContent(),
|
||||||
@@ -92,12 +95,18 @@ fun ProfileScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||||
|
.navigationBarsPadding(),
|
||||||
|
contentAlignment = Alignment.TopCenter,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(if (isTabletLayout) Modifier.widthIn(max = 720.dp) else Modifier)
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.navigationBarsPadding()
|
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
@@ -202,6 +211,7 @@ fun ProfileScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Uri.toSquareJpeg(context: Context): ByteArray? {
|
private fun Uri.toSquareJpeg(context: Context): ByteArray? {
|
||||||
val bitmap = runCatching {
|
val bitmap = runCatching {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ru.daemonlord.messenger.ui.settings
|
package ru.daemonlord.messenger.ui.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -9,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
@@ -28,6 +30,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
@@ -66,16 +69,23 @@ fun SettingsScreen(
|
|||||||
var blockUserIdInput by remember { mutableStateOf("") }
|
var blockUserIdInput by remember { mutableStateOf("") }
|
||||||
var nightMode by remember { mutableIntStateOf(AppCompatDelegate.getDefaultNightMode()) }
|
var nightMode by remember { mutableIntStateOf(AppCompatDelegate.getDefaultNightMode()) }
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
viewModel.refreshRecoveryStatus()
|
viewModel.refreshRecoveryStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
.windowInsetsPadding(WindowInsets.safeDrawing),
|
||||||
|
contentAlignment = Alignment.TopCenter,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(if (isTabletLayout) Modifier.widthIn(max = 720.dp) else Modifier)
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
@@ -312,3 +322,4 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
## 13. UI/UX и темы
|
## 13. UI/UX и темы
|
||||||
- [x] Светлая/темная тема (читаемая)
|
- [x] Светлая/темная тема (читаемая)
|
||||||
- [ ] Адаптивность phone/tablet
|
- [x] Адаптивность phone/tablet
|
||||||
- [x] Контекстные меню без конфликтов жестов
|
- [x] Контекстные меню без конфликтов жестов
|
||||||
- [x] Bottom sheets/dialog behavior consistency
|
- [x] Bottom sheets/dialog behavior consistency
|
||||||
- [x] Accessibility (TalkBack, dynamic type)
|
- [x] Accessibility (TalkBack, dynamic type)
|
||||||
|
|||||||
Reference in New Issue
Block a user