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) suspend fun deleteTool(tool: ToolEntity)
@Query("SELECT * FROM tools WHERE id = :id") @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") @Query("SELECT * FROM tools ORDER BY updateTime DESC")
fun selectAllTools(): Flow<List<ToolEntity>> fun selectAllTools(): Flow<List<ToolEntity>>

View File

@@ -48,6 +48,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.LoadState import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import kotlinx.coroutines.flow.StateFlow
import top.fatweb.oxygen.toolbox.R import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.Loading import top.fatweb.oxygen.toolbox.icon.Loading
import top.fatweb.oxygen.toolbox.icon.OxygenIcons import top.fatweb.oxygen.toolbox.icon.OxygenIcons
@@ -70,6 +71,7 @@ internal fun ToolStoreRoute(
modifier = modifier, modifier = modifier,
onNavigateToToolView = onNavigateToToolView, onNavigateToToolView = onNavigateToToolView,
toolStorePagingItems = toolStorePagingItems, toolStorePagingItems = toolStorePagingItems,
hasInstalled = { viewModel.hasInstalled(it) },
onChangeInstallStatus = viewModel::changeInstallStatus, onChangeInstallStatus = viewModel::changeInstallStatus,
onInstallTool = viewModel::installTool, onInstallTool = viewModel::installTool,
installInfo = installInfo installInfo = installInfo
@@ -81,6 +83,7 @@ internal fun ToolStoreScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onNavigateToToolView: (username: String, toolId: String) -> Unit, onNavigateToToolView: (username: String, toolId: String) -> Unit,
toolStorePagingItems: LazyPagingItems<ToolEntity>, toolStorePagingItems: LazyPagingItems<ToolEntity>,
hasInstalled: (ToolEntity) -> StateFlow<Boolean>,
onChangeInstallStatus: (installStatus: ToolStoreUiState.Status, username: String?, toolId: String?) -> Unit, onChangeInstallStatus: (installStatus: ToolStoreUiState.Status, username: String?, toolId: String?) -> Unit,
onInstallTool: () -> Unit, onInstallTool: () -> Unit,
installInfo: ToolStoreUiState.InstallInfo installInfo: ToolStoreUiState.InstallInfo
@@ -110,6 +113,7 @@ internal fun ToolStoreScreen(
) { ) {
toolsPanel( toolsPanel(
toolStorePagingItems = toolStorePagingItems, toolStorePagingItems = toolStorePagingItems,
hasInstalled = hasInstalled,
onAction = { username, toolId -> onAction = { username, toolId ->
onChangeInstallStatus( onChangeInstallStatus(
ToolStoreUiState.Status.Pending, ToolStoreUiState.Status.Pending,
@@ -270,6 +274,7 @@ internal fun ToolStoreScreen(
private fun LazyStaggeredGridScope.toolsPanel( private fun LazyStaggeredGridScope.toolsPanel(
toolStorePagingItems: LazyPagingItems<ToolEntity>, toolStorePagingItems: LazyPagingItems<ToolEntity>,
hasInstalled: (ToolEntity) -> StateFlow<Boolean>,
onAction: (username: String, toolId: String) -> Unit, onAction: (username: String, toolId: String) -> Unit,
onClick: (username: String, toolId: String) -> Unit onClick: (username: String, toolId: String) -> Unit
) { ) {
@@ -277,9 +282,10 @@ private fun LazyStaggeredGridScope.toolsPanel(
items = toolStorePagingItems.itemSnapshotList, items = toolStorePagingItems.itemSnapshotList,
key = { it!!.id }, key = { it!!.id },
) { ) {
val installed by hasInstalled(it!!).collectAsState()
ToolCard( ToolCard(
tool = it!!, tool = it!!,
actionIcon = OxygenIcons.Download, actionIcon = if (installed) null else OxygenIcons.Download,
actionIconContentDescription = stringResource(R.string.core_install), actionIconContentDescription = stringResource(R.string.core_install),
onAction = { onAction(it.authorUsername, it.toolId) }, onAction = { onAction(it.authorUsername, it.toolId) },
onClick = { onClick(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 dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow 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.combine
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import top.fatweb.oxygen.toolbox.model.Result 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.StoreRepository
import top.fatweb.oxygen.toolbox.repository.tool.ToolRepository import top.fatweb.oxygen.toolbox.repository.tool.ToolRepository
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@HiltViewModel @HiltViewModel
class ToolStoreViewModel @Inject constructor( class ToolStoreViewModel @Inject constructor(
@@ -27,6 +33,11 @@ class ToolStoreViewModel @Inject constructor(
) : ViewModel() { ) : ViewModel() {
private val searchValue = savedStateHandle.getStateFlow(SEARCH_VALUE, "") private val searchValue = savedStateHandle.getStateFlow(SEARCH_VALUE, "")
private val currentPage = savedStateHandle.getStateFlow(CURRENT_PAGE, 1) 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( val installInfo = savedStateHandle.getStateFlow(
INSTALL_INFO, ToolStoreUiState.InstallInfo() INSTALL_INFO, ToolStoreUiState.InstallInfo()
) )
@@ -35,9 +46,27 @@ class ToolStoreViewModel @Inject constructor(
val storeData: Flow<PagingData<ToolEntity>> = combine( val storeData: Flow<PagingData<ToolEntity>> = combine(
searchValue, currentPage, ::Pair searchValue, currentPage, ::Pair
).flatMapLatest { (searchValue, currentPage) -> ).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( fun changeInstallStatus(
installStatus: ToolStoreUiState.Status, username: String?, toolId: String? installStatus: ToolStoreUiState.Status, username: String?, toolId: String?
) { ) {
@@ -60,6 +89,12 @@ class ToolStoreViewModel @Inject constructor(
toolRepository.saveTool(it.data) toolRepository.saveTool(it.data)
savedStateHandle[INSTALL_INFO] = savedStateHandle[INSTALL_INFO] =
ToolStoreUiState.InstallInfo(ToolStoreUiState.Status.Success) 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 SEARCH_VALUE = "searchValue"
private const val CURRENT_PAGE = "currentPage" private const val CURRENT_PAGE = "currentPage"
private const val INSTALLED_STATUS = "installedStatus"
private const val INSTALL_INFO = "installInfo" private const val INSTALL_INFO = "installInfo"