iOS 2.7.0 - BETA Release of the iCloud Sync provider!

This commit is contained in:
2026-01-12 09:59:44 -07:00
parent 33610a5959
commit 98589645e6
10 changed files with 697 additions and 102 deletions

View File

@@ -555,7 +555,7 @@ struct SyncSection: View {
: .red
)
VStack(alignment: .leading) {
Text("Sync Server")
Text(syncService.providerType == .iCloud ? "iCloud Sync" : "Sync Server")
.font(.headline)
Text(
syncService.isConnected
@@ -570,14 +570,14 @@ struct SyncSection: View {
Spacer()
}
// Configure Server
// Configure Sync
Button(action: {
activeSheet = .syncSettings
}) {
HStack {
Image(systemName: "gear")
.foregroundColor(themeManager.accentColor)
Text("Configure Server")
Text("Configure Sync")
Spacer()
Image(systemName: "chevron.right")
.font(.caption)
@@ -698,63 +698,78 @@ struct SyncSettingsView: View {
@State private var isTesting = false
@State private var showingTestResult = false
@State private var testResultMessage = ""
@State private var selectedProvider: SyncProviderType = .server
var body: some View {
NavigationStack {
Form {
Section {
TextField("Server URL", text: $serverURL, prompt: Text("http://your-server:8080"))
.keyboardType(.URL)
.autocapitalization(.none)
.disableAutocorrection(true)
TextField("Auth Token", text: $authToken, prompt: Text("your-secret-token"))
.autocapitalization(.none)
.disableAutocorrection(true)
Picker("Provider", selection: $selectedProvider) {
ForEach(SyncProviderType.allCases) { type in
Text(type.displayName).tag(type)
}
}
} header: {
Text("Server Configuration")
} footer: {
Text(
"Enter your sync server URL and authentication token. You must test the connection before syncing is available."
)
Text("Sync Provider")
}
Section {
Button(action: {
testConnection()
}) {
HStack {
if isTesting {
ProgressView()
.scaleEffect(0.8)
Text("Testing...")
.foregroundColor(.secondary)
} else {
Image(systemName: "network")
.foregroundColor(themeManager.accentColor)
Text("Test Connection")
Spacer()
if syncService.isConnected {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
if selectedProvider == .server {
Section {
TextField("Server URL", text: $serverURL, prompt: Text("http://your-server:8080"))
.keyboardType(.URL)
.autocapitalization(.none)
.disableAutocorrection(true)
TextField("Auth Token", text: $authToken, prompt: Text("your-secret-token"))
.autocapitalization(.none)
.disableAutocorrection(true)
} header: {
Text("Server Configuration")
} footer: {
Text(
"Enter your sync server URL and authentication token. You must test the connection before syncing is available."
)
}
}
if selectedProvider != .none {
Section {
Button(action: {
testConnection()
}) {
HStack {
if isTesting {
ProgressView()
.scaleEffect(0.8)
Text("Testing...")
.foregroundColor(.secondary)
} else {
Image(systemName: "network")
.foregroundColor(themeManager.accentColor)
Text("Test Connection")
Spacer()
if syncService.isConnected && syncService.providerType == selectedProvider {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
}
}
}
}
.disabled(
isTesting
|| (selectedProvider == .server && (serverURL.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|| authToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty))
)
.foregroundColor(.primary)
} header: {
Text("Connection")
} footer: {
Text("Test the connection to verify your settings before saving.")
}
.disabled(
isTesting
|| serverURL.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|| authToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
)
.foregroundColor(.primary)
} header: {
Text("Connection")
} footer: {
Text("Test the connection to verify your server settings before saving.")
}
Section {
Button("Disconnect from Server") {
Button("Disconnect") {
showingDisconnectAlert = true
}
.foregroundColor(.orange)
@@ -785,18 +800,17 @@ struct SyncSettingsView: View {
let newToken = authToken.trimmingCharacters(in: .whitespacesAndNewlines)
// Mark as disconnected if settings changed
if newURL != syncService.serverURL || newToken != syncService.authToken {
if selectedProvider == .server && (newURL != syncService.serverURL || newToken != syncService.authToken) {
syncService.isConnected = false
UserDefaults.standard.set(false, forKey: "sync_is_connected")
} else if selectedProvider != syncService.providerType {
syncService.isConnected = false
UserDefaults.standard.set(false, forKey: "sync_is_connected")
}
syncService.serverURL = newURL
syncService.authToken = newToken
// Ensure provider type is set to server
if syncService.providerType != .server {
syncService.providerType = .server
}
syncService.providerType = selectedProvider
dismiss()
}
@@ -807,6 +821,7 @@ struct SyncSettingsView: View {
.onAppear {
serverURL = syncService.serverURL
authToken = syncService.authToken
selectedProvider = syncService.providerType
}
.alert("Disconnect from Server", isPresented: $showingDisconnectAlert) {
Button("Cancel", role: .cancel) {}
@@ -835,17 +850,19 @@ struct SyncSettingsView: View {
// Store original values in case test fails
let originalURL = syncService.serverURL
let originalToken = syncService.authToken
let originalProvider = syncService.providerType
Task { @MainActor in
do {
// Ensure we are using the server provider
if syncService.providerType != .server {
syncService.providerType = .server
// Switch to selected provider
if syncService.providerType != selectedProvider {
syncService.providerType = selectedProvider
}
// Temporarily set the values for testing
syncService.serverURL = testURL
syncService.authToken = testToken
if selectedProvider == .server {
syncService.serverURL = testURL
syncService.authToken = testToken
}
// Explicitly sync UserDefaults to ensure immediate availability
UserDefaults.standard.synchronize()
@@ -858,8 +875,11 @@ struct SyncSettingsView: View {
showingTestResult = true
} catch {
// Restore original values if test failed
syncService.serverURL = originalURL
syncService.authToken = originalToken
syncService.providerType = originalProvider
if originalProvider == .server {
syncService.serverURL = originalURL
syncService.authToken = originalToken
}
isTesting = false
testResultMessage = "Connection failed: \(error.localizedDescription)"