mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-15 13:37:29 +01:00
Use Stable interface for History screen (#7586)
- Adds Stable interface - Move last Dialog into Compose - Make History screen be full Compose screen
This commit is contained in:
@@ -1,220 +1,89 @@
|
||||
package eu.kanade.presentation.history
|
||||
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.selection.toggleable
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.foundation.layout.safeContentPadding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Brush.Companion.linearGradient
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.paging.LoadState
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.items
|
||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||
import eu.kanade.presentation.components.EmptyScreen
|
||||
import eu.kanade.presentation.components.LoadingScreen
|
||||
import eu.kanade.presentation.components.RelativeDateHeader
|
||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||
import eu.kanade.presentation.history.components.HistoryItem
|
||||
import eu.kanade.presentation.history.components.HistoryItemShimmer
|
||||
import eu.kanade.presentation.util.bottomNavPaddingValues
|
||||
import eu.kanade.presentation.util.plus
|
||||
import eu.kanade.presentation.util.shimmerGradient
|
||||
import eu.kanade.presentation.util.topPaddingValues
|
||||
import eu.kanade.presentation.history.components.HistoryContent
|
||||
import eu.kanade.presentation.history.components.HistoryDeleteAllDialog
|
||||
import eu.kanade.presentation.history.components.HistoryDeleteDialog
|
||||
import eu.kanade.presentation.history.components.HistoryToolbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.text.DateFormat
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter.Dialog
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
fun HistoryScreen(
|
||||
nestedScrollInterop: NestedScrollConnection,
|
||||
presenter: HistoryPresenter,
|
||||
onClickCover: (HistoryWithRelations) -> Unit,
|
||||
onClickResume: (HistoryWithRelations) -> Unit,
|
||||
onClickDelete: (HistoryWithRelations, Boolean) -> Unit,
|
||||
) {
|
||||
val state by presenter.state.collectAsState()
|
||||
when (state) {
|
||||
is HistoryState.Loading -> LoadingScreen()
|
||||
is HistoryState.Error -> Text(text = (state as HistoryState.Error).error.message!!)
|
||||
is HistoryState.Success ->
|
||||
HistoryContent(
|
||||
nestedScroll = nestedScrollInterop,
|
||||
history = (state as HistoryState.Success).uiModels.collectAsLazyPagingItems(),
|
||||
val context = LocalContext.current
|
||||
Scaffold(
|
||||
modifier = Modifier.safeContentPadding(),
|
||||
topBar = {
|
||||
HistoryToolbar(state = presenter)
|
||||
},
|
||||
) {
|
||||
val items = presenter.getLazyHistory()
|
||||
when {
|
||||
items.loadState.refresh is LoadState.Loading && items.itemCount < 1 -> LoadingScreen()
|
||||
items.loadState.refresh is LoadState.NotLoading && items.itemCount < 1 -> EmptyScreen(textResource = R.string.information_no_recent_manga)
|
||||
else -> HistoryContent(
|
||||
history = items,
|
||||
contentPadding = it,
|
||||
onClickCover = onClickCover,
|
||||
onClickResume = onClickResume,
|
||||
onClickDelete = onClickDelete,
|
||||
onClickDelete = { presenter.dialog = Dialog.Delete(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistoryContent(
|
||||
history: LazyPagingItems<HistoryUiModel>,
|
||||
onClickCover: (HistoryWithRelations) -> Unit,
|
||||
onClickResume: (HistoryWithRelations) -> Unit,
|
||||
onClickDelete: (HistoryWithRelations, Boolean) -> Unit,
|
||||
preferences: PreferencesHelper = Injekt.get(),
|
||||
nestedScroll: NestedScrollConnection,
|
||||
) {
|
||||
if (history.loadState.refresh is LoadState.NotLoading && history.itemCount == 0) {
|
||||
EmptyScreen(textResource = R.string.information_no_recent_manga)
|
||||
return
|
||||
}
|
||||
|
||||
val relativeTime: Int = remember { preferences.relativeTime().get() }
|
||||
val dateFormat: DateFormat = remember { preferences.dateFormat() }
|
||||
|
||||
var removeState by remember { mutableStateOf<HistoryWithRelations?>(null) }
|
||||
|
||||
val scrollState = rememberLazyListState()
|
||||
|
||||
ScrollbarLazyColumn(
|
||||
modifier = Modifier
|
||||
.nestedScroll(nestedScroll),
|
||||
contentPadding = bottomNavPaddingValues + WindowInsets.navigationBars.asPaddingValues() + topPaddingValues,
|
||||
state = scrollState,
|
||||
) {
|
||||
items(history) { item ->
|
||||
when (item) {
|
||||
is HistoryUiModel.Header -> {
|
||||
RelativeDateHeader(
|
||||
modifier = Modifier
|
||||
.animateItemPlacement(),
|
||||
date = item.date,
|
||||
relativeTime = relativeTime,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
}
|
||||
is HistoryUiModel.Item -> {
|
||||
val value = item.item
|
||||
HistoryItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
history = value,
|
||||
onClickCover = { onClickCover(value) },
|
||||
onClickResume = { onClickResume(value) },
|
||||
onClickDelete = { removeState = value },
|
||||
)
|
||||
}
|
||||
null -> {
|
||||
val transition = rememberInfiniteTransition()
|
||||
val translateAnimation = transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 1000f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(
|
||||
durationMillis = 1000,
|
||||
easing = LinearEasing,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val brush = remember {
|
||||
linearGradient(
|
||||
colors = shimmerGradient,
|
||||
start = Offset(0f, 0f),
|
||||
end = Offset(
|
||||
x = translateAnimation.value,
|
||||
y = 00f,
|
||||
),
|
||||
)
|
||||
val onDismissRequest = { presenter.dialog = null }
|
||||
when (val dialog = presenter.dialog) {
|
||||
is Dialog.Delete -> {
|
||||
HistoryDeleteDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onDelete = { all ->
|
||||
if (all) {
|
||||
presenter.removeAllFromHistory(dialog.history.mangaId)
|
||||
} else {
|
||||
presenter.removeFromHistory(dialog.history)
|
||||
}
|
||||
HistoryItemShimmer(brush = brush)
|
||||
},
|
||||
)
|
||||
}
|
||||
Dialog.DeleteAll -> {
|
||||
HistoryDeleteAllDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onDelete = {
|
||||
presenter.deleteAllHistory()
|
||||
},
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
presenter.events.collectLatest { event ->
|
||||
when (event) {
|
||||
HistoryPresenter.Event.InternalError -> context.toast(R.string.internal_error)
|
||||
HistoryPresenter.Event.NoNextChapterFound -> context.toast(R.string.no_next_chapter)
|
||||
is HistoryPresenter.Event.OpenChapter -> {
|
||||
val intent = ReaderActivity.newIntent(context, event.chapter.mangaId, event.chapter.id)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removeState != null) {
|
||||
RemoveHistoryDialog(
|
||||
onPositive = { all ->
|
||||
onClickDelete(removeState!!, all)
|
||||
removeState = null
|
||||
},
|
||||
onNegative = { removeState = null },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RemoveHistoryDialog(
|
||||
onPositive: (Boolean) -> Unit,
|
||||
onNegative: () -> Unit,
|
||||
) {
|
||||
var removeEverything by remember { mutableStateOf(false) }
|
||||
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(text = stringResource(R.string.action_remove))
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
Text(text = stringResource(R.string.dialog_with_checkbox_remove_description))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp)
|
||||
.toggleable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
value = removeEverything,
|
||||
onValueChange = { removeEverything = it },
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Checkbox(
|
||||
checked = removeEverything,
|
||||
onCheckedChange = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
text = stringResource(R.string.dialog_with_checkbox_reset),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = onNegative,
|
||||
confirmButton = {
|
||||
TextButton(onClick = { onPositive(removeEverything) }) {
|
||||
Text(text = stringResource(R.string.action_remove))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onNegative) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
sealed class HistoryUiModel {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package eu.kanade.presentation.history.components
|
||||
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.items
|
||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||
import eu.kanade.presentation.components.RelativeDateHeader
|
||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||
import eu.kanade.presentation.history.HistoryUiModel
|
||||
import eu.kanade.presentation.util.bottomNavPaddingValues
|
||||
import eu.kanade.presentation.util.plus
|
||||
import eu.kanade.presentation.util.shimmerGradient
|
||||
import eu.kanade.presentation.util.topPaddingValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.text.DateFormat
|
||||
|
||||
@Composable
|
||||
fun HistoryContent(
|
||||
history: LazyPagingItems<HistoryUiModel>,
|
||||
contentPadding: PaddingValues,
|
||||
onClickCover: (HistoryWithRelations) -> Unit,
|
||||
onClickResume: (HistoryWithRelations) -> Unit,
|
||||
onClickDelete: (HistoryWithRelations) -> Unit,
|
||||
preferences: PreferencesHelper = Injekt.get(),
|
||||
) {
|
||||
val relativeTime: Int = remember { preferences.relativeTime().get() }
|
||||
val dateFormat: DateFormat = remember { preferences.dateFormat() }
|
||||
|
||||
ScrollbarLazyColumn(
|
||||
contentPadding = contentPadding + bottomNavPaddingValues + topPaddingValues,
|
||||
state = rememberLazyListState(),
|
||||
) {
|
||||
items(history) { item ->
|
||||
when (item) {
|
||||
is HistoryUiModel.Header -> {
|
||||
RelativeDateHeader(
|
||||
modifier = Modifier
|
||||
.animateItemPlacement(),
|
||||
date = item.date,
|
||||
relativeTime = relativeTime,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
}
|
||||
is HistoryUiModel.Item -> {
|
||||
val value = item.item
|
||||
HistoryItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
history = value,
|
||||
onClickCover = { onClickCover(value) },
|
||||
onClickResume = { onClickResume(value) },
|
||||
onClickDelete = { onClickDelete(value) },
|
||||
)
|
||||
}
|
||||
null -> {
|
||||
val transition = rememberInfiniteTransition()
|
||||
val translateAnimation = transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 1000f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(
|
||||
durationMillis = 1000,
|
||||
easing = LinearEasing,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val brush = remember {
|
||||
Brush.linearGradient(
|
||||
colors = shimmerGradient,
|
||||
start = Offset(0f, 0f),
|
||||
end = Offset(
|
||||
x = translateAnimation.value,
|
||||
y = 00f,
|
||||
),
|
||||
)
|
||||
}
|
||||
HistoryItemShimmer(brush = brush)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package eu.kanade.presentation.history.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.selection.toggleable
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@Composable
|
||||
fun HistoryDeleteDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
onDelete: (Boolean) -> Unit,
|
||||
) {
|
||||
var removeEverything by remember { mutableStateOf(false) }
|
||||
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(text = stringResource(R.string.action_remove))
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
Text(text = stringResource(R.string.dialog_with_checkbox_remove_description))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp)
|
||||
.toggleable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
value = removeEverything,
|
||||
onValueChange = { removeEverything = it },
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Checkbox(
|
||||
checked = removeEverything,
|
||||
onCheckedChange = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
text = stringResource(R.string.dialog_with_checkbox_reset),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = onDismissRequest,
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
onDelete(removeEverything)
|
||||
onDismissRequest()
|
||||
},) {
|
||||
Text(text = stringResource(R.string.action_remove))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(android.R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistoryDeleteAllDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
) {
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(text = stringResource(R.string.action_remove_everything))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(R.string.clear_history_confirmation))
|
||||
},
|
||||
onDismissRequest = onDismissRequest,
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
onDelete()
|
||||
onDismissRequest()
|
||||
},) {
|
||||
Text(text = stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(android.R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package eu.kanade.presentation.history.components
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.DeleteSweep
|
||||
import androidx.compose.material.icons.outlined.Search
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryState
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun HistoryToolbar(
|
||||
state: HistoryState,
|
||||
) {
|
||||
if (state.searchQuery == null) {
|
||||
HistoryRegularToolbar(
|
||||
onClickSearch = { state.searchQuery = "" },
|
||||
onClickDelete = { state.dialog = HistoryPresenter.Dialog.DeleteAll },
|
||||
)
|
||||
} else {
|
||||
HistorySearchToolbar(
|
||||
searchQuery = state.searchQuery!!,
|
||||
onChangeSearchQuery = { state.searchQuery = it },
|
||||
onClickCloseSearch = { state.searchQuery = null },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistoryRegularToolbar(
|
||||
onClickSearch: () -> Unit,
|
||||
onClickDelete: () -> Unit,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
title = {
|
||||
Text(text = stringResource(id = R.string.history))
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = onClickSearch) {
|
||||
Icon(Icons.Outlined.Search, contentDescription = "search")
|
||||
}
|
||||
IconButton(onClick = onClickDelete) {
|
||||
Icon(Icons.Outlined.DeleteSweep, contentDescription = "delete")
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistorySearchToolbar(
|
||||
searchQuery: String,
|
||||
onChangeSearchQuery: (String) -> Unit,
|
||||
onClickCloseSearch: () -> Unit,
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester.Default }
|
||||
SmallTopAppBar(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickCloseSearch) {
|
||||
Icon(Icons.Outlined.ArrowBack, contentDescription = "delete")
|
||||
}
|
||||
},
|
||||
title = {
|
||||
BasicTextField(
|
||||
value = searchQuery,
|
||||
onValueChange = onChangeSearchQuery,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequester),
|
||||
textStyle = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onBackground),
|
||||
singleLine = true,
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
},
|
||||
)
|
||||
LaunchedEffect(focusRequester) {
|
||||
// TODO: https://issuetracker.google.com/issues/204502668
|
||||
delay(100)
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user