mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 12:38:24 +00:00
fix: handle terminal install ops in install button
- Show uninstall (delete) actions immediately after install by treating Completed as not busy on the detail screen. - Ignore stale Completed when the app is no longer installed so the primary CTA returns to Install. - Allow install → uninstall → install again by clearing stale terminal ops (Completed/OperationFailed) in PackageManager.startDownload() (keeps batch progress UX intact).
This commit is contained in:
@@ -330,7 +330,18 @@ abstract class PackageManager extends StateNotifier<PackageManagerState> {
|
||||
String? displayName,
|
||||
}) async {
|
||||
await _ensureDownloaderReady();
|
||||
if (hasOperation(appId)) return false;
|
||||
final existing = getOperation(appId);
|
||||
if (existing != null) {
|
||||
// We keep terminal states (Completed/Failed) in the operations map briefly so
|
||||
// batch progress UI can derive totals. However, starting a new download for the
|
||||
// same app should not be blocked by a stale terminal op (e.g. install -> uninstall
|
||||
// -> install again). Only in-flight operations should block.
|
||||
if (existing is Completed || existing is OperationFailed) {
|
||||
clearOperation(appId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final downloadUrl = target.urls.firstOrNull;
|
||||
if (downloadUrl == null || downloadUrl.isEmpty) {
|
||||
|
||||
@@ -31,6 +31,12 @@ class InstallButton extends ConsumerWidget {
|
||||
|
||||
// Derive what to display
|
||||
final isInstalled = installedPkg != null;
|
||||
// Note: PackageManager keeps terminal operations (e.g. Completed) in the
|
||||
// operations map for a while so batch UX (e.g. "All done") can derive counts.
|
||||
// For the detail screen action row, Completed should be treated as "not busy"
|
||||
// so the user can immediately Open/Delete after install.
|
||||
final canShowActionButtons =
|
||||
isInstalled && (operation == null || operation is Completed);
|
||||
final hasUpdate = app.hasUpdate;
|
||||
final hasDowngrade = app.hasDowngrade;
|
||||
final hasRelease = release != null;
|
||||
@@ -76,7 +82,7 @@ class InstallButton extends ConsumerWidget {
|
||||
children: [
|
||||
Expanded(child: SizedBox(height: 48, child: button)),
|
||||
// Show action buttons only for installed apps with no active operation
|
||||
if (isInstalled && operation == null) ...[
|
||||
if (canShowActionButtons) ...[
|
||||
if (hasUpdate) ...[
|
||||
const SizedBox(width: 8),
|
||||
_buildOpenIconButton(context, ref),
|
||||
@@ -101,9 +107,15 @@ class InstallButton extends ConsumerWidget {
|
||||
required FileMetadata? fileMetadata,
|
||||
required double fontSize,
|
||||
}) {
|
||||
// Completed is a terminal "result" state and may linger for batch progress UX.
|
||||
// If the app is no longer installed (e.g. user uninstalled right after install),
|
||||
// ignore a stale Completed op so we fall back to the normal "Install" UI.
|
||||
final effectiveOperation =
|
||||
(!isInstalled && operation is Completed) ? null : operation;
|
||||
|
||||
// Handle operation states first
|
||||
if (operation != null) {
|
||||
return switch (operation) {
|
||||
if (effectiveOperation != null) {
|
||||
return switch (effectiveOperation) {
|
||||
DownloadQueued() => _buildSimpleButton(
|
||||
context,
|
||||
'Queued for download',
|
||||
|
||||
Reference in New Issue
Block a user