Refactor(ToolStore): Support dynamic display tool installation button

This commit is contained in:
2024-08-09 13:49:53 +08:00
parent c9c0debb2b
commit 3286ed2934
3 changed files with 45 additions and 3 deletions

View File

@@ -21,7 +21,7 @@ interface ToolDao {
suspend fun deleteTool(tool: ToolEntity)
@Query("SELECT * FROM tools WHERE id = :id")
fun selectToolById(id: Long): Flow<ToolEntity>
fun selectToolById(id: Long): Flow<ToolEntity?>
@Query("SELECT * FROM tools ORDER BY updateTime DESC")
fun selectAllTools(): Flow<List<ToolEntity>>

View File

@@ -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<ToolEntity>,
hasInstalled: (ToolEntity) -> StateFlow<Boolean>,
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<ToolEntity>,
hasInstalled: (ToolEntity) -> StateFlow<Boolean>,
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) },

View File

@@ -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<MutableMap<String, MutableMap<String, Boolean>>>(
INSTALLED_STATUS,
mutableMapOf()
)
val installInfo = savedStateHandle.getStateFlow(
INSTALL_INFO, ToolStoreUiState.InstallInfo()
)
@@ -35,9 +46,27 @@ class ToolStoreViewModel @Inject constructor(
val storeData: Flow<PagingData<ToolEntity>> = 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<Boolean> =
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"