Fix AppMenuView Connection Status UX and add smart sync dashboard

- Wi-Fi row: title always "Wi-Fi", subtitle shows SSID or Cellular/Not connected;
  badge is Connected (green) / Cellular (amber) / Offline (muted) — no more
  contradictory "No Wi-Fi" title with "Wi-Fi connected" subtitle
- NAS badge: Reachable now amber (TCP ping only, not auth-confirmed), Offline red,
  Unknown muted — removes misleading green on unverified NAS connectivity
- Error rows are now tappable; chevron affordance + ScaleButtonStyle; opens detail
  sheet with date, counts, duration, NAS host, trigger type, and suggested fix steps
- Sync Activity section: Clear button with confirmation alert (warns about error count
  if errors exist), calls store.clearHistory()
- BackupViewModel: compareWithNAS() computes accurate pre-scan alreadySafeCount /
  notBackedUpCount by matching lowercased filenames against NAS directory listing
- BackupView: ring shows state-based content (idle: not-backed-up count, running: %,
  completed: checkmark), pill-style page indicator, display counts update live during
  backup run, loadNASAndCompare() called on appear

Co-Authored-By: Kutesir <kutesir@provoc.ug>
Co-Authored-By: Sentry <sentry@provoc.ug>
This commit is contained in:
Robin Kutesa
2026-05-17 11:54:43 +03:00
parent 59bdad803f
commit a077964d75
3 changed files with 350 additions and 92 deletions

View File

@@ -4,13 +4,40 @@ import Photos
@MainActor
final class BackupViewModel: ObservableObject {
@Published var totalPhotoCount: Int = 0
@Published var alreadySafeCount: Int = 0
@Published var notBackedUpCount: Int = 0
@Published var photosAuthStatus: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
private let photoService = PhotoLibraryService()
private var fetchedAssets: [PhotoAsset] = []
func loadPhotoCount(filter: BackupFilter) {
let assets = photoService.fetchAssets(filter: filter)
fetchedAssets = assets
totalPhotoCount = assets.count
// Conservative initial state until NAS scan completes
alreadySafeCount = 0
notBackedUpCount = assets.count
}
// Called after NAS directory listing loads.
// Matches by lowercased filename same heuristic BackupEngine uses for skip checks.
// This gives an accurate pre-scan "Already Safe / Not Backed Up" split before
// the user ever taps Start Backup.
func compareWithNAS(nasItems: [NASItem]) {
let nasFilenames = Set(
nasItems
.filter { !$0.isDirectory }
.map { $0.name.lowercased() }
)
var safe = 0
for asset in fetchedAssets {
if nasFilenames.contains(asset.filename.lowercased()) {
safe += 1
}
}
alreadySafeCount = safe
notBackedUpCount = totalPhotoCount - safe
}
func requestPhotosAccess() async {