Feat(ToolStore): Support upgrade tool

This commit is contained in:
2024-08-14 15:26:10 +08:00
parent f5cfbd7296
commit 6732eb6a22
7 changed files with 189 additions and 74 deletions

View File

@@ -13,6 +13,7 @@ import androidx.compose.material.icons.filled.Download
import androidx.compose.material.icons.filled.Inbox
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Reorder
import androidx.compose.material.icons.filled.Upgrade
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.StarBorder
@@ -55,6 +56,7 @@ object OxygenIcons {
val Success = Icons.Rounded.CheckCircle
val Time = Icons.Default.AccessTime
val Tool = Icons.Default.Build
val Upgrade = Icons.Default.Upgrade
@OptIn(ExperimentalEncodingApi::class)
fun fromSvgBase64(base64String: String): ImageBitmap {

View File

@@ -54,6 +54,25 @@ data class ToolEntity(
@ColumnInfo(defaultValue = "NULL")
val upgrade: String? = null
) {
constructor(toolId: String, authorUsername: String, ver: String, upgrade: String? = null) :
this(
id = -1,
name = "Unknown",
toolId = toolId,
icon = "",
platform = Platform.Android,
authorUsername = authorUsername,
authorNickname = "Unknown",
authorAvatar = "",
ver = ver,
keywords = emptyList(),
categories = emptyList(),
entryPoint = "",
createTime = LocalDateTime(1970, 1, 1, 0, 0),
updateTime = LocalDateTime(1970, 1, 1, 0, 0),
upgrade = upgrade
)
enum class Platform {
Web,

View File

@@ -39,6 +39,7 @@ import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
fun ToolCard(
modifier: Modifier = Modifier,
tool: ToolEntity,
specifyVer: String? = null,
actionIcon: ImageVector? = null,
actionIconContentDescription: String = "",
onAction: () -> Unit = {},
@@ -59,7 +60,7 @@ fun ToolCard(
modifier = Modifier.padding(16.dp)
) {
ToolHeader(
ver = tool.ver,
ver = specifyVer ?: tool.ver,
actionIcon = actionIcon,
actionIconContentDescription = actionIconContentDescription,
onAction = onAction

View File

@@ -73,7 +73,10 @@ internal fun ToolStoreRoute(
modifier = modifier,
onNavigateToToolView = onNavigateToToolView,
toolStorePagingItems = toolStorePagingItems,
onChangeInstallStatus = viewModel::changeInstallStatus,
onChangeInstallStatus = viewModel::changeInstallInfo,
onChangeInstallType = {
viewModel.changeInstallInfo(type = it)
},
onInstallTool = viewModel::installTool,
installInfo = installInfo
)
@@ -84,8 +87,9 @@ internal fun ToolStoreScreen(
modifier: Modifier = Modifier,
onNavigateToToolView: (username: String, toolId: String) -> Unit,
toolStorePagingItems: LazyPagingItems<ToolEntity>,
onChangeInstallStatus: (installStatus: ToolStoreUiState.Status) -> Unit,
onInstallTool: (username: String, toolId: String) -> Unit,
onChangeInstallStatus: (status: ToolStoreUiState.InstallInfo.Status) -> Unit,
onChangeInstallType: (type: ToolStoreUiState.InstallInfo.Type) -> Unit,
onInstallTool: (installTool: ToolEntity) -> Unit,
installInfo: ToolStoreUiState.InstallInfo
) {
val isToolLoading =
@@ -101,8 +105,7 @@ internal fun ToolStoreScreen(
val infiniteTransition = rememberInfiniteTransition(label = "infiniteTransition")
var installToolUsername by remember { mutableStateOf("Unknown") }
var installToolId by remember { mutableStateOf("Unknown") }
var installTool by remember { mutableStateOf(ToolEntity("Unknown", "Unknown", "Unknown")) }
Box(
modifier.fillMaxSize()
@@ -116,12 +119,14 @@ internal fun ToolStoreScreen(
) {
toolsPanel(
toolStorePagingItems = toolStorePagingItems,
onAction = { username, toolId ->
installToolUsername = username
installToolId = toolId
onChangeInstallStatus(ToolStoreUiState.Status.Pending)
onAction = { tool, installType ->
installTool = tool
onChangeInstallStatus(ToolStoreUiState.InstallInfo.Status.Pending)
onChangeInstallType(installType)
},
onClick = onNavigateToToolView
onClick = {
onNavigateToToolView(it.authorUsername, it.toolId)
}
)
item(span = StaggeredGridItemSpan.FullLine) {
@@ -165,18 +170,17 @@ internal fun ToolStoreScreen(
}
InstallAlertDialog(
status = installInfo.status,
installTool = installTool,
installInfo = installInfo,
onChangeInstallStatus = onChangeInstallStatus,
onInstallTool = { onInstallTool(installToolUsername, installToolId) },
username = installToolUsername,
toolId = installToolId
onInstallTool = { onInstallTool(installTool) }
)
}
private fun LazyStaggeredGridScope.toolsPanel(
toolStorePagingItems: LazyPagingItems<ToolEntity>,
onAction: (username: String, toolId: String) -> Unit,
onClick: (username: String, toolId: String) -> Unit
onAction: (installTool: ToolEntity, installType: ToolStoreUiState.InstallInfo.Type) -> Unit,
onClick: (ToolEntity) -> Unit
) {
items(
items = toolStorePagingItems.itemSnapshotList,
@@ -184,28 +188,34 @@ private fun LazyStaggeredGridScope.toolsPanel(
) {
ToolCard(
tool = it!!,
actionIcon = if (!it.isInstalled) OxygenIcons.Download else null,
specifyVer = it.upgrade,
actionIcon = if (it.upgrade != null) OxygenIcons.Upgrade else 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) },
onLongClick = { onClick(it.authorUsername, it.toolId) },
onAction = {
onAction(
it,
if (it.upgrade != null) ToolStoreUiState.InstallInfo.Type.Upgrade else ToolStoreUiState.InstallInfo.Type.Install
)
},
onClick = { onClick(it) }
)
}
}
@Composable
private fun InstallAlertDialog(
status: ToolStoreUiState.Status,
onChangeInstallStatus: (ToolStoreUiState.Status) -> Unit,
onInstallTool: () -> Unit,
username: String,
toolId: String
installTool: ToolEntity,
installInfo: ToolStoreUiState.InstallInfo,
onChangeInstallStatus: (ToolStoreUiState.InstallInfo.Status) -> Unit,
onInstallTool: () -> Unit
) {
if (status != ToolStoreUiState.Status.None) {
val (status, type) = installInfo
if (status != ToolStoreUiState.InstallInfo.Status.None) {
AlertDialog(
onDismissRequest = {
if (status == ToolStoreUiState.Status.Pending) {
onChangeInstallStatus(ToolStoreUiState.Status.None)
if (status == ToolStoreUiState.InstallInfo.Status.Pending) {
onChangeInstallStatus(ToolStoreUiState.InstallInfo.Status.None)
}
},
title = {
@@ -214,20 +224,34 @@ private fun InstallAlertDialog(
) {
Icon(
imageVector = when (status) {
ToolStoreUiState.Status.Success -> OxygenIcons.Success
ToolStoreUiState.Status.Fail -> OxygenIcons.Error
ToolStoreUiState.InstallInfo.Status.Success -> OxygenIcons.Success
ToolStoreUiState.InstallInfo.Status.Fail -> OxygenIcons.Error
else -> OxygenIcons.Info
},
contentDescription = stringResource(R.string.core_install)
contentDescription = stringResource(
when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> R.string.core_install
ToolStoreUiState.InstallInfo.Type.Upgrade -> R.string.core_upgrade
}
)
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = stringResource(
when (status) {
ToolStoreUiState.Status.Success -> R.string.feature_store_install_success
ToolStoreUiState.Status.Fail -> R.string.feature_store_install_fail
when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> when (status) {
ToolStoreUiState.InstallInfo.Status.Success -> R.string.feature_store_install_success
ToolStoreUiState.InstallInfo.Status.Fail -> R.string.feature_store_install_fail
else -> R.string.feature_store_install_tool
}
ToolStoreUiState.InstallInfo.Type.Upgrade -> when (status) {
ToolStoreUiState.InstallInfo.Status.Success -> R.string.feature_store_upgrade_success
ToolStoreUiState.InstallInfo.Status.Fail -> R.string.feature_store_upgrade_fail
else -> R.string.feature_store_upgrade_tool
}
}
)
)
}
@@ -239,39 +263,71 @@ private fun InstallAlertDialog(
.padding(vertical = 16.dp)
) {
when (status) {
ToolStoreUiState.Status.Pending ->
ToolStoreUiState.InstallInfo.Status.Pending ->
Text(
text = stringResource(
text = when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> stringResource(
R.string.feature_store_ask_install,
username,
toolId
)
installTool.authorUsername,
installTool.toolId
)
ToolStoreUiState.Status.Installing ->
ToolStoreUiState.InstallInfo.Type.Upgrade -> stringResource(
R.string.feature_store_ask_upgrade,
installTool.authorUsername,
installTool.toolId,
installTool.ver,
installTool.upgrade ?: installTool.ver
)
}
)
ToolStoreUiState.InstallInfo.Status.Processing ->
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(16.dp))
Text(text = stringResource(R.string.core_installing))
Text(
text = stringResource(
when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> R.string.core_installing
ToolStoreUiState.InstallInfo.Type.Upgrade -> R.string.core_upgrading
}
)
)
}
ToolStoreUiState.Status.Success ->
Text(text = stringResource(R.string.feature_store_install_success_info))
ToolStoreUiState.InstallInfo.Status.Success ->
Text(
text = stringResource(
when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> R.string.feature_store_install_success_info
ToolStoreUiState.InstallInfo.Type.Upgrade -> R.string.feature_store_upgrade_success_info
}
)
)
ToolStoreUiState.Status.Fail ->
Text(text = stringResource(R.string.feature_store_install_fail_info))
ToolStoreUiState.InstallInfo.Status.Fail ->
Text(
text = stringResource(
when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> R.string.feature_store_install_fail_info
ToolStoreUiState.InstallInfo.Type.Upgrade -> R.string.feature_store_upgrade_fail_info
}
)
)
else -> Unit
}
}
},
dismissButton = {
if (status == ToolStoreUiState.Status.Pending) {
if (status == ToolStoreUiState.InstallInfo.Status.Pending) {
TextButton(onClick = {
onChangeInstallStatus(ToolStoreUiState.Status.None)
onChangeInstallStatus(ToolStoreUiState.InstallInfo.Status.None)
}) {
Text(text = stringResource(R.string.core_cancel))
}
@@ -279,19 +335,23 @@ private fun InstallAlertDialog(
},
confirmButton = {
when (status) {
ToolStoreUiState.Status.Pending ->
ToolStoreUiState.InstallInfo.Status.Pending ->
TextButton(onClick = onInstallTool) {
Text(text = stringResource(R.string.core_install))
Text(text = stringResource(
when (type) {
ToolStoreUiState.InstallInfo.Type.Install -> R.string.core_install
ToolStoreUiState.InstallInfo.Type.Upgrade -> R.string.core_upgrade
}))
}
ToolStoreUiState.Status.Success,
ToolStoreUiState.Status.Fail ->
ToolStoreUiState.InstallInfo.Status.Success,
ToolStoreUiState.InstallInfo.Status.Fail ->
TextButton(onClick = {
onChangeInstallStatus(ToolStoreUiState.Status.None)
onChangeInstallStatus(ToolStoreUiState.InstallInfo.Status.None)
}) {
Text(
text = stringResource(
if (status == ToolStoreUiState.Status.Success) R.string.core_ok
if (status == ToolStoreUiState.InstallInfo.Status.Success) R.string.core_ok
else R.string.core_close
)
)

View File

@@ -38,24 +38,36 @@ class ToolStoreViewModel @Inject constructor(
)
}
fun changeInstallStatus(installStatus: ToolStoreUiState.Status) {
savedStateHandle[INSTALL_INFO] = ToolStoreUiState.InstallInfo(installStatus)
fun changeInstallInfo(
status: ToolStoreUiState.InstallInfo.Status = installInfo.value.status,
type: ToolStoreUiState.InstallInfo.Type = installInfo.value.type
) {
savedStateHandle[INSTALL_INFO] = ToolStoreUiState.InstallInfo(status, type)
}
fun installTool(username: String, toolId: String) {
fun installTool(
toolEntity: ToolEntity
) {
viewModelScope.launch {
storeRepository.detail(username, toolId).collect {
when (it) {
Result.Loading -> savedStateHandle[INSTALL_INFO] =
ToolStoreUiState.InstallInfo(ToolStoreUiState.Status.Installing)
storeRepository.detail(toolEntity.authorUsername, toolEntity.toolId).collect { result ->
when (result) {
Result.Loading -> changeInstallInfo(status = ToolStoreUiState.InstallInfo.Status.Processing)
is Result.Error, is Result.Fail -> savedStateHandle[INSTALL_INFO] =
ToolStoreUiState.InstallInfo(ToolStoreUiState.Status.Fail)
is Result.Error, is Result.Fail -> changeInstallInfo(status = ToolStoreUiState.InstallInfo.Status.Fail)
is Result.Success -> {
toolRepository.saveTool(it.data)
savedStateHandle[INSTALL_INFO] =
ToolStoreUiState.InstallInfo(ToolStoreUiState.Status.Success)
when (installInfo.value.type) {
ToolStoreUiState.InstallInfo.Type.Install -> toolRepository.saveTool(
result.data
)
ToolStoreUiState.InstallInfo.Type.Upgrade -> {
toolRepository.removeTool(toolEntity)
toolRepository.saveTool(result.data)
}
}
changeInstallInfo(status = ToolStoreUiState.InstallInfo.Status.Success)
}
}
}
@@ -69,11 +81,16 @@ data class ToolStoreUiState(
) : Parcelable {
@Parcelize
data class InstallInfo(
var status: Status = Status.None
) : Parcelable
var status: Status = Status.None,
var type: Type = Type.Install
) : Parcelable {
enum class Status {
None, Pending, Installing, Success, Fail
None, Pending, Processing, Success, Fail
}
enum class Type {
Install, Upgrade
}
}
}

View File

@@ -14,6 +14,8 @@
<string name="core_no_connect">⚠️ 无法连接至互联网</string>
<string name="core_install">安装</string>
<string name="core_installing">安装中……</string>
<string name="core_upgrade">更新</string>
<string name="core_upgrading">更新中……</string>
<string name="core_uninstall">卸载</string>
<string name="core_uninstall_success">卸载成功</string>
<string name="core_cancel">取消</string>
@@ -21,11 +23,17 @@
<string name="feature_store_title">商店</string>
<string name="feature_store_install_tool">安装工具</string>
<string name="feature_store_ask_install">确定安装由用户 %1$s 提供的工具 %2$s 吗?</string>
<string name="feature_store_ask_install">确定安装由用户 %1$s 提供的工具 %2$s 吗</string>
<string name="feature_store_install_success">安装成功</string>
<string name="feature_store_install_success_info">恭喜!工具安装成功。</string>
<string name="feature_store_install_fail">安装失败</string>
<string name="feature_store_install_fail_info">安装失败!请稍后重试……</string>
<string name="feature_store_upgrade_tool">更新工具</string>
<string name="feature_store_ask_upgrade">确定要将用户 %2$s 提供的工具 %1$s 从版本 %3$s 更新到版本 %4$s 吗?</string>
<string name="feature_store_upgrade_success">更新成功</string>
<string name="feature_store_upgrade_success_info">恭喜!工具更新成功。</string>
<string name="feature_store_upgrade_fail">更新失败</string>
<string name="feature_store_upgrade_fail_info">更新失败!请稍后重试……</string>
<string name="feature_tools_title">工具</string>
<string name="feature_tools_description">简介</string>

View File

@@ -13,6 +13,8 @@
<string name="core_no_connect">⚠️ Unable to connect to the internet</string>
<string name="core_install">Install</string>
<string name="core_installing">Installing…</string>
<string name="core_upgrade">Upgrade</string>
<string name="core_upgrading">Upgrading…</string>
<string name="core_uninstall">Uninstall</string>
<string name="core_uninstall_success">Uninstalled successfully</string>
<string name="core_cancel">Cancel</string>
@@ -20,11 +22,17 @@
<string name="feature_store_title">Store</string>
<string name="feature_store_install_tool">Install Tool</string>
<string name="feature_store_ask_install">Are you sure to install tool %1$s provided by user %2$s?</string>
<string name="feature_store_ask_install">Are you sure you want to install tool %1$s provided by user %2$s?</string>
<string name="feature_store_install_success">Install Success</string>
<string name="feature_store_install_success_info">Congratulations, the tool installation is successful.</string>
<string name="feature_store_install_fail">Install Failed</string>
<string name="feature_store_install_fail_info">Installation failed, please try again later…</string>
<string name="feature_store_upgrade_tool">Upgrade Tool</string>
<string name="feature_store_ask_upgrade">Are you sure you want to upgrade tool %1$s provided by user %2$s from version %3$s to version %4$s?</string>
<string name="feature_store_upgrade_success">Upgrade Success</string>
<string name="feature_store_upgrade_success_info">Congratulations, the tool upgrade was successful.</string>
<string name="feature_store_upgrade_fail">Upgrade Failed</string>
<string name="feature_store_upgrade_fail_info">Upgrade failed, please try again later…</string>
<string name="feature_tools_title">Tools</string>
<string name="feature_tools_description">Desc</string>