forked from Nexus/nexus
add syncing waiting / error / failed indicator
This commit is contained in:
parent
a5fef138dd
commit
07700c1eff
6 changed files with 186 additions and 75 deletions
85
lib/widgets/sync_status_banner.dart
Normal file
85
lib/widgets/sync_status_banner.dart
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||
import "package:material_ui/material_ui.dart";
|
||||
import "package:nexus/controllers/sync_status.dart";
|
||||
import "package:nexus/widgets/error_dialog.dart";
|
||||
import "package:timeago/timeago.dart";
|
||||
|
||||
class const SyncStatusBanner({super.key}) extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final status = ref.watch(SyncStatusController.provider);
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
final banner = switch (status?.type) {
|
||||
null || .ok => null,
|
||||
.waiting => (
|
||||
title: "Waiting for sync...",
|
||||
icon: Icons.sync,
|
||||
background: colorScheme.primary,
|
||||
foreground: colorScheme.onPrimary,
|
||||
),
|
||||
.erroring => (
|
||||
title: "Sync is failing, retrying...",
|
||||
icon: Icons.sync_problem,
|
||||
background: colorScheme.error,
|
||||
foreground: colorScheme.onError,
|
||||
),
|
||||
.permanentlyFailed => (
|
||||
title: "Sync has permanently failed",
|
||||
icon: Icons.cloud_off,
|
||||
background: colorScheme.error,
|
||||
foreground: colorScheme.onError,
|
||||
),
|
||||
};
|
||||
|
||||
final details = status == null
|
||||
? null
|
||||
: [
|
||||
?status.error,
|
||||
if (status.errorCount > 0) "Failed attempts: ${status.errorCount}.",
|
||||
if (status.lastSync case final lastSync?)
|
||||
"Last synced ${format(lastSync)}.",
|
||||
];
|
||||
|
||||
return AnimatedSize(
|
||||
duration: const .new(milliseconds: 200),
|
||||
alignment: .topCenter,
|
||||
child: banner == null
|
||||
? const SizedBox(width: double.infinity)
|
||||
: Material(
|
||||
color: banner.background,
|
||||
child: InkWell(
|
||||
onTap: details == null
|
||||
? null
|
||||
: () => showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
ErrorDialog(details.join("\n\n"), null),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const .symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
spacing: 12,
|
||||
children: [
|
||||
Icon(banner.icon, size: 20, color: banner.foreground),
|
||||
Expanded(
|
||||
child: Text(
|
||||
banner.title,
|
||||
maxLines: 1,
|
||||
overflow: .ellipsis,
|
||||
style: TextStyle(
|
||||
color: banner.foreground,
|
||||
fontWeight: .bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (details != null)
|
||||
Icon(Icons.info_outline, color: banner.foreground),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue