diff --git a/app/schemas/top.fatweb.oxygen.toolbox.data.tool.ToolDatabase/1.json b/app/schemas/top.fatweb.oxygen.toolbox.data.tool.ToolDatabase/1.json index 92901bc..13eff18 100644 --- a/app/schemas/top.fatweb.oxygen.toolbox.data.tool.ToolDatabase/1.json +++ b/app/schemas/top.fatweb.oxygen.toolbox.data.tool.ToolDatabase/1.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "adfae7fd1829b1afdfd27eb282388074", + "identityHash": "34c5a37d790e5542a93e0dc27bb3f4f1", "entities": [ { "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `toolId` TEXT NOT NULL, `icon` TEXT NOT NULL, `platform` TEXT NOT NULL, `description` TEXT, `base` TEXT, `authorUsername` TEXT NOT NULL, `authorNickname` TEXT NOT NULL, `authorAvatar` TEXT NOT NULL, `ver` TEXT NOT NULL, `keywords` TEXT NOT NULL, `categories` TEXT NOT NULL, `source` TEXT, `dist` TEXT, `entryPoint` TEXT NOT NULL, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL, `isStar` INTEGER NOT NULL DEFAULT false, `upgrade` TEXT DEFAULT NULL, PRIMARY KEY(`id`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `toolId` TEXT NOT NULL, `icon` TEXT NOT NULL, `platform` TEXT NOT NULL, `description` TEXT, `base` TEXT, `authorUsername` TEXT NOT NULL, `authorNickname` TEXT NOT NULL, `authorAvatar` TEXT NOT NULL, `ver` TEXT NOT NULL, `keywords` TEXT NOT NULL, `categories` TEXT NOT NULL, `source` TEXT, `dist` TEXT, `entryPoint` TEXT NOT NULL, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL, `isStar` INTEGER NOT NULL, `isInstalled` INTEGER NOT NULL, `upgrade` TEXT DEFAULT NULL, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", @@ -120,8 +120,13 @@ "fieldPath": "isStar", "columnName": "isStar", "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" + "notNull": true + }, + { + "fieldPath": "isInstalled", + "columnName": "isInstalled", + "affinity": "INTEGER", + "notNull": true }, { "fieldPath": "upgrade", @@ -144,7 +149,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'adfae7fd1829b1afdfd27eb282388074')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '34c5a37d790e5542a93e0dc27bb3f4f1')" ] } } \ No newline at end of file diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/tool/ToolEntity.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/tool/ToolEntity.kt index 8e2ee4e..87c6b38 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/tool/ToolEntity.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/tool/ToolEntity.kt @@ -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 ) { diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/network/paging/ToolStorePagingSource.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/network/paging/ToolStorePagingSource.kt index 0e5ae6f..371274f 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/network/paging/ToolStorePagingSource.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/network/paging/ToolStorePagingSource.kt @@ -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() { override fun getRefreshKey(state: PagingState): 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 ) diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/NetworkStoreRepository.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/NetworkStoreRepository.kt index 6386d71..e8296a1 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/NetworkStoreRepository.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/NetworkStoreRepository.kt @@ -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> = Pager( config = PagingConfig(PAGE_SIZE), - pagingSourceFactory = { ToolStorePagingSource(oxygenNetworkDataSource, searchValue) } + pagingSourceFactory = { + ToolStorePagingSource( + oxygenNetworkDataSource, + toolDao, + searchValue + ) + } ).flow override fun detail( diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/OfflineToolRepository.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/OfflineToolRepository.kt index 06cd6ed..80e8ce5 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/OfflineToolRepository.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/tool/impl/OfflineToolRepository.kt @@ -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) 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 49f98f6..f9638f2 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 @@ -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, - hasInstalled: (ToolEntity) -> StateFlow, 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, - hasInstalled: (ToolEntity) -> StateFlow, 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) }, 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 1c3c4df..94a67d9 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,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>>( - 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 = - 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"