Skip to content

Commit a613a0f

Browse files
committed
feat: enhance app linking with asset selection and validation
- Implement a new "Pick Asset" step in the manual app linking flow to allow users to select a specific APK for verification. - Add support for downloading and verifying the selected asset's package name and signing fingerprint against the installed app. - Update `AppsViewModel` to handle asset selection, download progress tracking, and detailed validation logic. - Enhance GitHub URL parsing to be more robust and strictly validate the "github.com" domain. - Refactor string resources to move hardcoded UI text into `strings.xml` for better localization support. - Improve the "Apps" list sorting to prioritize apps with available updates. - Update `LinkAppBottomSheet` UI with `AnimatedContent` for smoother transitions between linking steps and a new `PickAssetStep` list.
1 parent b25bb34 commit a613a0f

5 files changed

Lines changed: 379 additions & 87 deletions

File tree

core/presentation/src/commonMain/composeResources/values/strings.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@
555555
<string name="verifying_signing_key">Verifying signing key…</string>
556556
<string name="package_name_mismatch">Package name mismatch: the APK is %1$s, but the selected app is %2$s</string>
557557
<string name="signing_key_mismatch_link">Signing key mismatch: the APK in this repository was signed by a different developer than the installed app</string>
558+
<string name="select_asset_title">Select installer</string>
559+
<string name="select_asset_description">Pick the APK to verify against your installed app</string>
560+
<string name="download_failed">Download failed</string>
558561
<string name="export_apps">Export</string>
559562
<string name="import_apps">Import</string>
560563
<string name="import_apps_title">Import apps</string>
@@ -565,4 +568,16 @@
565568
<string name="include_pre_releases_description">Track pre-release versions when checking for updates. When disabled, only stable releases are considered.</string>
566569
<string name="confirm_uninstall_title">Uninstall app?</string>
567570
<string name="confirm_uninstall_message">Are you sure you want to uninstall %1$s? This action cannot be undone and app data may be lost.</string>
571+
572+
<string name="invalid_github_url">Invalid GitHub URL. Use format: github.com/owner/repo</string>
573+
<string name="repo_not_found">Repository not found: %1$s/%2$s</string>
574+
<string name="rate_limit_try_again">GitHub API rate limit exceeded. Try again later.</string>
575+
<string name="failed_to_link">Failed to link: %1$s</string>
576+
<string name="failed_to_load_apps">Failed to load installed apps</string>
577+
<string name="app_linked_success">%1$s linked to %2$s/%3$s</string>
578+
<string name="export_failed">Export failed: %1$s</string>
579+
<string name="import_failed">Import failed: %1$s</string>
580+
<string name="imported_apps_summary">Imported %1$d apps</string>
581+
<string name="imported_skipped">, %1$d skipped</string>
582+
<string name="imported_failed">, %1$d failed</string>
568583
</resources>

feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package zed.rainxch.apps.presentation
22

33
import zed.rainxch.core.domain.model.DeviceApp
4+
import zed.rainxch.core.domain.model.GithubAsset
45
import zed.rainxch.core.domain.model.InstalledApp
56

67
sealed interface AppsAction {
@@ -50,6 +51,8 @@ sealed interface AppsAction {
5051
data class OnRepoUrlChanged(val url: String) : AppsAction
5152
data object OnValidateAndLinkRepo : AppsAction
5253
data object OnBackToAppPicker : AppsAction
54+
data class OnLinkAssetSelected(val asset: GithubAsset) : AppsAction
55+
data object OnBackToEnterUrl : AppsAction
5356

5457
// Export/Import
5558
data object OnExportApps : AppsAction

feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsState.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import zed.rainxch.apps.domain.model.GithubRepoInfo
44
import zed.rainxch.apps.presentation.model.AppItem
55
import zed.rainxch.apps.presentation.model.UpdateAllProgress
66
import zed.rainxch.core.domain.model.DeviceApp
7+
import zed.rainxch.core.domain.model.GithubAsset
78
import zed.rainxch.core.domain.model.InstalledApp
89

910
data class AppsState(
@@ -27,6 +28,9 @@ data class AppsState(
2728
val isValidatingRepo: Boolean = false,
2829
val repoValidationError: String? = null,
2930
val linkValidationStatus: String? = null,
31+
val linkInstallableAssets: List<GithubAsset> = emptyList(),
32+
val linkSelectedAsset: GithubAsset? = null,
33+
val linkDownloadProgress: Int? = null,
3034
val fetchedRepoInfo: GithubRepoInfo? = null,
3135
// Export/Import
3236
val isExporting: Boolean = false,
@@ -35,17 +39,19 @@ data class AppsState(
3539
val appPendingUninstall: InstalledApp? = null,
3640
) {
3741
val filteredDeviceApps: List<DeviceApp>
38-
get() = if (deviceAppSearchQuery.isBlank()) {
39-
deviceApps
40-
} else {
41-
deviceApps.filter {
42-
it.appName.contains(deviceAppSearchQuery, ignoreCase = true) ||
43-
it.packageName.contains(deviceAppSearchQuery, ignoreCase = true)
42+
get() =
43+
if (deviceAppSearchQuery.isBlank()) {
44+
deviceApps
45+
} else {
46+
deviceApps.filter {
47+
it.appName.contains(deviceAppSearchQuery, ignoreCase = true) ||
48+
it.packageName.contains(deviceAppSearchQuery, ignoreCase = true)
49+
}
4450
}
45-
}
4651
}
4752

4853
enum class LinkStep {
4954
PickApp,
5055
EnterUrl,
56+
PickAsset,
5157
}

0 commit comments

Comments
 (0)