Refactor(ToolStore): Support dynamic display tool installation button
This commit is contained in:
@@ -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>>
|
||||||
|
|||||||
@@ -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) },
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user