Files
zapstore/lib/widgets/batch_progress_banner.dart
T
Henrique VellosoandCursor 57878a774e feat: backup and restore installed apps (Issue #20)
- Add backup/restore for cataloged installed apps as encrypted AppStack (kind 30267)
- New service: installed_apps_backup_service with backup + restore providers
- Backup: saves addressable IDs to Nostr social relays via NIP-44 encryption
- Restore: fetches from relays, decrypts, resolves to App models; full-screen route
- Profile Data Management: Backup and Restore tiles (sign-in required)
- Restore screen: sections "To install" / "Already installed", Install All button
- Exclude backup identifier from bookmark/stack picker (bookmark_widgets)
- UpdateAllRow: optional label for "Install All" in restore screen
- Add /profile/restore route; no back arrow (matches app navigation style)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-24 21:06:47 -03:00

61 lines
1.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:models/models.dart';
import 'package:zapstore/services/package_manager/package_manager.dart';
import 'package:zapstore/theme.dart';
import 'package:zapstore/utils/extensions.dart';
/// "Update All" / "Install All" button row.
/// Progress and "All done" states are handled by sticky banners in _UpdatesListBody.
class UpdateAllRow extends ConsumerWidget {
const UpdateAllRow({
super.key,
required this.allUpdates,
this.label = 'Update All',
});
final List<App> allUpdates;
final String label;
@override
Widget build(BuildContext context, WidgetRef ref) {
if (allUpdates.length < 2) {
return const SizedBox.shrink();
}
return Container(
margin: const EdgeInsets.fromLTRB(16, 0, 16, 8),
width: double.infinity,
child: TextButton.icon(
onPressed: () async {
final pm = ref.read(packageManagerProvider.notifier);
final items = allUpdates
.where((app) => app.latestFileMetadata != null)
.map(
(app) => (
appId: app.identifier,
target: app.latestFileMetadata!,
displayName: app.name,
),
)
.toList();
await pm.queueDownloads(items);
},
icon: const Icon(Icons.download, size: 16, color: Colors.white),
label: Text(
'$label (${allUpdates.length})',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
style: TextButton.styleFrom(
backgroundColor: AppColors.darkPillBackground,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
),
);
}
}