Package manager fixes

This commit is contained in:
franzap
2026-02-05 15:31:24 -03:00
parent cc31af4ee7
commit 36e3677b80
3 changed files with 16 additions and 28 deletions
@@ -658,31 +658,10 @@ final class AndroidPackageManager extends PackageManager {
// Derive general silent install capability from per-app data
_supportsSilentInstall = anyCanInstallSilently;
// Preserve any packages we've directly updated (they have installTime set)
// This prevents race conditions where sync returns stale data
final preserved = <String, PackageInfo>{};
for (final entry in state.installed.entries) {
if (entry.value.installTime != null &&
!packages.containsKey(entry.key)) {
// We directly updated this but sync doesn't have it yet - keep ours
preserved[entry.key] = entry.value;
} else if (entry.value.installTime != null &&
packages.containsKey(entry.key)) {
// Both have it - use sync data but preserve installTime marker
final syncPkg = packages[entry.key]!;
preserved[entry.key] = PackageInfo(
appId: syncPkg.appId,
name: syncPkg.name,
version: syncPkg.version,
versionCode: syncPkg.versionCode,
signatureHash: syncPkg.signatureHash,
installTime: entry.value.installTime,
canInstallSilently: syncPkg.canInstallSilently,
);
}
}
state = state.copyWith(installed: {...packages, ...preserved});
// Trust the native source as the single source of truth.
// Android's SUCCESS broadcast only fires after the package is committed,
// so there's no race condition with queryable state.
state = state.copyWith(installed: packages);
await InstalledPackagesSnapshot.save(state.installed);
// Clear operations for apps where the installed version matches the target version
@@ -1438,6 +1438,7 @@ class BatchProgress {
required this.installing,
required this.queued,
required this.failed,
required this.cancelled,
required this.phase,
});
@@ -1462,10 +1463,14 @@ class BatchProgress {
/// Operations that failed
final int failed;
/// Operations cancelled by user (InstallCancelled - can retry individually)
final int cancelled;
/// Current dominant phase
final BatchPhase phase;
/// Whether any operations are in progress (not terminal)
/// Terminal states: Completed, OperationFailed, InstallCancelled
bool get hasInProgress =>
downloading > 0 || verifying > 0 || installing > 0 || queued > 0;
@@ -1494,7 +1499,8 @@ final batchProgressProvider = Provider<BatchProgress?>((ref) {
verifying = 0,
installing = 0,
queued = 0,
failed = 0;
failed = 0,
cancelled = 0;
for (final op in ops.values) {
switch (op) {
@@ -1511,7 +1517,7 @@ final batchProgressProvider = Provider<BatchProgress?>((ref) {
case OperationFailed():
failed++;
case InstallCancelled():
queued++; // User can retry
cancelled++; // Terminal for batch - user can retry individually
case AwaitingPermission():
queued++; // Waiting for permission
case Uninstalling():
@@ -1540,6 +1546,7 @@ final batchProgressProvider = Provider<BatchProgress?>((ref) {
installing: installing,
queued: queued,
failed: failed,
cancelled: cancelled,
phase: phase,
);
});
+3 -1
View File
@@ -199,8 +199,10 @@ There is no third option. Timeouts, crashes, backgrounding, network loss—all p
- Successful operations transition to `Completed` state (stay in map)
- Total = operations.length (includes completed)
- Completed = count of `Completed` operations
- In-progress = Total - Completed - Failed
- In-progress = Total - Completed - Failed - Cancelled
- Phase = derived from operation types currently active
- Terminal states for batch progress: `Completed`, `OperationFailed`, `InstallCancelled`
- `InstallCancelled` counts as cancelled (user can retry individually, but batch doesn't wait)
- When all operations reach terminal state, banner shows "X of X updated ✓"
- After 3 seconds with no in-progress operations, completed operations auto-clear