diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/components/compose/scan/QrCodeScannerScreen.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/components/compose/scan/QrCodeScannerScreen.kt index 3aa2e0236..db120028f 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/components/compose/scan/QrCodeScannerScreen.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/components/compose/scan/QrCodeScannerScreen.kt @@ -49,14 +49,14 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.PathOperation import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension import jp.co.soramitsu.common.R import jp.co.soramitsu.common.presentation.compose.uikit.tokens.ScreenStatus import jp.co.soramitsu.common.presentation.compose.uikit.tokens.Text -import jp.co.soramitsu.common.presentation.compose.uikit.tokens.retrieveString import jp.co.soramitsu.ui_core.component.button.BleachedButton import jp.co.soramitsu.ui_core.component.button.FilledButton import jp.co.soramitsu.ui_core.component.button.properties.Order @@ -71,15 +71,6 @@ data class QRCodeScannerScreenState( val screenStatus: ScreenStatus, val throwable: Throwable? ) { - - val toolbarTitleText: Text = Text.StringRes(id = R.string.common_scan_qr) - - val uploadFromGalleryButtonText: Text = Text.StringRes(id = R.string.common_upload_from_library) - - val showMyQrButtonText: Text = Text.StringRes(id = R.string.scan_qr_show_my_qr) - - val isErrorTextVisible: Boolean = screenStatus === ScreenStatus.ERROR - val errorText: Text get() = throwable?.message?.let { Text.SimpleText(it) @@ -88,7 +79,6 @@ data class QRCodeScannerScreenState( @Composable fun QrCodeScannerScreen( - state: QRCodeScannerScreenState, onNavIconClick: () -> Unit, onUploadFromGalleryClick: () -> Unit, onShowUserQrClick: () -> Unit @@ -122,14 +112,14 @@ fun QrCodeScannerScreen( SoramitsuToolbar( state = SoramitsuToolbarState( basic = BasicToolbarState( - title = state.toolbarTitleText.retrieveString(), + title = R.string.common_scan_qr, navIcon = R.drawable.ic_close, ), type = SoramitsuToolbarType.SmallCentered() ), backgroundColor = blurCameraBackground, - elevation = Dp(0f), - onNavigate = onNavIconClick + elevation = 0.dp, + onNavigate = onNavIconClick, ) } @@ -262,7 +252,7 @@ fun QrCodeScannerScreen( ), size = Size.Large, order = Order.SECONDARY, - text = state.uploadFromGalleryButtonText.retrieveString(), + text = stringResource(id = R.string.common_upload_from_library), onClick = onUploadFromGalleryClick ) @@ -283,7 +273,7 @@ fun QrCodeScannerScreen( ), size = Size.Large, order = Order.SECONDARY, - text = state.showMyQrButtonText.retrieveString(), + text = stringResource(id = R.string.scan_qr_show_my_qr), onClick = onShowUserQrClick ) } @@ -301,10 +291,6 @@ private fun PreviewQrCodeScannerScreen() { contentDescription = "" ) QrCodeScannerScreen( - state = QRCodeScannerScreenState( - screenStatus = ScreenStatus.READY_TO_RENDER, - throwable = null - ), onNavIconClick = {}, onUploadFromGalleryClick = {}, onShowUserQrClick = {} diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListFragment.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListFragment.kt index b9e72f3aa..b5aac4c1e 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListFragment.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListFragment.kt @@ -55,13 +55,14 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import com.google.accompanist.navigation.animation.composable @@ -72,10 +73,6 @@ import jp.co.soramitsu.common.base.theOnlyRoute import jp.co.soramitsu.common.domain.BottomBarController import jp.co.soramitsu.common_wallet.presentation.compose.components.AssetItem import jp.co.soramitsu.feature_assets_impl.presentation.components.compose.assetslist.CommonAssetsList -import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbar -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import jp.co.soramitsu.ui_core.resources.Dimens import jp.co.soramitsu.ui_core.theme.customColors import jp.co.soramitsu.ui_core.theme.customTypography @@ -86,6 +83,9 @@ class FullAssetListFragment : SoraBaseFragment() { override val viewModel: FullAssetListViewModel by viewModels() override fun backgroundColor(): Int = R.attr.baseBackgroundSecond + @Composable + override fun backgroundColorComposable() = MaterialTheme.customColors.bgSurface + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) (activity as BottomBarController).hideBottomBar() @@ -104,23 +104,7 @@ class FullAssetListFragment : SoraBaseFragment() { .background(MaterialTheme.customColors.bgSurface) .fillMaxSize() ) { - SoramitsuToolbar( - state = SoramitsuToolbarState( - basic = BasicToolbarState( - title = "", - navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_cross_24, - actionLabel = R.string.common_edit, - searchValue = "", - ), - type = SoramitsuToolbarType.Small(), - ), - backgroundColor = MaterialTheme.customColors.bgSurface, - elevation = 0.dp, - onAction = viewModel::onAction, - onNavigate = viewModel::onNavIcon, - onSearch = viewModel::searchAssets, - ) - val state = viewModel.state + val state = viewModel.state.collectAsStateWithLifecycle() Row( modifier = Modifier .padding( @@ -142,7 +126,7 @@ class FullAssetListFragment : SoraBaseFragment() { ) Text( modifier = Modifier.weight(1f), - text = state.fiatSum, + text = state.value.fiatSum, textAlign = TextAlign.End, style = MaterialTheme.customTypography.headline2, color = MaterialTheme.customColors.fgPrimary, @@ -154,7 +138,7 @@ class FullAssetListFragment : SoraBaseFragment() { .fillMaxSize() ) { androidx.compose.animation.AnimatedVisibility( - visible = state.searchMode.not(), + visible = state.value.searchMode.not(), enter = fadeIn(), exit = fadeOut(), ) { @@ -164,24 +148,24 @@ class FullAssetListFragment : SoraBaseFragment() { .verticalScroll(scrollState), ) { CommonAssetsList( - state = state, + state = state.value, onAssetClick = viewModel::onAssetClick, ) } } androidx.compose.animation.AnimatedVisibility( - visible = state.searchMode, + visible = state.value.searchMode, enter = fadeIn(), exit = fadeOut(), ) { val listState = rememberLazyListState() LazyColumn(state = listState, modifier = Modifier.fillMaxSize()) { items( - count = state.topList.size + state.bottomList.size + 1, + count = state.value.topList.size + state.value.bottomList.size + 1, key = null, - contentType = { p -> if (p == state.topList.size) 0 else 1 }, + contentType = { p -> if (p == state.value.topList.size) 0 else 1 }, ) { position -> - if (position == state.topList.size) { + if (position == state.value.topList.size) { Text( text = stringResource(id = R.string.global_results).uppercase(), style = MaterialTheme.customTypography.headline4, @@ -189,7 +173,7 @@ class FullAssetListFragment : SoraBaseFragment() { ) } else { val item = - if (position < state.topList.size) state.topList[position] else state.bottomList[position - state.topList.size - 1] + if (position < state.value.topList.size) state.value.topList[position] else state.value.bottomList[position - state.value.topList.size - 1] AssetItem( assetState = item, testTag = "", diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListViewModel.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListViewModel.kt index 04663d8a0..6e2c01496 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListViewModel.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetlist/FullAssetListViewModel.kt @@ -33,7 +33,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_assets_impl.presentation.screens.fullassetlist import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -49,7 +48,12 @@ import jp.co.soramitsu.common_wallet.presentation.compose.states.mapAssetsToCard import jp.co.soramitsu.feature_assets_api.domain.AssetsInteractor import jp.co.soramitsu.feature_assets_api.presentation.AssetsRouter import jp.co.soramitsu.feature_assets_impl.presentation.states.FullAssetListState +import jp.co.soramitsu.ui_core.R +import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.debounce @@ -68,10 +72,20 @@ class FullAssetListViewModel @Inject constructor( private val visAssets = mutableListOf() private val filter = MutableStateFlow("") - var state by mutableStateOf(FullAssetListState(false, "", emptyList(), emptyList())) - private set + private val _state = MutableStateFlow(FullAssetListState(false, "", emptyList(), emptyList())) + val state = _state.asStateFlow() init { + _toolbarState.value = SoramitsuToolbarState( + basic = BasicToolbarState( + title = "", + navIcon = R.drawable.ic_cross_24, + actionLabel = jp.co.soramitsu.common.R.string.common_edit, + searchValue = "", + searchEnabled = true, + ), + type = SoramitsuToolbarType.Small(), + ) viewModelScope.launch { allAssets.addAll(assetsInteractor.getWhitelistAssets()) launch { @@ -92,6 +106,10 @@ class FullAssetListViewModel @Inject constructor( } } + override fun onToolbarSearch(value: String) { + filter.value = value + } + private fun calcState(filter: String) { val idMap = visAssets.map { t -> t.token.id } val excluded = allAssets.filter { it.token.id !in idMap } @@ -101,7 +119,7 @@ class FullAssetListViewModel @Inject constructor( val group = visAssets.groupBy { (it.fiat ?: 0.0) >= thresholdBalance } - state = state.copy( + _state.value = _state.value.copy( searchMode = false, topList = mapAssetsToCardState( group[true] ?: emptyList(), @@ -122,7 +140,7 @@ class FullAssetListViewModel @Inject constructor( val bottomFilter = invisibleAssets.filter { it.token.isMatchFilter(filter) } val topSum = topFilter.fiatSum() val bottomSum = bottomFilter.fiatSum() - state = state.copy( + _state.value = _state.value.copy( searchMode = true, topList = mapAssetsToCardState(topFilter, numbersFormatter), bottomList = mapAssetsToCardState(bottomFilter, numbersFormatter), @@ -135,10 +153,6 @@ class FullAssetListViewModel @Inject constructor( } } - fun searchAssets(search: String) { - filter.value = search - } - override fun onAction() { assetsRouter.showFullAssetsSettings() } diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsFragment.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsFragment.kt index f2f385293..9b1d91592 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsFragment.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsFragment.kt @@ -43,13 +43,14 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.recyclerview.widget.DividerItemDecoration @@ -63,10 +64,6 @@ import jp.co.soramitsu.common.presentation.view.WrappedRecyclerView import jp.co.soramitsu.common.view.CustomItemTouchHelperCallback import jp.co.soramitsu.common_wallet.R as polkaswapR import jp.co.soramitsu.feature_assets_impl.presentation.components.classic.AssetsManagementAdapter -import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbar -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import jp.co.soramitsu.ui_core.resources.Dimens import jp.co.soramitsu.ui_core.theme.customColors import jp.co.soramitsu.ui_core.theme.customTypography @@ -77,6 +74,9 @@ class FullAssetSettingsFragment : SoraBaseFragment() override val viewModel: FullAssetSettingsViewModel by viewModels() override fun backgroundColor(): Int = R.attr.baseBackgroundSecond + @Composable + override fun backgroundColorComposable() = MaterialTheme.customColors.bgSurface + private val itemTouchHelperCallback = CustomItemTouchHelperCallback { from, to -> viewModel.assetPositionChanged(from, to) } @@ -95,25 +95,6 @@ class FullAssetSettingsFragment : SoraBaseFragment() .background(MaterialTheme.customColors.bgSurface) .fillMaxSize() ) { - SoramitsuToolbar( - state = SoramitsuToolbarState( - basic = BasicToolbarState( - title = "", - navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_cross_24, - actionLabel = R.string.common_done, - searchValue = "", - ), - type = SoramitsuToolbarType.Small(), - ), - backgroundColor = MaterialTheme.customColors.bgSurface, - elevation = 0.dp, - onAction = viewModel::onCloseClick, - onNavigate = viewModel::onCloseClick, - onSearch = { - viewModel.searchAssets(it) - itemTouchHelperCallback.isDraggable = it.isBlank() - }, - ) Row( modifier = Modifier .padding( @@ -134,7 +115,7 @@ class FullAssetSettingsFragment : SoraBaseFragment() ) Text( modifier = Modifier, - text = viewModel.fiatSum, + text = viewModel.fiatSum.collectAsStateWithLifecycle().value, style = MaterialTheme.customTypography.headline2, color = MaterialTheme.customColors.fgPrimary, ) @@ -170,6 +151,9 @@ class FullAssetSettingsFragment : SoraBaseFragment() viewModel::onFavoriteClick, viewModel::onVisibilityClick, ) + viewModel.dragList.observe { + itemTouchHelperCallback.isDraggable = it + } viewModel.settingsState.observe { (view.list.adapter as AssetsManagementAdapter).submitList( buildList { diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsViewModel.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsViewModel.kt index 8c1591f65..36df9daa6 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsViewModel.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/fullassetsettings/FullAssetSettingsViewModel.kt @@ -33,7 +33,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_assets_impl.presentation.screens.fullassetsettings import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -49,6 +48,12 @@ import jp.co.soramitsu.common.util.NumbersFormatter import jp.co.soramitsu.feature_assets_api.domain.AssetsInteractor import jp.co.soramitsu.feature_assets_api.presentation.AssetsRouter import jp.co.soramitsu.feature_assets_impl.presentation.states.AssetSettingsState +import jp.co.soramitsu.ui_core.R +import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch @HiltViewModel @@ -61,15 +66,30 @@ class FullAssetSettingsViewModel @Inject constructor( private val _settingsState = MutableLiveData>() val settingsState: LiveData> = _settingsState + private val _dragList = MutableLiveData() + val dragList: LiveData = _dragList + private val curAssetList = mutableListOf() private var positions = mutableListOf() private var curFilter: String = "" private val tokensToMove = mutableListOf>() private var symbol: String = "" - internal var fiatSum by mutableStateOf("") + private val _fiatSum = MutableStateFlow("") + val fiatSum = _fiatSum.asStateFlow() init { + _toolbarState.value = SoramitsuToolbarState( + basic = BasicToolbarState( + title = "", + navIcon = R.drawable.ic_cross_24, + actionLabel = jp.co.soramitsu.common.R.string.common_done, + searchValue = "", + searchEnabled = true, + ), + type = SoramitsuToolbarType.Small(), + ) + viewModelScope.launch { curAssetList.clear() curAssetList.addAll( @@ -97,6 +117,20 @@ class FullAssetSettingsViewModel @Inject constructor( } } + override fun onToolbarSearch(value: String) { + _dragList.value = value.isBlank() + curFilter = value + filterAndUpdateAssetsList() + } + + override fun onAction() { + onCloseClick() + } + + override fun onNavIcon() { + onCloseClick() + } + private fun filterAndUpdateAssetsList() { val filter = curFilter.lowercase() val list = if (filter.isBlank()) { @@ -111,17 +145,12 @@ class FullAssetSettingsViewModel @Inject constructor( } } _settingsState.value = list - fiatSum = if (list.isNotEmpty()) + _fiatSum.value = if (list.isNotEmpty()) list.map { it.fiat ?: 0.0 }.reduce { acc, d -> acc + d }.let { formatFiatAmount(it, symbol, numbersFormatter) } else "" } - fun searchAssets(filter: String) { - curFilter = filter - filterAndUpdateAssetsList() - } - fun onFavoriteClick(asset: AssetSettingsState) { val checked = asset.favorite.not() val position = curAssetList.indexOfFirst { it.token.id == asset.token.id } @@ -176,7 +205,7 @@ class FullAssetSettingsViewModel @Inject constructor( } } - fun onCloseClick() { + private fun onCloseClick() { val unknownVisibleCount = curAssetList.count { it.favorite && !AssetHolder.isKnownAsset(it.token.id) } val position = AssetHolder.knownCount() + unknownVisibleCount diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/scan/QRCodeScannerActivity.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/scan/QRCodeScannerActivity.kt index c37151b61..8fcf8aff6 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/scan/QRCodeScannerActivity.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/scan/QRCodeScannerActivity.kt @@ -53,6 +53,7 @@ import androidx.lifecycle.repeatOnLifecycle import com.google.zxing.client.android.Intents import com.journeyapps.barcodescanner.CaptureManager import dagger.hilt.android.AndroidEntryPoint +import jp.co.soramitsu.common.presentation.compose.uikit.tokens.ScreenStatus import jp.co.soramitsu.common.presentation.compose.uikit.tokens.retrieveString import jp.co.soramitsu.feature_assets_impl.databinding.QrCodeScannerLayoutBinding import jp.co.soramitsu.feature_assets_impl.presentation.components.compose.scan.QrCodeScannerScreen @@ -131,10 +132,9 @@ class QRCodeScannerActivity : AppCompatActivity() { setContent { MaterialTheme { QrCodeScannerScreen( - state = viewModel.qrCodeScannerScreenState, onNavIconClick = ::finish, onUploadFromGalleryClick = ::selectQrFromGallery, - onShowUserQrClick = ::finish + onShowUserQrClick = ::finish, ) } } @@ -158,7 +158,7 @@ class QRCodeScannerActivity : AppCompatActivity() { lifecycleScope.launch { repeatOnLifecycle(state = Lifecycle.State.STARTED) { snapshotFlow { viewModel.qrCodeScannerScreenState }.collectLatest { state -> - if (state.isErrorTextVisible) { + if (state.screenStatus == ScreenStatus.ERROR) { Toast.makeText( this@QRCodeScannerActivity, state.errorText.retrieveString( diff --git a/feature_assets_impl/src/test/java/jp/co/soramitsu/feature_assets_impl/presentation/assetsettings/AssetSettingsViewModelTest.kt b/feature_assets_impl/src/test/java/jp/co/soramitsu/feature_assets_impl/presentation/assetsettings/AssetSettingsViewModelTest.kt index d44a3d11f..a6fdbba3f 100644 --- a/feature_assets_impl/src/test/java/jp/co/soramitsu/feature_assets_impl/presentation/assetsettings/AssetSettingsViewModelTest.kt +++ b/feature_assets_impl/src/test/java/jp/co/soramitsu/feature_assets_impl/presentation/assetsettings/AssetSettingsViewModelTest.kt @@ -146,7 +146,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[6]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOn(listOf("token2_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 5, 6) @@ -168,7 +168,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[2]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOn(listOf("0x0200050000000000000000000000000000000000000000000000000000000000")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 6, 7) @@ -193,7 +193,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[5]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 5, 6) @@ -221,7 +221,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[8]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token4_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 6, 7) @@ -241,7 +241,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[8]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOn(listOf("token4_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 5, 6) @@ -269,7 +269,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[8]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOn(listOf("token4_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.mapIndexed { index, s -> s to index }.toMap() verify(assetsInteractor).updateAssetPositions(map) @@ -283,7 +283,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[6]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token2_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 6, 7) @@ -304,7 +304,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[7]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token3_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 7, 8) @@ -328,7 +328,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[7]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token3_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 7, 8) @@ -356,7 +356,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[8]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token4_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.mapIndexed { index, s -> s to index }.toMap() verify(assetsInteractor).updateAssetPositions(map) @@ -391,7 +391,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[8]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token4_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.mapIndexed { index, s -> s to index }.toMap() verify(assetsInteractor).updateAssetPositions(map) @@ -411,7 +411,7 @@ class AssetSettingsViewModelTest { viewModel.onFavoriteClick(mappedModels[6]) advanceUntilIdle() verify(assetsInteractor).tokenFavoriteOff(listOf("token2_id")) - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() val map = list.map { it.token.id }.let { Collections.swap(it, 7, 8) @@ -446,7 +446,7 @@ class AssetSettingsViewModelTest { @Test fun `click back`() = runTest { setUpStartList() - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() verify(router).popBackStackFragment() } @@ -454,7 +454,7 @@ class AssetSettingsViewModelTest { @Test fun `click done`() = runTest { setUpStartList() - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() verify(router).popBackStackFragment() } @@ -465,7 +465,7 @@ class AssetSettingsViewModelTest { val mappedModels = mapModels(list) viewModel.onFavoriteClick(mappedModels[0]) advanceUntilIdle() - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() verify(router).popBackStackFragment() } @@ -478,7 +478,7 @@ class AssetSettingsViewModelTest { advanceUntilIdle() viewModel.onFavoriteClick(mappedModels[1]) advanceUntilIdle() - viewModel.onCloseClick() + viewModel.onAction() advanceUntilIdle() verify(router).popBackStackFragment() } diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/EcoSystemTokensState.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/EcoSystemTokensState.kt index 0f4c6e00b..afe997e93 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/EcoSystemTokensState.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/EcoSystemTokensState.kt @@ -39,20 +39,16 @@ import jp.co.soramitsu.common_wallet.presentation.compose.states.assetItemCardSt internal data class EcoSystemTokensState( val topTokens: List>, - val filter: String, ) internal val initialEcoSystemTokensState = EcoSystemTokensState( topTokens = List(5) { i -> (i + 1).toString() to assetItemCardStateEmpty }, - filter = "", ) internal data class EcoSystemPoolsState( val pools: List, - val filter: String, ) internal val initialEcoSystemPoolsState = EcoSystemPoolsState( pools = List(5) { i -> basicPoolListItemStateEmpty }, - filter = "", ) diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesScreen.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesScreen.kt index 60ddbebd0..43aa31694 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesScreen.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesScreen.kt @@ -33,72 +33,50 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_ecosystem_impl.presentation.allcurrencies import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import jp.co.soramitsu.common.R import jp.co.soramitsu.common.presentation.compose.components.ContentCardEndless import jp.co.soramitsu.common_wallet.presentation.compose.components.AssetItemEnumerated import jp.co.soramitsu.common_wallet.presentation.compose.states.previewAssetItemCardStateList import jp.co.soramitsu.feature_ecosystem_impl.presentation.EcoSystemTokensState -import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbar -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import jp.co.soramitsu.ui_core.resources.Dimens @Composable internal fun AllCurrenciesScreen( + searchState: String, onTokenClicked: (String) -> Unit, - onNavClicked: () -> Unit, viewModel: AllCurrenciesViewModel = hiltViewModel(), ) { + LaunchedEffect(searchState) { + viewModel.onSearch(searchState) + } Column(modifier = Modifier.fillMaxSize()) { val state = viewModel.state.collectAsStateWithLifecycle().value AllCurrenciesInternal( state = state, - onNavIconClicked = onNavClicked, - onSearch = viewModel::onSearch, onTokenClicked = onTokenClicked, ) } } @Composable -private fun ColumnScope.AllCurrenciesInternal( +private fun AllCurrenciesInternal( state: EcoSystemTokensState, - onNavIconClicked: () -> Unit, - onSearch: (String) -> Unit, onTokenClicked: (String) -> Unit, ) { - SoramitsuToolbar( - state = SoramitsuToolbarState( - basic = BasicToolbarState( - title = R.string.common_currencies, - navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_arrow_left, - searchValue = state.filter, - ), - type = SoramitsuToolbarType.Small(), - ), - elevation = 0.dp, - onNavigate = onNavIconClicked, - onSearch = onSearch, - ) ContentCardEndless( modifier = Modifier .padding(start = Dimens.x2, end = Dimens.x2, top = Dimens.x2) - .fillMaxWidth() - .weight(1f), + .fillMaxSize(), innerPadding = PaddingValues(all = Dimens.x2), ) { val listState = rememberLazyListState() @@ -127,9 +105,7 @@ private fun PreviewAllCurrenciesInternal() { previewAssetItemCardStateList.mapIndexed { q, w -> q.toString() to w }, - "", ), - {}, {}, {}, - ) + ) {} } } diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesViewModel.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesViewModel.kt index 27e601b33..09bd13fa4 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesViewModel.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allcurrencies/AllCurrenciesViewModel.kt @@ -83,7 +83,7 @@ internal class AllCurrenciesViewModel @Inject constructor( val indexInAll = positions?.get(it.second.tokenId).orEmpty() indexInAll to it.second } - EcoSystemTokensState(mappedEnumerated, pair.second) + EcoSystemTokensState(mappedEnumerated) } .flowOn(coroutineManager.io) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialEcoSystemTokensState) diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsScreen.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsScreen.kt index 19e89c684..00e2e4c99 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsScreen.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsScreen.kt @@ -33,79 +33,51 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_ecosystem_impl.presentation.allpools import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import jp.co.soramitsu.common.R import jp.co.soramitsu.common.presentation.compose.components.ContentCardEndless import jp.co.soramitsu.common.util.StringPair import jp.co.soramitsu.common_wallet.presentation.compose.BasicPoolListItem import jp.co.soramitsu.common_wallet.presentation.compose.previewBasicPoolListItemState import jp.co.soramitsu.feature_ecosystem_impl.presentation.EcoSystemPoolsState -import jp.co.soramitsu.ui_core.component.toolbar.Action -import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbar -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import jp.co.soramitsu.ui_core.resources.Dimens @Composable internal fun AllPoolsScreen( + searchState: String, onPoolClicked: (StringPair) -> Unit, - onNavClicked: () -> Unit, - onPoolPlus: () -> Unit, viewModel: AllPoolsViewModel = hiltViewModel(), ) { + LaunchedEffect(searchState) { + viewModel.onSearch(searchState) + } Column(modifier = Modifier.fillMaxSize()) { val state = viewModel.poolsState.collectAsStateWithLifecycle().value AllPoolsInternal( state = state, - onNavIconClicked = onNavClicked, - onSearch = viewModel::onSearch, onPoolClicked = onPoolClicked, - onPoolPlus = onPoolPlus, ) } } @Composable -private fun ColumnScope.AllPoolsInternal( +private fun AllPoolsInternal( state: EcoSystemPoolsState, - onNavIconClicked: () -> Unit, - onSearch: (String) -> Unit, onPoolClicked: (StringPair) -> Unit, - onPoolPlus: () -> Unit, ) { - SoramitsuToolbar( - state = SoramitsuToolbarState( - basic = BasicToolbarState( - title = R.string.discovery_polkaswap_pools, - menu = listOf(Action.Plus()), - navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_arrow_left, - searchValue = state.filter, - ), - type = SoramitsuToolbarType.Small(), - ), - elevation = 0.dp, - onNavigate = onNavIconClicked, - onSearch = onSearch, - onMenuItemClicked = { onPoolPlus.invoke() }, - ) ContentCardEndless( modifier = Modifier .padding(start = Dimens.x2, end = Dimens.x2, top = Dimens.x2) - .fillMaxWidth() - .weight(1f), + .fillMaxSize(), innerPadding = PaddingValues(all = Dimens.x2), ) { val listState = rememberLazyListState() @@ -130,12 +102,8 @@ private fun PreviewAllPoolsInternal() { AllPoolsInternal( state = EcoSystemPoolsState( pools = previewBasicPoolListItemState, - filter = "", ), - onNavIconClicked = {}, - onSearch = {}, onPoolClicked = {}, - onPoolPlus = {}, ) } } diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsViewModel.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsViewModel.kt index 88846dd50..9ada953ed 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsViewModel.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/allpools/AllPoolsViewModel.kt @@ -88,7 +88,6 @@ internal class AllPoolsViewModel @Inject constructor( } EcoSystemPoolsState( pools = mappedEnumerated, - filter = pair.second, ) } .flowOn(coroutineManager.io) diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt index 9912dfb87..0cdd12399 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt @@ -35,6 +35,7 @@ package jp.co.soramitsu.feature_ecosystem_impl.presentation.explore import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.ScrollState import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import com.google.accompanist.navigation.animation.composable @@ -86,18 +87,19 @@ class ExploreFragment : SoraBaseFragment() { composable( route = ExploreRoutes.ALL_CURRENCIES, ) { + val searchState = viewModel.searchState.collectAsStateWithLifecycle() AllCurrenciesScreen( + searchState = searchState.value, onTokenClicked = viewModel::onTokenClicked, - onNavClicked = { navController.popBackStack() }, ) } composable( route = ExploreRoutes.ALL_POOLS, ) { + val searchState = viewModel.searchState.collectAsStateWithLifecycle() AllPoolsScreen( + searchState = searchState.value, onPoolClicked = viewModel::onPoolClicked, - onNavClicked = { navController.popBackStack() }, - onPoolPlus = viewModel::onPoolPlus, ) } } diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt index d1b1f4cdf..1ff8ace89 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt @@ -34,12 +34,19 @@ package jp.co.soramitsu.feature_ecosystem_impl.presentation.explore import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import jp.co.soramitsu.common.R import jp.co.soramitsu.common.presentation.viewmodel.BaseViewModel import jp.co.soramitsu.common.util.StringPair import jp.co.soramitsu.feature_assets_api.presentation.AssetsRouter import jp.co.soramitsu.feature_ecosystem_impl.presentation.ExploreRoutes import jp.co.soramitsu.feature_polkaswap_api.launcher.PolkaswapRouter import jp.co.soramitsu.sora.substrate.runtime.SubstrateOptionsProvider +import jp.co.soramitsu.ui_core.component.toolbar.Action +import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow @HiltViewModel class ExploreViewModel @Inject constructor( @@ -47,8 +54,73 @@ class ExploreViewModel @Inject constructor( private val assetsRouter: AssetsRouter, ) : BaseViewModel() { + private val _searchState = MutableStateFlow("") + val searchState = _searchState.asStateFlow() + + init { + _toolbarState.value = SoramitsuToolbarState( + type = SoramitsuToolbarType.Small(), + basic = BasicToolbarState( + title = "", + navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_arrow_left, + visibility = false, + searchEnabled = false, + ), + ) + } + override fun startScreen(): String = ExploreRoutes.START + override fun onMenuItem(action: Action) { + when (action) { + is Action.Plus -> { + onPoolPlus() + } + else -> {} + } + } + + override fun onCurrentDestinationChanged(curDest: String) { + _toolbarState.value?.let { state -> + when (curDest) { + ExploreRoutes.ALL_POOLS -> { + _toolbarState.value = state.copy( + basic = state.basic.copy( + visibility = true, + title = R.string.discovery_polkaswap_pools, + searchEnabled = true, + searchValue = _searchState.value, + menu = listOf(Action.Plus()), + ) + ) + } + ExploreRoutes.ALL_CURRENCIES -> { + _toolbarState.value = state.copy( + basic = state.basic.copy( + visibility = true, + title = R.string.common_currencies, + searchEnabled = true, + searchValue = _searchState.value, + menu = emptyList(), + ) + ) + } + else -> { + _toolbarState.value = state.copy( + basic = state.basic.copy( + visibility = false, + searchEnabled = false, + ) + ) + } + } + } + } + + override fun onToolbarSearch(value: String) { + _searchState.value = value + } + fun onTokenClicked(tokenId: String) { assetsRouter.showAssetDetails(tokenId) } @@ -57,7 +129,7 @@ class ExploreViewModel @Inject constructor( polkaswapRouter.showPoolDetails(pool) } - fun onPoolPlus() { + private fun onPoolPlus() { polkaswapRouter.showAddLiquidity(SubstrateOptionsProvider.feeAssetId) } } diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreen.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreen.kt index 89b9c0faa..d23b653fe 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreen.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreen.kt @@ -156,11 +156,9 @@ private fun DiscoverScreenPreview() { previewAssetItemCardStateList.mapIndexed { i, a -> i.toString() to a }, - "", ), EcoSystemPoolsState( previewBasicPoolListItemState, - "", ), {}, {}, {}, {}, ) diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreenViewModel.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreenViewModel.kt index 2672a05c9..eb09f3137 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreenViewModel.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/start/StartScreenViewModel.kt @@ -80,7 +80,7 @@ internal class StartScreenViewModel @Inject constructor( ) } .map { - EcoSystemTokensState(ecoSystemMapper.mapEcoSystemTokens(it), "") + EcoSystemTokensState(ecoSystemMapper.mapEcoSystemTokens(it)) } .flowOn(coroutineManager.io) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialEcoSystemTokensState) @@ -97,7 +97,6 @@ internal class StartScreenViewModel @Inject constructor( .map { EcoSystemPoolsState( pools = ecoSystemMapper.mapEcoSystemPools(it), - filter = "", ) } .flowOn(coroutineManager.io) diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/components/classic/PoolsManagementAdapter.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/components/classic/PoolsManagementAdapter.kt index b6cc18b32..3202f5d1b 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/components/classic/PoolsManagementAdapter.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/components/classic/PoolsManagementAdapter.kt @@ -85,7 +85,7 @@ class PoolViewHolder( fun bind(asset: PoolSettingsState) { assetIcon.load(asset.token1Icon) asset2Icon.load(asset.token2Icon) - title.text = asset.tokenName + title.text = asset.tokenSymbol amount.text = asset.assetAmount favoriteIcon.setImageResource(if (asset.favorite) R.drawable.ic_favorite_enabled else R.drawable.ic_favorite_disabled) diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListFragment.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListFragment.kt index a0dfd4c10..312e985e3 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListFragment.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListFragment.kt @@ -48,12 +48,13 @@ import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import com.google.accompanist.navigation.animation.composable @@ -63,10 +64,6 @@ import jp.co.soramitsu.common.base.SoraBaseFragment import jp.co.soramitsu.common.base.theOnlyRoute import jp.co.soramitsu.common.domain.BottomBarController import jp.co.soramitsu.common_wallet.presentation.compose.components.PoolsList -import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbar -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import jp.co.soramitsu.ui_core.resources.Dimens import jp.co.soramitsu.ui_core.theme.customColors import jp.co.soramitsu.ui_core.theme.customTypography @@ -77,6 +74,9 @@ class FullPoolListFragment : SoraBaseFragment() { override val viewModel: FullPoolListViewModel by viewModels() override fun backgroundColor(): Int = R.attr.baseBackgroundSecond + @Composable + override fun backgroundColorComposable() = MaterialTheme.customColors.bgSurface + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) (activity as BottomBarController).hideBottomBar() @@ -95,23 +95,7 @@ class FullPoolListFragment : SoraBaseFragment() { .background(MaterialTheme.customColors.bgSurface) .fillMaxSize() ) { - SoramitsuToolbar( - state = SoramitsuToolbarState( - basic = BasicToolbarState( - title = "", - navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_cross_24, - actionLabel = R.string.common_edit, - searchValue = "", - ), - type = SoramitsuToolbarType.Small(), - ), - backgroundColor = MaterialTheme.customColors.bgSurface, - elevation = 0.dp, - onAction = viewModel::onAction, - onNavigate = viewModel::onNavIcon, - onSearch = viewModel::searchAssets, - ) - val state = viewModel.state + val state = viewModel.state.collectAsStateWithLifecycle() Row( modifier = Modifier .padding( @@ -133,7 +117,7 @@ class FullPoolListFragment : SoraBaseFragment() { ) Text( modifier = Modifier.weight(1f), - text = state.fiatSum, + text = state.value.fiatSum, textAlign = TextAlign.End, style = MaterialTheme.customTypography.headline2, color = MaterialTheme.customColors.fgPrimary, @@ -145,7 +129,7 @@ class FullPoolListFragment : SoraBaseFragment() { .verticalScroll(scrollState) ) { PoolsList( - cardState = state.list, + cardState = state.value.list, onPoolClick = viewModel::onPoolClick, ) } diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListViewModel.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListViewModel.kt index ac163ce4c..60c5a6366 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListViewModel.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoollist/FullPoolListViewModel.kt @@ -33,7 +33,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_polkaswap_impl.presentation.screens.fullpoollist import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -50,7 +49,12 @@ import jp.co.soramitsu.common_wallet.presentation.compose.states.mapPoolsData import jp.co.soramitsu.feature_polkaswap_api.domain.interfaces.PoolsInteractor import jp.co.soramitsu.feature_polkaswap_api.launcher.PolkaswapRouter import jp.co.soramitsu.feature_polkaswap_impl.presentation.states.FullPoolListState +import jp.co.soramitsu.ui_core.R +import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.debounce @@ -66,15 +70,25 @@ class FullPoolListViewModel @Inject constructor( private val allPools = mutableListOf() private val filter = MutableStateFlow("") - internal var state by mutableStateOf( + private val _state = MutableStateFlow( FullPoolListState( "", PoolsListState(emptyList()) ) ) - private set + internal val state = _state.asStateFlow() init { + _toolbarState.value = SoramitsuToolbarState( + type = SoramitsuToolbarType.Small(), + basic = BasicToolbarState( + title = "", + navIcon = R.drawable.ic_cross_24, + visibility = true, + searchEnabled = true, + actionLabel = jp.co.soramitsu.common.R.string.common_edit, + ), + ) viewModelScope.launch { poolsInteractor.subscribePoolsCacheOfCurAccount() .catch { onError(it) } @@ -93,11 +107,15 @@ class FullPoolListViewModel @Inject constructor( } } + override fun onToolbarSearch(value: String) { + filter.value = value + } + private fun calcState(filter: String) { val filtered = if (filter.isBlank()) allPools else allPools.filter { it.basic.isFilterMatch(filter) } val data = mapPoolsData(filtered, numbersFormatter) - state = state.copy( + _state.value = _state.value.copy( list = data.first, fiatSum = formatFiatAmount( data.second, @@ -107,10 +125,6 @@ class FullPoolListViewModel @Inject constructor( ) } - fun searchAssets(search: String) { - filter.value = search - } - override fun onAction() { polkaswapRouter.showFullPoolsSettings() } diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsFragment.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsFragment.kt index 155caee54..b1dc5ef74 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsFragment.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsFragment.kt @@ -43,13 +43,14 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.recyclerview.widget.DividerItemDecoration @@ -63,10 +64,6 @@ import jp.co.soramitsu.common.presentation.view.WrappedRecyclerView import jp.co.soramitsu.common.view.CustomItemTouchHelperCallback import jp.co.soramitsu.common_wallet.R as polkaswapR import jp.co.soramitsu.feature_polkaswap_impl.presentation.components.classic.PoolsManagementAdapter -import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbar -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState -import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType import jp.co.soramitsu.ui_core.resources.Dimens import jp.co.soramitsu.ui_core.theme.customColors import jp.co.soramitsu.ui_core.theme.customTypography @@ -77,6 +74,9 @@ class FullPoolSettingsFragment : SoraBaseFragment() { override val viewModel: FullPoolSettingsViewModel by viewModels() override fun backgroundColor(): Int = R.attr.baseBackgroundSecond + @Composable + override fun backgroundColorComposable() = MaterialTheme.customColors.bgSurface + private val itemTouchHelperCallback = CustomItemTouchHelperCallback { from, to -> viewModel.assetPositionChanged(from, to) } @@ -95,25 +95,6 @@ class FullPoolSettingsFragment : SoraBaseFragment() { .background(MaterialTheme.customColors.bgSurface) .fillMaxSize() ) { - SoramitsuToolbar( - state = SoramitsuToolbarState( - basic = BasicToolbarState( - title = "", - navIcon = jp.co.soramitsu.ui_core.R.drawable.ic_cross_24, - actionLabel = R.string.common_done, - searchValue = "", - ), - type = SoramitsuToolbarType.Small(), - ), - backgroundColor = MaterialTheme.customColors.bgSurface, - elevation = 0.dp, - onAction = viewModel::onCloseClick, - onNavigate = viewModel::onCloseClick, - onSearch = { - viewModel.searchAssets(it) - itemTouchHelperCallback.isDraggable = it.isBlank() - }, - ) Row( modifier = Modifier .padding( @@ -134,7 +115,7 @@ class FullPoolSettingsFragment : SoraBaseFragment() { ) Text( modifier = Modifier, - text = viewModel.fiatSum, + text = viewModel.fiatSum.collectAsStateWithLifecycle().value, style = MaterialTheme.customTypography.headline2, color = MaterialTheme.customColors.fgPrimary, ) @@ -176,6 +157,9 @@ class FullPoolSettingsFragment : SoraBaseFragment() { } ) } + viewModel.dragList.observe { + itemTouchHelperCallback.isDraggable = it + } viewModel.assetPositions.observe { (view.list.adapter as PoolsManagementAdapter).notifyItemMoved( it.first, diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsViewModel.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsViewModel.kt index 5ab536a50..fd81977c7 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsViewModel.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/fullpoolsettings/FullPoolSettingsViewModel.kt @@ -33,7 +33,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_polkaswap_impl.presentation.screens.fullpoolsettings import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -51,6 +50,12 @@ import jp.co.soramitsu.common_wallet.domain.model.fiatSymbol import jp.co.soramitsu.feature_polkaswap_api.domain.interfaces.PoolsInteractor import jp.co.soramitsu.feature_polkaswap_impl.presentation.states.PoolSettingsState import jp.co.soramitsu.feature_wallet_api.launcher.WalletRouter +import jp.co.soramitsu.ui_core.R +import jp.co.soramitsu.ui_core.component.toolbar.BasicToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarState +import jp.co.soramitsu.ui_core.component.toolbar.SoramitsuToolbarType +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch @HiltViewModel @@ -66,14 +71,28 @@ class FullPoolSettingsViewModel @Inject constructor( private val _assetPositions = MutableLiveData>() val assetPositions: LiveData> = _assetPositions + private val _dragList = MutableLiveData() + val dragList: LiveData = _dragList + private val curPoolList = mutableListOf() private var positions = mutableListOf() private var curFilter: String = "" private var symbol: String = "" - internal var fiatSum by mutableStateOf("") + private val _fiatSum = MutableStateFlow("") + internal val fiatSum = _fiatSum.asStateFlow() init { + _toolbarState.value = SoramitsuToolbarState( + type = SoramitsuToolbarType.Small(), + basic = BasicToolbarState( + title = "", + navIcon = R.drawable.ic_cross_24, + visibility = true, + searchEnabled = true, + actionLabel = jp.co.soramitsu.common.R.string.common_done, + ), + ) viewModelScope.launch { val pools: List = poolsInteractor.getPoolsCacheOfCurAccount() @@ -85,6 +104,10 @@ class FullPoolSettingsViewModel @Inject constructor( token1Icon = poolData.basic.baseToken.iconUri(), token2Icon = poolData.basic.targetToken.iconUri(), tokenName = "%s-%s".format( + poolData.basic.baseToken.name, + poolData.basic.targetToken.name, + ), + tokenSymbol = "%s-%s".format( poolData.basic.baseToken.symbol, poolData.basic.targetToken.symbol, ), @@ -119,6 +142,7 @@ class FullPoolSettingsViewModel @Inject constructor( addAll( curPoolList.filter { it.tokenName.lowercase().contains(filter) || + it.tokenSymbol.lowercase().contains(filter) || it.assetAmount.lowercase().contains(filter) || it.id.first.lowercase().contains(filter) || it.id.second.lowercase().contains(filter) @@ -128,14 +152,15 @@ class FullPoolSettingsViewModel @Inject constructor( } _settingsState.value = list - fiatSum = if (list.isNotEmpty()) + _fiatSum.value = if (list.isNotEmpty()) list.map { it.fiat }.reduce { acc, d -> acc + d }.let { formatFiatAmount(it, symbol, numbersFormatter) } else "" } - fun searchAssets(filter: String) { - curFilter = filter + override fun onToolbarSearch(value: String) { + _dragList.value = value.isBlank() + curFilter = value filterAndUpdateAssetsList() } @@ -163,7 +188,11 @@ class FullPoolSettingsViewModel @Inject constructor( return true } - fun onCloseClick() { + override fun onAction() { + walletRouter.popBackStackFragment() + } + + override fun onNavIcon() { walletRouter.popBackStackFragment() } diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/swap/SwapViewModel.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/swap/SwapViewModel.kt index abb8e143e..230102682 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/swap/SwapViewModel.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/screens/swap/SwapViewModel.kt @@ -422,6 +422,12 @@ class SwapViewModel @AssistedInject constructor( fun fromCardClicked() { if (assetsList.isNotEmpty()) { + val filtered = assetsList.filter { + it.token.id != _swapMainState.value.tokenToState?.token?.id.orEmpty() + } + _swapTokensFilter.value = _swapTokensFilter.value.copy( + tokenIds = filtered.map { it.token.id } + ) _swapMainState.value = _swapMainState.value.copy( tokenFromState = _swapMainState.value.tokenFromState?.copy( initialAmount = _swapMainState.value.tokenFromState?.amount?.nullZero(), @@ -435,6 +441,12 @@ class SwapViewModel @AssistedInject constructor( fun toCardClicked() { if (assetsList.isNotEmpty()) { + val filtered = assetsList.filter { + it.token.id != _swapMainState.value.tokenFromState?.token?.id.orEmpty() + } + _swapTokensFilter.value = _swapTokensFilter.value.copy( + tokenIds = filtered.map { it.token.id } + ) _swapMainState.value = _swapMainState.value.copy( tokenFromState = _swapMainState.value.tokenFromState?.copy( initialAmount = _swapMainState.value.tokenFromState?.amount?.nullZero(), diff --git a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/states/PoolSettingsState.kt b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/states/PoolSettingsState.kt index 75152fb7d..fd8b4032c 100644 --- a/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/states/PoolSettingsState.kt +++ b/feature_polkaswap_impl/src/main/java/jp/co/soramitsu/feature_polkaswap_impl/presentation/states/PoolSettingsState.kt @@ -40,6 +40,7 @@ data class PoolSettingsState( val token1Icon: Uri, val token2Icon: Uri, val tokenName: String, + val tokenSymbol: String, val assetAmount: String, val favorite: Boolean, val fiat: Double,