Updated on 2026-08-14
This commit is contained in:
parent
c83081cc11
commit
1ca7f17e37
7 changed files with 144 additions and 89 deletions
|
|
@ -2,110 +2,32 @@ package com.tangem.feature.walletsettings.component.impl
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetWalletNamesUseCase
|
||||
import com.tangem.domain.wallets.usecase.RenameWalletUseCase
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.feature.walletsettings.component.RenameWalletComponent
|
||||
import com.tangem.feature.walletsettings.entity.RenameWalletUM
|
||||
import com.tangem.feature.walletsettings.impl.R
|
||||
import com.tangem.feature.walletsettings.component.impl.model.RenameWalletModel
|
||||
import com.tangem.feature.walletsettings.ui.RenameWalletDialog
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultRenameWalletComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: RenameWalletComponent.Params,
|
||||
getWalletNamesUseCase: GetWalletNamesUseCase,
|
||||
private val renameWalletUseCase: RenameWalletUseCase,
|
||||
) : RenameWalletComponent, AppComponentContext by context {
|
||||
|
||||
private val initialName = params.currentName
|
||||
private val walletNames by lazy(getWalletNamesUseCase::invoke)
|
||||
private val model: RenameWalletModel = getOrCreateModel(params)
|
||||
|
||||
private val stateFlow: MutableStateFlow<RenameWalletUM> = MutableStateFlow(
|
||||
value = RenameWalletUM(
|
||||
walletNameValue = TextFieldValue(text = params.currentName),
|
||||
onValueChange = ::updateValue,
|
||||
isConfirmEnabled = false,
|
||||
onConfirm = { renameWallet(params.userWalletId) },
|
||||
error = null,
|
||||
),
|
||||
)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
override fun dismiss() = model.dismiss()
|
||||
|
||||
@Composable
|
||||
override fun Dialog() {
|
||||
val model by stateFlow.collectAsStateWithLifecycle()
|
||||
val model by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
RenameWalletDialog(model = model, onDismiss = ::dismiss)
|
||||
}
|
||||
|
||||
private fun updateValue(value: TextFieldValue) {
|
||||
stateFlow.update {
|
||||
val isNameAlreadyExists = initialName != value.text && walletNames.contains(value.text)
|
||||
|
||||
it.copy(
|
||||
walletNameValue = value,
|
||||
isConfirmEnabled = value.text.isNotBlank() &&
|
||||
value.text != initialName &&
|
||||
!isNameAlreadyExists,
|
||||
error = if (isNameAlreadyExists) {
|
||||
resourceReference(
|
||||
id = R.string.user_wallet_list_rename_popup_error_already_exists,
|
||||
formatArgs = wrappedList(value.text),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renameWallet(userWalletId: UserWalletId) {
|
||||
componentScope.launch {
|
||||
withContext(NonCancellable) {
|
||||
val newName = stateFlow.value.walletNameValue
|
||||
|
||||
renameWalletUseCase(userWalletId, newName.text)
|
||||
.onLeft {
|
||||
Timber.e("Unable to rename wallet: $it")
|
||||
showRenameWalletError(error = it, updatedName = newName.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private fun showRenameWalletError(error: UpdateWalletError, updatedName: String) {
|
||||
val message = when (error) {
|
||||
is UpdateWalletError.DataError -> resourceReference(id = R.string.common_unknown_error)
|
||||
is UpdateWalletError.NameAlreadyExists -> resourceReference(
|
||||
id = R.string.user_wallet_list_rename_popup_error_already_exists,
|
||||
formatArgs = wrappedList(updatedName),
|
||||
)
|
||||
}
|
||||
|
||||
messageSender.send(message = SnackbarMessage(message))
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : RenameWalletComponent.Factory {
|
||||
override fun create(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package com.tangem.feature.walletsettings.component.impl.model
|
||||
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.usecase.GetWalletNamesUseCase
|
||||
import com.tangem.domain.wallets.usecase.RenameWalletUseCase
|
||||
import com.tangem.feature.walletsettings.component.RenameWalletComponent
|
||||
import com.tangem.feature.walletsettings.entity.RenameWalletUM
|
||||
import com.tangem.feature.walletsettings.impl.R
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Rename wallet model
|
||||
*
|
||||
* @param paramsContainer params container
|
||||
* @param getWalletNamesUseCase use case for getting wallets names
|
||||
* @property dispatchers dispatchers
|
||||
* @property renameWalletUseCase use case for renaming the wallet by id
|
||||
* @property uiMessageSender UI message sender
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@ComponentScoped
|
||||
internal class RenameWalletModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
getWalletNamesUseCase: GetWalletNamesUseCase,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val renameWalletUseCase: RenameWalletUseCase,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params: RenameWalletComponent.Params = paramsContainer.require()
|
||||
|
||||
private val initialName = params.currentName
|
||||
private val walletNames by lazy(getWalletNamesUseCase::invoke)
|
||||
|
||||
val state: StateFlow<RenameWalletUM> get() = _state
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
value = RenameWalletUM(
|
||||
walletNameValue = TextFieldValue(text = params.currentName),
|
||||
onValueChange = ::onValueChange,
|
||||
isConfirmEnabled = false,
|
||||
onConfirmClick = ::onConfirmClick,
|
||||
error = null,
|
||||
),
|
||||
)
|
||||
|
||||
fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
private fun onValueChange(value: TextFieldValue) {
|
||||
_state.update {
|
||||
val newName = value.text
|
||||
|
||||
it.copy(
|
||||
walletNameValue = value,
|
||||
isConfirmEnabled = getConfirmButtonAvailability(newName),
|
||||
error = getErrorOrNull(newName),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmButtonAvailability(newName: String): Boolean {
|
||||
return newName.isNotBlank() && newName != initialName && !isNameAlreadyExists(newName)
|
||||
}
|
||||
|
||||
private fun getErrorOrNull(newName: String): TextReference? {
|
||||
return if (isNameAlreadyExists(newName)) {
|
||||
resourceReference(
|
||||
id = R.string.user_wallet_list_rename_popup_error_already_exists,
|
||||
formatArgs = wrappedList(newName),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNameAlreadyExists(newName: String): Boolean {
|
||||
return initialName != newName && walletNames.contains(newName)
|
||||
}
|
||||
|
||||
private fun onConfirmClick() {
|
||||
modelScope.launch {
|
||||
withContext(NonCancellable) {
|
||||
val newName = _state.value.walletNameValue
|
||||
|
||||
renameWalletUseCase(userWalletId = params.userWalletId, name = newName.text)
|
||||
.onLeft {
|
||||
Timber.e("Unable to rename wallet: $it")
|
||||
showRenameWalletError(error = it, updatedName = newName.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private fun showRenameWalletError(error: UpdateWalletError, updatedName: String) {
|
||||
val message = when (error) {
|
||||
is UpdateWalletError.DataError -> resourceReference(id = R.string.common_unknown_error)
|
||||
is UpdateWalletError.NameAlreadyExists -> resourceReference(
|
||||
id = R.string.user_wallet_list_rename_popup_error_already_exists,
|
||||
formatArgs = wrappedList(updatedName),
|
||||
)
|
||||
}
|
||||
|
||||
uiMessageSender.send(message = SnackbarMessage(message))
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ internal class PreviewRenameWalletComponent : RenameWalletComponent {
|
|||
walletNameValue = TextFieldValue(text = "My Wallet"),
|
||||
isConfirmEnabled = false,
|
||||
onValueChange = {},
|
||||
onConfirm = {},
|
||||
onConfirmClick = {},
|
||||
error = null,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ComponentModule {
|
||||
internal interface WalletSettingsComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.walletsettings.di
|
|||
|
||||
import com.tangem.core.decompose.di.DecomposeComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.feature.walletsettings.component.impl.model.RenameWalletModel
|
||||
import com.tangem.feature.walletsettings.model.WalletSettingsModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
@ -11,10 +12,15 @@ import dagger.multibindings.IntoMap
|
|||
|
||||
@Module
|
||||
@InstallIn(DecomposeComponent::class)
|
||||
internal interface ModelModule {
|
||||
internal interface WalletSettingsModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(WalletSettingsModel::class)
|
||||
fun provideWalletSettingsModel(model: WalletSettingsModel): Model
|
||||
fun bindWalletSettingsModel(model: WalletSettingsModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(RenameWalletModel::class)
|
||||
fun bindRenameWalletModel(model: RenameWalletModel): Model
|
||||
}
|
||||
|
|
@ -9,6 +9,6 @@ internal data class RenameWalletUM(
|
|||
val walletNameValue: TextFieldValue,
|
||||
val onValueChange: (value: TextFieldValue) -> Unit,
|
||||
val isConfirmEnabled: Boolean,
|
||||
val onConfirm: () -> Unit,
|
||||
val onConfirmClick: () -> Unit,
|
||||
val error: TextReference?,
|
||||
)
|
||||
|
|
@ -25,7 +25,7 @@ internal fun RenameWalletDialog(model: RenameWalletUM, onDismiss: () -> Unit) {
|
|||
confirmButton = DialogButtonUM(
|
||||
title = stringResourceSafe(id = R.string.common_ok),
|
||||
enabled = model.isConfirmEnabled,
|
||||
onClick = model.onConfirm,
|
||||
onClick = model.onConfirmClick,
|
||||
),
|
||||
dismissButton = DialogButtonUM(
|
||||
title = stringResourceSafe(id = R.string.common_cancel),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue