diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultRenameWalletComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultRenameWalletComponent.kt index 051fef6074..351905ddc0 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultRenameWalletComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultRenameWalletComponent.kt @@ -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 = 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( diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt new file mode 100644 index 0000000000..2579a58329 --- /dev/null +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt @@ -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 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)) + } +} \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewRenameWalletComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewRenameWalletComponent.kt index 12834f5b0d..b56f10f749 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewRenameWalletComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewRenameWalletComponent.kt @@ -12,7 +12,7 @@ internal class PreviewRenameWalletComponent : RenameWalletComponent { walletNameValue = TextFieldValue(text = "My Wallet"), isConfirmEnabled = false, onValueChange = {}, - onConfirm = {}, + onConfirmClick = {}, error = null, ) diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/ComponentModule.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt similarity index 94% rename from features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/ComponentModule.kt rename to features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt index 90ff4e1255..f3cc276efa 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/ComponentModule.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsComponentModule.kt @@ -12,7 +12,7 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -internal interface ComponentModule { +internal interface WalletSettingsComponentModule { @Binds @Singleton diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/ModelModule.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt similarity index 59% rename from features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/ModelModule.kt rename to features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt index f7c93024a5..6cc2cd67eb 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/ModelModule.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt @@ -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 } \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/RenameWalletUM.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/RenameWalletUM.kt index 23549c9809..d30be7ece0 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/RenameWalletUM.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/RenameWalletUM.kt @@ -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?, ) \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/RenameWalletDialog.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/RenameWalletDialog.kt index 0d32c07b9e..11d76500bd 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/RenameWalletDialog.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/RenameWalletDialog.kt @@ -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),