mirror of
https://github.com/twofas/2fas-android.git
synced 2025-01-05 14:05:30 +01:00
Add search to browser extension request screen
This commit is contained in:
parent
7dee6658a7
commit
ec590bd579
@ -0,0 +1,174 @@
|
||||
package com.twofasapp.designsystem.common
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
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.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.twofasapp.designsystem.TwIcons
|
||||
import com.twofasapp.designsystem.TwTheme
|
||||
|
||||
@Composable
|
||||
fun TopAppBarWithSearch(
|
||||
title: String,
|
||||
searchHint: String = "",
|
||||
modifier: Modifier = Modifier,
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
onSearchValueChanged: (String) -> Unit = {},
|
||||
navigationClick: () -> Unit
|
||||
) {
|
||||
val showSearch = remember { mutableStateOf(false) }
|
||||
|
||||
TwTopAppBar(title = {
|
||||
if (showSearch.value) {
|
||||
SearchBar(hint = searchHint, showSearch = showSearch, onValueChanged = onSearchValueChanged)
|
||||
} else {
|
||||
Text(text = title, color = TwTheme.color.onSurfacePrimary)
|
||||
}
|
||||
}, navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
if (showSearch.value) {
|
||||
showSearch.value = false
|
||||
onSearchValueChanged("")
|
||||
} else {
|
||||
navigationClick.invoke()
|
||||
}
|
||||
}) {
|
||||
Icon(TwIcons.ArrowBack, null, tint = TwTheme.color.onSurfacePrimary)
|
||||
}
|
||||
}, actions = {
|
||||
if (showSearch.value.not()) {
|
||||
IconButton(onClick = { showSearch.value = true }) {
|
||||
Icon(TwIcons.Search, null, tint = TwTheme.color.primary)
|
||||
}
|
||||
}
|
||||
actions()
|
||||
}, modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
value: String = "",
|
||||
hint: String = "",
|
||||
showSearch: MutableState<Boolean>,
|
||||
onValueChanged: (String) -> Unit = {},
|
||||
onClearClick: () -> Unit = {},
|
||||
) {
|
||||
val textValue = remember { mutableStateOf(value) }
|
||||
val showClearButton = remember { mutableStateOf(false) }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
BackHandler(
|
||||
enabled = showSearch.value
|
||||
) {
|
||||
if (textValue.value.isNotEmpty()) {
|
||||
textValue.value = ""
|
||||
onValueChanged("")
|
||||
} else {
|
||||
showClearButton.value = false
|
||||
showSearch.value = false
|
||||
focusManager.clearFocus()
|
||||
keyboardController?.hide()
|
||||
}
|
||||
|
||||
onClearClick()
|
||||
}
|
||||
|
||||
if (showSearch.value) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.height(56.dp)
|
||||
.fillMaxWidth()
|
||||
.onFocusChanged { focusState ->
|
||||
showClearButton.value = focusState.isFocused
|
||||
}
|
||||
.focusRequester(focusRequester),
|
||||
value = textValue.value,
|
||||
onValueChange = {
|
||||
textValue.value = it
|
||||
onValueChanged(it)
|
||||
},
|
||||
placeholder = {
|
||||
Text(text = hint, style = MaterialTheme.typography.bodyMedium.copy(fontSize = 18.sp))
|
||||
},
|
||||
textStyle = MaterialTheme.typography.bodyMedium.copy(fontSize = 18.sp),
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedTextColor = TwTheme.color.onSurfacePrimary,
|
||||
disabledTextColor = Color.Black,
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
focusedLabelColor = TwTheme.color.onSurfaceSecondary,
|
||||
unfocusedLabelColor = TwTheme.color.onSurfaceSecondary,
|
||||
errorLabelColor = TwTheme.color.error,
|
||||
),
|
||||
trailingIcon = {
|
||||
AnimatedVisibility(
|
||||
visible = showClearButton.value,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
IconButton(onClick = {
|
||||
if (textValue.value.isNotEmpty()) {
|
||||
textValue.value = ""
|
||||
onValueChanged("")
|
||||
} else {
|
||||
showClearButton.value = false
|
||||
showSearch.value = false
|
||||
focusManager.clearFocus()
|
||||
keyboardController?.hide()
|
||||
}
|
||||
|
||||
onClearClick()
|
||||
}) {
|
||||
Icon(
|
||||
painter = TwIcons.Close,
|
||||
tint = TwTheme.color.onSurfacePrimary,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
maxLines = 1,
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = {
|
||||
keyboardController?.hide()
|
||||
}),
|
||||
)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
} else {
|
||||
textValue.value = ""
|
||||
onValueChanged("")
|
||||
}
|
||||
}
|
@ -189,6 +189,7 @@ class Strings(c: Context) {
|
||||
val browserRequestSuggested = c.getString(R.string.extension__services_suggested_header)
|
||||
val browserRequestAll = c.getString(R.string.extension__services_all_header)
|
||||
val browserRequestOther = c.getString(R.string.extension__services_other_header)
|
||||
val browserRequestEmpty = c.getString(R.string.tokens__service_not_found_search)
|
||||
|
||||
val settingsTheme = c.getString(R.string.settings__option_theme)
|
||||
val settingsShowNextCode = c.getString(R.string.settings__show_next_token)
|
||||
|
@ -3,10 +3,12 @@ package com.twofasapp.feature.browserext.ui.request
|
||||
import android.content.Intent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@ -17,9 +19,13 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
@ -27,13 +33,16 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.twofasapp.common.domain.Service
|
||||
import com.twofasapp.designsystem.TwTheme
|
||||
import com.twofasapp.designsystem.common.TopAppBarWithSearch
|
||||
import com.twofasapp.designsystem.common.TwDivider
|
||||
import com.twofasapp.designsystem.common.TwSwitch
|
||||
import com.twofasapp.designsystem.common.TwTopAppBar
|
||||
import com.twofasapp.designsystem.ktx.LocalBackDispatcher
|
||||
import com.twofasapp.designsystem.ktx.currentActivity
|
||||
import com.twofasapp.designsystem.service.DsServiceSimple
|
||||
import com.twofasapp.designsystem.service.asState
|
||||
import com.twofasapp.feature.browserext.notification.BrowserExtRequestPayload
|
||||
import com.twofasapp.feature.browserext.notification.BrowserExtRequestReceiver
|
||||
import com.twofasapp.locale.R
|
||||
import com.twofasapp.locale.TwLocale
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
@ -53,6 +62,7 @@ internal fun BrowserExtRequestScreen(
|
||||
ScreenContent(
|
||||
uiState = uiState,
|
||||
onSaveMyChoiceToggle = { viewModel.toggleSaveMyChoice() },
|
||||
onSearchChanged = { viewModel.updateSearchQuery(it) },
|
||||
onServiceClick = { service ->
|
||||
activity.lifecycleScope.launch {
|
||||
viewModel.assignDomain(service)
|
||||
@ -81,11 +91,26 @@ private fun ScreenContent(
|
||||
uiState: BrowserExtRequestUiState,
|
||||
onSaveMyChoiceToggle: () -> Unit = {},
|
||||
onServiceClick: (Service) -> Unit = {},
|
||||
onSearchChanged: (String) -> Unit = {},
|
||||
) {
|
||||
val strings = TwLocale.strings
|
||||
val backDispatcher = LocalBackDispatcher
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
|
||||
Scaffold(
|
||||
topBar = { TwTopAppBar(titleText = strings.browserRequestTitle) },
|
||||
topBar = {
|
||||
TopAppBarWithSearch(
|
||||
title = strings.browserRequestTitle,
|
||||
searchHint = stringResource(id = R.string.commons__search),
|
||||
onSearchValueChanged = {
|
||||
onSearchChanged(it)
|
||||
},
|
||||
) {
|
||||
backDispatcher.onBackPressed()
|
||||
}
|
||||
}
|
||||
) { padding ->
|
||||
LazyColumn(modifier = Modifier.padding(padding)) {
|
||||
item {
|
||||
@ -146,6 +171,25 @@ private fun ScreenContent(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.suggestedServices.isEmpty() && uiState.otherServices.isEmpty()) {
|
||||
item {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
TwDivider()
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
text = strings.browserRequestEmpty,
|
||||
color = TwTheme.color.onSurfaceSecondary,
|
||||
style = TwTheme.typo.body2,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,3 +236,16 @@ private fun Preview() {
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Empty() {
|
||||
ScreenContent(
|
||||
uiState = BrowserExtRequestUiState(
|
||||
browserName = "{browser}",
|
||||
domain = "{domain}",
|
||||
suggestedServices = emptyList(),
|
||||
otherServices = emptyList(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.twofasapp.feature.browserext.ui.request
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.twofasapp.feature.browserext.notification.BrowserExtRequestPayload
|
||||
import com.twofasapp.feature.browserext.notification.DomainMatcher
|
||||
import com.twofasapp.common.domain.Service
|
||||
import com.twofasapp.common.ktx.launchScoped
|
||||
import com.twofasapp.data.browserext.BrowserExtRepository
|
||||
import com.twofasapp.data.services.ServicesRepository
|
||||
import com.twofasapp.feature.browserext.notification.BrowserExtRequestPayload
|
||||
import com.twofasapp.feature.browserext.notification.DomainMatcher
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
@ -14,28 +14,45 @@ internal class BrowserExtRequestViewModel(
|
||||
private val browserExtRepository: BrowserExtRepository,
|
||||
private val servicesRepository: ServicesRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
val uiState = MutableStateFlow(BrowserExtRequestUiState())
|
||||
private val searchQuery = MutableStateFlow("")
|
||||
|
||||
fun init(payload: BrowserExtRequestPayload) {
|
||||
launchScoped {
|
||||
val domain = payload.domain
|
||||
val services = servicesRepository.getServices()
|
||||
val matched = domain?.let { DomainMatcher.findMatchingDomain(services, domain) } ?: emptyList()
|
||||
val suggested = domain?.let { DomainMatcher.findSuggestedForDomain(services, domain) }?.minus(matched.toSet()) ?: emptyList()
|
||||
val recommended = matched.plus(suggested)
|
||||
searchQuery.collect { query ->
|
||||
val domain = payload.domain
|
||||
val services = servicesRepository.getServices()
|
||||
.filter {
|
||||
if (query.isNotEmpty()) {
|
||||
it.name.contains(query.trim(), ignoreCase = true) ||
|
||||
it.tags.map { tag -> tag.lowercase() }.contains(query.lowercase())
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
val matched = domain?.let { DomainMatcher.findMatchingDomain(services, domain) } ?: emptyList()
|
||||
val suggested =
|
||||
domain?.let { DomainMatcher.findSuggestedForDomain(services, domain) }?.minus(matched.toSet()) ?: emptyList()
|
||||
val recommended = matched.plus(suggested)
|
||||
|
||||
uiState.update { state ->
|
||||
state.copy(
|
||||
browserName = browserExtRepository.getPairedBrowser(payload.extensionId).name,
|
||||
domain = payload.domain.orEmpty(),
|
||||
suggestedServices = recommended,
|
||||
otherServices = services.minus(recommended.toSet()),
|
||||
payload = payload,
|
||||
)
|
||||
uiState.update { state ->
|
||||
state.copy(
|
||||
browserName = browserExtRepository.getPairedBrowser(payload.extensionId).name,
|
||||
domain = payload.domain.orEmpty(),
|
||||
suggestedServices = recommended,
|
||||
otherServices = services.minus(recommended.toSet()),
|
||||
payload = payload,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSearchQuery(query: String) {
|
||||
searchQuery.update { query }
|
||||
}
|
||||
|
||||
fun assignDomain(service: Service) {
|
||||
launchScoped {
|
||||
if (uiState.value.saveMyChoice) {
|
||||
|
@ -1,8 +1,5 @@
|
||||
package com.twofasapp.feature.home.ui.editservice.changebrand
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
@ -10,7 +7,6 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
@ -22,18 +18,11 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@ -42,25 +31,16 @@ import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
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.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.twofasapp.designsystem.TwIcons
|
||||
import com.twofasapp.designsystem.TwTheme
|
||||
import com.twofasapp.designsystem.common.TwTopAppBar
|
||||
import com.twofasapp.designsystem.common.TopAppBarWithSearch
|
||||
import com.twofasapp.designsystem.dialog.ListDialog
|
||||
import com.twofasapp.designsystem.ktx.LocalBackDispatcher
|
||||
import com.twofasapp.feature.home.ui.editservice.EditServiceViewModel
|
||||
@ -86,7 +66,7 @@ internal fun ChangeBrandScreen(
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
ToolbarWithSearch(
|
||||
TopAppBarWithSearch(
|
||||
title = stringResource(id = R.string.customization_change_brand),
|
||||
searchHint = stringResource(id = R.string.commons__search),
|
||||
onSearchValueChanged = { brandViewModel.applySearchFilter(it) },
|
||||
@ -269,127 +249,3 @@ fun SectionHeader(header: String) {
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ToolbarWithSearch(
|
||||
title: String,
|
||||
searchHint: String = "",
|
||||
modifier: Modifier = Modifier,
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
onSearchValueChanged: (String) -> Unit = {},
|
||||
navigationClick: () -> Unit
|
||||
) {
|
||||
val showSearch = remember { mutableStateOf(false) }
|
||||
|
||||
TwTopAppBar(title = {
|
||||
if (showSearch.value) {
|
||||
SearchBar(hint = searchHint, showSearch = showSearch, onValueChanged = onSearchValueChanged)
|
||||
} else {
|
||||
Text(text = title, color = TwTheme.color.onSurfacePrimary)
|
||||
}
|
||||
}, navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
if (showSearch.value) {
|
||||
showSearch.value = false
|
||||
onSearchValueChanged("")
|
||||
} else {
|
||||
navigationClick.invoke()
|
||||
}
|
||||
}) {
|
||||
Icon(TwIcons.ArrowBack, null, tint = TwTheme.color.onSurfacePrimary)
|
||||
}
|
||||
}, actions = {
|
||||
if (showSearch.value.not()) {
|
||||
IconButton(onClick = { showSearch.value = true }) {
|
||||
Icon(TwIcons.Search, null, tint = TwTheme.color.primary)
|
||||
}
|
||||
}
|
||||
actions()
|
||||
}, modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
value: String = "",
|
||||
hint: String = "",
|
||||
showSearch: MutableState<Boolean>,
|
||||
onValueChanged: (String) -> Unit = {},
|
||||
onClearClick: () -> Unit = {},
|
||||
) {
|
||||
val textValue = remember { mutableStateOf(value) }
|
||||
val showClearButton = remember { mutableStateOf(false) }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
if (showSearch.value) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.height(56.dp)
|
||||
.fillMaxWidth()
|
||||
.onFocusChanged { focusState ->
|
||||
showClearButton.value = focusState.isFocused
|
||||
}
|
||||
.focusRequester(focusRequester),
|
||||
value = textValue.value,
|
||||
onValueChange = {
|
||||
textValue.value = it
|
||||
onValueChanged(it)
|
||||
},
|
||||
placeholder = {
|
||||
Text(text = hint, style = MaterialTheme.typography.bodyMedium.copy(fontSize = 18.sp))
|
||||
},
|
||||
textStyle = MaterialTheme.typography.bodyMedium.copy(fontSize = 18.sp),
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedTextColor = TwTheme.color.onSurfacePrimary,
|
||||
disabledTextColor = Color.Black,
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
focusedLabelColor = TwTheme.color.onSurfaceSecondary,
|
||||
unfocusedLabelColor = TwTheme.color.onSurfaceSecondary,
|
||||
errorLabelColor = TwTheme.color.error,
|
||||
),
|
||||
trailingIcon = {
|
||||
AnimatedVisibility(
|
||||
visible = showClearButton.value,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
IconButton(onClick = {
|
||||
if (textValue.value.isNotEmpty()) {
|
||||
textValue.value = ""
|
||||
onValueChanged("")
|
||||
} else {
|
||||
showClearButton.value = false
|
||||
showSearch.value = false
|
||||
focusManager.clearFocus()
|
||||
keyboardController?.hide()
|
||||
}
|
||||
|
||||
onClearClick()
|
||||
}) {
|
||||
Icon(
|
||||
painter = TwIcons.Close,
|
||||
tint = TwTheme.color.onSurfacePrimary,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
maxLines = 1,
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = {
|
||||
keyboardController?.hide()
|
||||
}),
|
||||
)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
} else {
|
||||
textValue.value = ""
|
||||
onValueChanged("")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user