diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/tool/dao/ToolDao.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/tool/dao/ToolDao.kt index 8974b93..3c6f54d 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/tool/dao/ToolDao.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/tool/dao/ToolDao.kt @@ -21,7 +21,7 @@ interface ToolDao { suspend fun deleteTool(tool: ToolEntity) @Query("SELECT * FROM tools WHERE id = :id") - fun selectToolById(id: Long): Flow + fun selectToolById(id: Long): Flow @Query("SELECT * FROM tools ORDER BY updateTime DESC") fun selectAllTools(): Flow> diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreScreen.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreScreen.kt index 94caf7e..a146c6b 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreScreen.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreScreen.kt @@ -48,6 +48,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.paging.LoadState import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems +import kotlinx.coroutines.flow.StateFlow import top.fatweb.oxygen.toolbox.R import top.fatweb.oxygen.toolbox.icon.Loading import top.fatweb.oxygen.toolbox.icon.OxygenIcons @@ -70,6 +71,7 @@ internal fun ToolStoreRoute( modifier = modifier, onNavigateToToolView = onNavigateToToolView, toolStorePagingItems = toolStorePagingItems, + hasInstalled = { viewModel.hasInstalled(it) }, onChangeInstallStatus = viewModel::changeInstallStatus, onInstallTool = viewModel::installTool, installInfo = installInfo @@ -81,6 +83,7 @@ internal fun ToolStoreScreen( modifier: Modifier = Modifier, onNavigateToToolView: (username: String, toolId: String) -> Unit, toolStorePagingItems: LazyPagingItems, + hasInstalled: (ToolEntity) -> StateFlow, onChangeInstallStatus: (installStatus: ToolStoreUiState.Status, username: String?, toolId: String?) -> Unit, onInstallTool: () -> Unit, installInfo: ToolStoreUiState.InstallInfo @@ -110,6 +113,7 @@ internal fun ToolStoreScreen( ) { toolsPanel( toolStorePagingItems = toolStorePagingItems, + hasInstalled = hasInstalled, onAction = { username, toolId -> onChangeInstallStatus( ToolStoreUiState.Status.Pending, @@ -270,6 +274,7 @@ internal fun ToolStoreScreen( private fun LazyStaggeredGridScope.toolsPanel( toolStorePagingItems: LazyPagingItems, + hasInstalled: (ToolEntity) -> StateFlow, onAction: (username: String, toolId: String) -> Unit, onClick: (username: String, toolId: String) -> Unit ) { @@ -277,9 +282,10 @@ private fun LazyStaggeredGridScope.toolsPanel( items = toolStorePagingItems.itemSnapshotList, key = { it!!.id }, ) { + val installed by hasInstalled(it!!).collectAsState() ToolCard( tool = it!!, - actionIcon = OxygenIcons.Download, + actionIcon = if (installed) null else OxygenIcons.Download, actionIconContentDescription = stringResource(R.string.core_install), onAction = { onAction(it.authorUsername, it.toolId) }, onClick = { onClick(it.authorUsername, it.toolId) }, diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreViewModel.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreViewModel.kt index 4925d6d..e762e45 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreViewModel.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/tool/ToolStoreViewModel.kt @@ -9,8 +9,13 @@ import androidx.paging.cachedIn import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import top.fatweb.oxygen.toolbox.model.Result @@ -18,6 +23,7 @@ import top.fatweb.oxygen.toolbox.model.tool.ToolEntity import top.fatweb.oxygen.toolbox.repository.tool.StoreRepository import top.fatweb.oxygen.toolbox.repository.tool.ToolRepository import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds @HiltViewModel class ToolStoreViewModel @Inject constructor( @@ -27,6 +33,11 @@ class ToolStoreViewModel @Inject constructor( ) : ViewModel() { private val searchValue = savedStateHandle.getStateFlow(SEARCH_VALUE, "") private val currentPage = savedStateHandle.getStateFlow(CURRENT_PAGE, 1) + private val installedStatus = + savedStateHandle.getStateFlow>>( + INSTALLED_STATUS, + mutableMapOf() + ) val installInfo = savedStateHandle.getStateFlow( INSTALL_INFO, ToolStoreUiState.InstallInfo() ) @@ -35,9 +46,27 @@ class ToolStoreViewModel @Inject constructor( val storeData: Flow> = combine( searchValue, currentPage, ::Pair ).flatMapLatest { (searchValue, currentPage) -> - storeRepository.getStore(searchValue, currentPage).cachedIn(viewModelScope) + storeRepository.getStore(searchValue, currentPage).cachedIn( + scope = viewModelScope + ) } + fun hasInstalled(toolEntity: ToolEntity): StateFlow = + installedStatus.value[toolEntity.authorUsername]?.get(toolEntity.toolId)?.let { MutableStateFlow(it) } + ?: toolRepository.getToolByUsernameAndToolId(toolEntity.authorUsername, toolEntity.toolId).map { + if (installedStatus.value[toolEntity.authorUsername] == null) { + installedStatus.value[toolEntity.authorUsername] = + mutableMapOf(toolEntity.toolId to (it != null)) + } else { + installedStatus.value[toolEntity.authorUsername]?.set(toolEntity.toolId, it != null) + } + it != null + }.stateIn( + scope = viewModelScope, + initialValue = true, + started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds) + ) + fun changeInstallStatus( installStatus: ToolStoreUiState.Status, username: String?, toolId: String? ) { @@ -60,6 +89,12 @@ class ToolStoreViewModel @Inject constructor( toolRepository.saveTool(it.data) savedStateHandle[INSTALL_INFO] = ToolStoreUiState.InstallInfo(ToolStoreUiState.Status.Success) + if (installedStatus.value[username] == null) { + installedStatus.value[username] = + mutableMapOf(toolId to true) + } else { + installedStatus.value[username]?.set(toolId, true) + } } } } @@ -85,4 +120,5 @@ data class ToolStoreUiState( private const val SEARCH_VALUE = "searchValue" private const val CURRENT_PAGE = "currentPage" +private const val INSTALLED_STATUS = "installedStatus" private const val INSTALL_INFO = "installInfo"