Refactor to use Bedrock's iCloudSyncSettingsView and CloudSyncable protocol

This commit is contained in:
Matt Bruce 2026-01-04 18:11:28 -06:00
parent db27e50b08
commit 845367fa87
2 changed files with 7 additions and 77 deletions

View File

@ -517,82 +517,12 @@ struct SettingsView: View {
// MARK: - iCloud Sync Section // MARK: - iCloud Sync Section
private var iCloudSyncSection: some View { private var iCloudSyncSection: some View {
VStack(alignment: .leading, spacing: Design.Spacing.small) { iCloudSyncSettingsView(
// Sync toggle viewModel: viewModel,
Toggle(isOn: $viewModel.iCloudEnabled) { accentColor: AppAccent.primary,
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) { successColor: AppStatus.success,
Text(String(localized: "Sync Settings")) warningColor: AppStatus.warning
.font(.system(size: Design.BaseFontSize.medium, weight: .medium)) )
.foregroundStyle(.white)
Text(viewModel.iCloudAvailable
? String(localized: "Sync settings across all your devices")
: String(localized: "Sign in to iCloud to enable sync"))
.font(.system(size: Design.BaseFontSize.body))
.foregroundStyle(.white.opacity(Design.Opacity.medium))
}
}
.tint(AppAccent.primary)
.padding(.vertical, Design.Spacing.xSmall)
.disabled(!viewModel.iCloudAvailable)
.accessibilityHint(String(localized: "Syncs settings across all your devices via iCloud"))
// Sync status (show when enabled and available)
if viewModel.iCloudEnabled && viewModel.iCloudAvailable {
HStack(spacing: Design.Spacing.small) {
Image(systemName: syncStatusIcon)
.font(.system(size: Design.BaseFontSize.body))
.foregroundStyle(syncStatusColor)
Text(syncStatusText)
.font(.system(size: Design.BaseFontSize.caption))
.foregroundStyle(.white.opacity(Design.Opacity.medium))
Spacer()
Button {
viewModel.forceSync()
} label: {
Text(String(localized: "Sync Now"))
.font(.system(size: Design.BaseFontSize.caption, weight: .medium))
.foregroundStyle(AppAccent.primary)
}
}
.padding(.top, Design.Spacing.xSmall)
}
}
}
// MARK: - Sync Status Helpers
private var syncStatusIcon: String {
if !viewModel.hasCompletedInitialSync {
return "arrow.triangle.2.circlepath"
}
return viewModel.syncStatus.isEmpty ? "checkmark.icloud" : "icloud"
}
private var syncStatusColor: Color {
if !viewModel.hasCompletedInitialSync {
return AppStatus.warning
}
return AppStatus.success
}
private var syncStatusText: String {
if !viewModel.hasCompletedInitialSync {
return String(localized: "Syncing...")
}
if let lastSync = viewModel.lastSyncDate {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .abbreviated
return String(localized: "Last synced \(formatter.localizedString(for: lastSync, relativeTo: Date()))")
}
return viewModel.syncStatus.isEmpty
? String(localized: "Synced")
: viewModel.syncStatus
} }
// MARK: - Acknowledgments Section // MARK: - Acknowledgments Section

View File

@ -38,7 +38,7 @@ enum TimerOption: String, CaseIterable, Identifiable {
/// Premium features are automatically reset to defaults when user doesn't have premium. /// Premium features are automatically reset to defaults when user doesn't have premium.
@MainActor @MainActor
@Observable @Observable
final class SettingsViewModel: RingLightConfigurable { final class SettingsViewModel: RingLightConfigurable, CloudSyncable {
// MARK: - Ring Size Limits // MARK: - Ring Size Limits