Files
noo/lib/widgets/sync_status_badge.dart
T
ayushyaandClaude Sonnet 5 faaec5365f
Build APK / build (push) Successful in 7m33s
Add device sync: mirror folders/files locally, background WorkManager engine
- New native sync engine (SyncEngine/SyncWorker/ConflictResolveWorker,
  WorkManager-based) that mirrors selected Nextcloud folders or files to
  app-private local storage, periodically and on-demand ("Sync now"),
  with never-auto-resolved conflict notifications.
- Single files (not just folders) can now be marked "Sync to device".
- Live sync status (syncing/synced/conflicts) pushes from native to Dart
  over a new EventChannel; the persistent header chip/panel now reflects
  device-sync status instead of the WebDAV-refresh loading state, with a
  cloud_off/cloud_sync/cloud_done/cloud_alert icon set and an expandable
  conflicts list with in-app "Keep local"/"Use server" resolution.
  Per-item cloud_done/sync badges show on Files tiles.
- Share/Download short-circuit to the local copy for already-synced
  files instead of a fresh network fetch.
- Settings gained a Device Sync section (per-folder list, "Sync
  everything", Wi-Fi-only toggle, manual "Sync now").
- Fixed two release-only bugs found via on-device testing: Android's
  HttpURLConnection silently rejects the PROPFIND method (switched to
  OkHttp), and R8 was stripping WorkManager's reflection-instantiated
  internals (broadened proguard-rules.pro to keep androidx.work.**
  wholesale rather than chasing individual classes).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 00:52:56 -04:00

35 lines
1.1 KiB
Dart

import 'package:flutter/material.dart';
import '../models/sync_status.dart';
/// A small corner badge over a thumbnail showing device-sync status - a
/// `cloud_done` badge once a file's mirrored locally, `sync` while it's
/// actively being transferred. Nothing is drawn for `none`/`conflict`
/// (conflicts surface in the sync header, not as per-tile noise).
class SyncStatusBadge extends StatelessWidget {
final SyncItemStatus status;
const SyncStatusBadge({super.key, required this.status});
@override
Widget build(BuildContext context) {
if (status != SyncItemStatus.syncing && status != SyncItemStatus.synced) {
return const SizedBox.shrink();
}
final colorScheme = Theme.of(context).colorScheme;
final icon = status == SyncItemStatus.syncing
? Icons.sync_rounded
: Icons.cloud_done_rounded;
return Container(
width: 18,
height: 18,
decoration: BoxDecoration(
color: colorScheme.surface,
shape: BoxShape.circle,
border: Border.all(color: colorScheme.surface, width: 1.5),
),
child: Icon(icon, size: 13, color: colorScheme.primary),
);
}
}