|
|
|
|
@ -162,48 +162,32 @@ class _ProfileIndicator extends ConsumerWidget {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const double _kBadgeWidgetSize = 30.0;
|
|
|
|
|
|
|
|
|
|
class _BackupIndicator extends ConsumerWidget {
|
|
|
|
|
const _BackupIndicator();
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
const widgetSize = 30.0;
|
|
|
|
|
final hasError = ref.watch(driftBackupProvider.select((state) => state.error != BackupError.none));
|
|
|
|
|
final indicatorIcon = hasError
|
|
|
|
|
? Icon(
|
|
|
|
|
Icons.warning_rounded,
|
|
|
|
|
size: 12,
|
|
|
|
|
color: context.colorScheme.error,
|
|
|
|
|
semanticLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
)
|
|
|
|
|
: _getBackupBadgeIcon(context, ref);
|
|
|
|
|
final badgeBackground = hasError ? context.colorScheme.errorContainer : context.colorScheme.surfaceContainer;
|
|
|
|
|
final indicatorIcon = _getBackupBadgeIcon(context, ref);
|
|
|
|
|
|
|
|
|
|
return InkWell(
|
|
|
|
|
onTap: () => context.pushRoute(const DriftBackupRoute()),
|
|
|
|
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
|
|
|
|
child: Badge(
|
|
|
|
|
label: Container(
|
|
|
|
|
width: widgetSize / 2,
|
|
|
|
|
height: widgetSize / 2,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: badgeBackground,
|
|
|
|
|
border: Border.all(color: context.colorScheme.outline.withValues(alpha: .3)),
|
|
|
|
|
borderRadius: BorderRadius.circular(widgetSize / 2),
|
|
|
|
|
),
|
|
|
|
|
child: indicatorIcon,
|
|
|
|
|
),
|
|
|
|
|
label: indicatorIcon,
|
|
|
|
|
backgroundColor: Colors.transparent,
|
|
|
|
|
alignment: Alignment.bottomRight,
|
|
|
|
|
isLabelVisible: indicatorIcon != null,
|
|
|
|
|
offset: const Offset(-2, -12),
|
|
|
|
|
child: Icon(Icons.backup_rounded, size: widgetSize, color: context.primaryColor),
|
|
|
|
|
child: Icon(Icons.backup_rounded, size: _kBadgeWidgetSize, color: context.primaryColor),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget? _getBackupBadgeIcon(BuildContext context, WidgetRef ref) {
|
|
|
|
|
final backupStateStream = ref.watch(settingsProvider).watch(Setting.enableBackup);
|
|
|
|
|
final hasError = ref.watch(driftBackupProvider.select((state) => state.error != BackupError.none));
|
|
|
|
|
final isDarkTheme = context.isDarkTheme;
|
|
|
|
|
final iconColor = isDarkTheme ? Colors.white : Colors.black;
|
|
|
|
|
final isUploading = ref.watch(driftBackupProvider.select((state) => state.uploadItems.isNotEmpty));
|
|
|
|
|
@ -215,42 +199,76 @@ class _BackupIndicator extends ConsumerWidget {
|
|
|
|
|
final backupEnabled = snapshot.data ?? false;
|
|
|
|
|
|
|
|
|
|
if (!backupEnabled) {
|
|
|
|
|
return Icon(
|
|
|
|
|
Icons.cloud_off_rounded,
|
|
|
|
|
size: 9,
|
|
|
|
|
color: iconColor,
|
|
|
|
|
semanticLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
return _BadgeLabel(
|
|
|
|
|
Icon(
|
|
|
|
|
Icons.cloud_off_rounded,
|
|
|
|
|
size: 9,
|
|
|
|
|
color: iconColor,
|
|
|
|
|
semanticLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasError) {
|
|
|
|
|
return _BadgeLabel(
|
|
|
|
|
Icon(
|
|
|
|
|
Icons.warning_rounded,
|
|
|
|
|
size: 12,
|
|
|
|
|
color: context.colorScheme.error,
|
|
|
|
|
semanticLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
),
|
|
|
|
|
backgroundColor: context.colorScheme.errorContainer,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isUploading) {
|
|
|
|
|
return Container(
|
|
|
|
|
padding: const EdgeInsets.all(3.5),
|
|
|
|
|
child: Theme(
|
|
|
|
|
data: context.themeData.copyWith(
|
|
|
|
|
progressIndicatorTheme: context.themeData.progressIndicatorTheme.copyWith(year2023: true),
|
|
|
|
|
),
|
|
|
|
|
child: CircularProgressIndicator(
|
|
|
|
|
strokeWidth: 2,
|
|
|
|
|
strokeCap: StrokeCap.round,
|
|
|
|
|
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
|
|
|
|
|
semanticsLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
return _BadgeLabel(
|
|
|
|
|
Container(
|
|
|
|
|
padding: const EdgeInsets.all(3.5),
|
|
|
|
|
child: Theme(
|
|
|
|
|
data: context.themeData.copyWith(
|
|
|
|
|
progressIndicatorTheme: context.themeData.progressIndicatorTheme.copyWith(year2023: true),
|
|
|
|
|
),
|
|
|
|
|
child: CircularProgressIndicator(
|
|
|
|
|
strokeWidth: 2,
|
|
|
|
|
strokeCap: StrokeCap.round,
|
|
|
|
|
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
|
|
|
|
|
semanticsLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Icon(
|
|
|
|
|
Icons.check_outlined,
|
|
|
|
|
size: 9,
|
|
|
|
|
color: iconColor,
|
|
|
|
|
semanticLabel: 'backup_controller_page_backup'.tr(),
|
|
|
|
|
return _BadgeLabel(
|
|
|
|
|
Icon(Icons.check_outlined, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr()),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _BadgeLabel extends StatelessWidget {
|
|
|
|
|
final Widget indicator;
|
|
|
|
|
final Color? backgroundColor;
|
|
|
|
|
|
|
|
|
|
const _BadgeLabel(this.indicator, {this.backgroundColor});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Container(
|
|
|
|
|
width: _kBadgeWidgetSize / 2,
|
|
|
|
|
height: _kBadgeWidgetSize / 2,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: backgroundColor ?? context.colorScheme.surfaceContainer,
|
|
|
|
|
border: Border.all(color: context.colorScheme.outline.withValues(alpha: .3)),
|
|
|
|
|
borderRadius: BorderRadius.circular(_kBadgeWidgetSize / 2),
|
|
|
|
|
),
|
|
|
|
|
child: indicator,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _SyncStatusIndicator extends ConsumerStatefulWidget {
|
|
|
|
|
const _SyncStatusIndicator();
|
|
|
|
|
|
|
|
|
|
|