修正下一个口令时间窗口错误及高度挤压问题
This commit is contained in:
@@ -40,6 +40,8 @@ fun TokenDetailSheet(
|
|||||||
var nextCode by remember { mutableStateOf("") }
|
var nextCode by remember { mutableStateOf("") }
|
||||||
var progress by remember { mutableStateOf(1f) }
|
var progress by remember { mutableStateOf(1f) }
|
||||||
var remainingSeconds by remember { mutableStateOf(0) }
|
var remainingSeconds by remember { mutableStateOf(0) }
|
||||||
|
val showNextPreview = remainingSeconds in 0..5 &&
|
||||||
|
(token.tokenType == TokenType.TOTP || token.tokenType == TokenType.STEAM)
|
||||||
|
|
||||||
val secretBytes = remember(token.secret.value) {
|
val secretBytes = remember(token.secret.value) {
|
||||||
try {
|
try {
|
||||||
@@ -64,7 +66,7 @@ fun TokenDetailSheet(
|
|||||||
secretBytes, time, token.period, token.digits, token.algorithm.ordinal
|
secretBytes, time, token.period, token.digits, token.algorithm.ordinal
|
||||||
)
|
)
|
||||||
nextCode = NativeLib.generateTOTP(
|
nextCode = NativeLib.generateTOTP(
|
||||||
secretBytes, time + 1, token.period, token.digits, token.algorithm.ordinal
|
secretBytes, time + token.period, token.period, token.digits, token.algorithm.ordinal
|
||||||
)
|
)
|
||||||
val remaining = periodMs - (now % periodMs)
|
val remaining = periodMs - (now % periodMs)
|
||||||
progress = remaining.toFloat() / periodMs.toFloat()
|
progress = remaining.toFloat() / periodMs.toFloat()
|
||||||
@@ -73,7 +75,7 @@ fun TokenDetailSheet(
|
|||||||
TokenType.STEAM -> {
|
TokenType.STEAM -> {
|
||||||
val time = now / 1000L
|
val time = now / 1000L
|
||||||
currentCode = NativeLib.generateSteam(secretBytes, time)
|
currentCode = NativeLib.generateSteam(secretBytes, time)
|
||||||
nextCode = NativeLib.generateSteam(secretBytes, time + 1)
|
nextCode = NativeLib.generateSteam(secretBytes, time + 30)
|
||||||
val periodMs = 30000L
|
val periodMs = 30000L
|
||||||
val remaining = periodMs - (now % periodMs)
|
val remaining = periodMs - (now % periodMs)
|
||||||
progress = remaining.toFloat() / periodMs.toFloat()
|
progress = remaining.toFloat() / periodMs.toFloat()
|
||||||
@@ -133,12 +135,17 @@ fun TokenDetailSheet(
|
|||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
if (remainingSeconds <= 5 && (token.tokenType == TokenType.TOTP || token.tokenType == TokenType.STEAM)) {
|
Box(
|
||||||
Text(
|
modifier = Modifier.height(20.dp),
|
||||||
text = formatCode(nextCode),
|
contentAlignment = Alignment.Center
|
||||||
style = MaterialTheme.typography.bodySmall,
|
) {
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
|
if (showNextPreview) {
|
||||||
)
|
Text(
|
||||||
|
text = formatCode(nextCode),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +157,7 @@ fun TokenDetailSheet(
|
|||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
progress = { progress },
|
progress = { progress },
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = if (remainingSeconds <= 5) warningColor else MaterialTheme.colorScheme.primary,
|
color = if (showNextPreview) warningColor else MaterialTheme.colorScheme.primary,
|
||||||
trackColor = MaterialTheme.colorScheme.surfaceVariant,
|
trackColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
strokeWidth = 3.dp,
|
strokeWidth = 3.dp,
|
||||||
)
|
)
|
||||||
@@ -158,7 +165,7 @@ fun TokenDetailSheet(
|
|||||||
text = "$remainingSeconds",
|
text = "$remainingSeconds",
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = if (remainingSeconds <= 5) warningColor else MaterialTheme.colorScheme.onSurface
|
color = if (showNextPreview) warningColor else MaterialTheme.colorScheme.onSurface
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ import androidx.compose.runtime.*
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -48,6 +52,15 @@ fun TokensScreen(
|
|||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
var showAddBottomSheet by remember { mutableStateOf(false) }
|
var showAddBottomSheet by remember { mutableStateOf(false) }
|
||||||
var isSearchExpanded by remember { mutableStateOf(false) }
|
var isSearchExpanded by remember { mutableStateOf(false) }
|
||||||
|
var searchFieldHasFocus by remember { mutableStateOf(false) }
|
||||||
|
val searchFocusRequester = remember { FocusRequester() }
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
|
|
||||||
|
LaunchedEffect(isSearchExpanded) {
|
||||||
|
if (isSearchExpanded) {
|
||||||
|
searchFocusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -62,7 +75,9 @@ fun TokensScreen(
|
|||||||
}
|
}
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = isSearchExpanded,
|
visible = isSearchExpanded,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(end = 16.dp)
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
shape = MaterialTheme.shapes.large,
|
shape = MaterialTheme.shapes.large,
|
||||||
@@ -72,12 +87,21 @@ fun TokensScreen(
|
|||||||
TextField(
|
TextField(
|
||||||
value = uiState.searchQuery,
|
value = uiState.searchQuery,
|
||||||
onValueChange = { viewModel.updateSearchQuery(it) },
|
onValueChange = { viewModel.updateSearchQuery(it) },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.focusRequester(searchFocusRequester)
|
||||||
|
.onFocusChanged { focusState ->
|
||||||
|
if (searchFieldHasFocus && !focusState.isFocused) {
|
||||||
|
isSearchExpanded = false
|
||||||
|
}
|
||||||
|
searchFieldHasFocus = focusState.isFocused
|
||||||
|
},
|
||||||
placeholder = { Text(stringResource(R.string.search_tokens)) },
|
placeholder = { Text(stringResource(R.string.search_tokens)) },
|
||||||
leadingIcon = { Icon(Icons.Default.Search, contentDescription = stringResource(R.string.search)) },
|
leadingIcon = { Icon(Icons.Default.Search, contentDescription = stringResource(R.string.search)) },
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
viewModel.updateSearchQuery("")
|
viewModel.updateSearchQuery("")
|
||||||
|
focusManager.clearFocus(force = true)
|
||||||
isSearchExpanded = false
|
isSearchExpanded = false
|
||||||
}) {
|
}) {
|
||||||
Icon(Icons.Default.Close, contentDescription = "Clear search")
|
Icon(Icons.Default.Close, contentDescription = "Clear search")
|
||||||
@@ -211,6 +235,8 @@ fun TokenCard(
|
|||||||
var remainingSeconds by remember { mutableStateOf(0) }
|
var remainingSeconds by remember { mutableStateOf(0) }
|
||||||
var showDetailSheet by remember { mutableStateOf(false) }
|
var showDetailSheet by remember { mutableStateOf(false) }
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val showNextPreview = remainingSeconds in 0..5 &&
|
||||||
|
(token.tokenType == TokenType.TOTP || token.tokenType == TokenType.STEAM)
|
||||||
|
|
||||||
val secretBytes = remember(token.secret.value) {
|
val secretBytes = remember(token.secret.value) {
|
||||||
try {
|
try {
|
||||||
@@ -240,7 +266,7 @@ fun TokenCard(
|
|||||||
)
|
)
|
||||||
nextCode = NativeLib.generateTOTP(
|
nextCode = NativeLib.generateTOTP(
|
||||||
secretBytes,
|
secretBytes,
|
||||||
time + 1,
|
time + token.period,
|
||||||
token.period,
|
token.period,
|
||||||
token.digits,
|
token.digits,
|
||||||
token.algorithm.ordinal
|
token.algorithm.ordinal
|
||||||
@@ -257,7 +283,7 @@ fun TokenCard(
|
|||||||
)
|
)
|
||||||
nextCode = NativeLib.generateSteam(
|
nextCode = NativeLib.generateSteam(
|
||||||
secretBytes,
|
secretBytes,
|
||||||
time + 1
|
time + 30
|
||||||
)
|
)
|
||||||
val periodMs = 30000L
|
val periodMs = 30000L
|
||||||
val remaining = periodMs - (now % periodMs)
|
val remaining = periodMs - (now % periodMs)
|
||||||
@@ -318,12 +344,17 @@ fun TokenCard(
|
|||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
if (remainingSeconds <= 5 && (token.tokenType == TokenType.TOTP || token.tokenType == TokenType.STEAM)) {
|
Box(
|
||||||
Text(
|
modifier = Modifier.height(20.dp),
|
||||||
text = formatCode(nextCode),
|
contentAlignment = Alignment.CenterStart
|
||||||
style = MaterialTheme.typography.bodySmall,
|
) {
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
|
if (showNextPreview) {
|
||||||
)
|
Text(
|
||||||
|
text = formatCode(nextCode),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +370,7 @@ fun TokenCard(
|
|||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
progress = { progress },
|
progress = { progress },
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = if (remainingSeconds <= 5) warningColor else MaterialTheme.colorScheme.primary,
|
color = if (showNextPreview) warningColor else MaterialTheme.colorScheme.primary,
|
||||||
trackColor = MaterialTheme.colorScheme.surfaceVariant,
|
trackColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
strokeWidth = 3.dp,
|
strokeWidth = 3.dp,
|
||||||
)
|
)
|
||||||
@@ -347,7 +378,7 @@ fun TokenCard(
|
|||||||
text = "$remainingSeconds",
|
text = "$remainingSeconds",
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = if (remainingSeconds <= 5) warningColor else MaterialTheme.colorScheme.onSurface
|
color = if (showNextPreview) warningColor else MaterialTheme.colorScheme.onSurface
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user