Refactor(ToolStore): Optimize the way to obtain installation status

This commit is contained in:
2024-08-13 18:04:49 +08:00
parent 60ffc569a5
commit 5246715d78
7 changed files with 41 additions and 53 deletions

View File

@@ -47,9 +47,10 @@ data class ToolEntity(
val updateTime: LocalDateTime,
@ColumnInfo(defaultValue = "false")
val isStar: Boolean = false,
val isInstalled: Boolean = false,
@ColumnInfo(defaultValue = "NULL")
val upgrade: String? = null
) {

View File

@@ -2,13 +2,16 @@ package top.fatweb.oxygen.toolbox.network.paging
import androidx.paging.PagingSource
import androidx.paging.PagingState
import kotlinx.coroutines.flow.first
import top.fatweb.oxygen.toolbox.data.network.OxygenNetworkDataSource
import top.fatweb.oxygen.toolbox.data.tool.dao.ToolDao
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
import top.fatweb.oxygen.toolbox.network.model.ToolVo
import top.fatweb.oxygen.toolbox.network.model.asExternalModel
internal class ToolStorePagingSource(
private val oxygenNetworkDataSource: OxygenNetworkDataSource,
private val toolDao: ToolDao,
private val searchValue: String
) : PagingSource<Int, ToolEntity>() {
override fun getRefreshKey(state: PagingState<Int, ToolEntity>): Int? = null
@@ -25,7 +28,20 @@ internal class ToolStorePagingSource(
val nextPage = if (currentPage < pages) currentPage + 1 else null
LoadResult.Page(
data = records.map(ToolVo::asExternalModel),
data = records.map(ToolVo::asExternalModel).map { toolEntity ->
toolDao.selectToolByUsernameAndToolId(
toolEntity.authorUsername,
toolEntity.toolId
).first()?.let {
if (it.id == toolEntity.id) {
it
} else {
it.copy(upgrade = toolEntity.ver).also { copy ->
toolDao.updateTool(copy)
}
}
} ?: toolEntity
},
prevKey = null,
nextKey = nextPage
)

View File

@@ -6,6 +6,7 @@ import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import top.fatweb.oxygen.toolbox.data.network.OxygenNetworkDataSource
import top.fatweb.oxygen.toolbox.data.tool.dao.ToolDao
import top.fatweb.oxygen.toolbox.model.Result
import top.fatweb.oxygen.toolbox.model.asExternalModel
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
@@ -19,7 +20,8 @@ import javax.inject.Inject
private const val PAGE_SIZE = 20
internal class NetworkStoreRepository @Inject constructor(
private val oxygenNetworkDataSource: OxygenNetworkDataSource
private val oxygenNetworkDataSource: OxygenNetworkDataSource,
private val toolDao: ToolDao
) : StoreRepository {
override suspend fun getStore(
@@ -28,7 +30,13 @@ internal class NetworkStoreRepository @Inject constructor(
): Flow<PagingData<ToolEntity>> =
Pager(
config = PagingConfig(PAGE_SIZE),
pagingSourceFactory = { ToolStorePagingSource(oxygenNetworkDataSource, searchValue) }
pagingSourceFactory = {
ToolStorePagingSource(
oxygenNetworkDataSource,
toolDao,
searchValue
)
}
).flow
override fun detail(

View File

@@ -24,7 +24,7 @@ class OfflineToolRepository @Inject constructor(
toolDao.selectToolByUsernameAndToolId(username, toolId)
override suspend fun saveTool(toolEntity: ToolEntity) =
toolDao.insertTool(toolEntity)
toolDao.insertTool(toolEntity.copy(isInstalled = true))
override suspend fun updateTool(toolEntity: ToolEntity) =
toolDao.updateTool(toolEntity)

View File

@@ -51,7 +51,6 @@ 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
@@ -74,7 +73,6 @@ internal fun ToolStoreRoute(
modifier = modifier,
onNavigateToToolView = onNavigateToToolView,
toolStorePagingItems = toolStorePagingItems,
hasInstalled = { viewModel.hasInstalled(it) },
onChangeInstallStatus = viewModel::changeInstallStatus,
onInstallTool = viewModel::installTool,
installInfo = installInfo
@@ -86,7 +84,6 @@ internal fun ToolStoreScreen(
modifier: Modifier = Modifier,
onNavigateToToolView: (username: String, toolId: String) -> Unit,
toolStorePagingItems: LazyPagingItems<ToolEntity>,
hasInstalled: (ToolEntity) -> StateFlow<Boolean>,
onChangeInstallStatus: (installStatus: ToolStoreUiState.Status) -> Unit,
onInstallTool: (username: String, toolId: String) -> Unit,
installInfo: ToolStoreUiState.InstallInfo
@@ -119,7 +116,6 @@ internal fun ToolStoreScreen(
) {
toolsPanel(
toolStorePagingItems = toolStorePagingItems,
hasInstalled = hasInstalled,
onAction = { username, toolId ->
installToolUsername = username
installToolId = toolId
@@ -179,7 +175,6 @@ 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
) {
@@ -187,10 +182,9 @@ private fun LazyStaggeredGridScope.toolsPanel(
items = toolStorePagingItems.itemSnapshotList,
key = { it!!.id },
) {
val installed by hasInstalled(it!!).collectAsState()
ToolCard(
tool = it!!,
actionIcon = if (installed) null else OxygenIcons.Download,
actionIcon = if (!it.isInstalled) OxygenIcons.Download else null,
actionIconContentDescription = stringResource(R.string.core_install),
onAction = { onAction(it.authorUsername, it.toolId) },
onClick = { onClick(it.authorUsername, it.toolId) },

View File

@@ -9,13 +9,8 @@ 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
@@ -23,7 +18,6 @@ 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(
@@ -33,10 +27,6 @@ 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())
@OptIn(ExperimentalCoroutinesApi::class)
@@ -48,26 +38,6 @@ class ToolStoreViewModel @Inject constructor(
)
}
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) {
savedStateHandle[INSTALL_INFO] = ToolStoreUiState.InstallInfo(installStatus)
}
@@ -86,11 +56,6 @@ 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)
}
}
}
}
@@ -114,5 +79,4 @@ 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"