aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2024-05-17 13:59:46 -0700
committerDustin Mierau <dustin@mierau.me>2024-05-17 13:59:46 -0700
commit386743e8b1aab8fe034bb650c45aca3a16f047b7 (patch)
tree10ec1d83e685433ac4bd42005bc6f4957a60fc1b /Hotline
parent277c4cb65218adb8485bb28560a9bb4cca42da82 (diff)
Further work on bookmark syncing. Reworked code that prepopulated bookmarks when empty to wait for first sync.
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Application-macOS.swift60
-rw-r--r--Hotline/Models/ApplicationState.swift2
-rw-r--r--Hotline/Models/Bookmark.swift23
-rw-r--r--Hotline/macOS/TrackerView.swift28
4 files changed, 80 insertions, 33 deletions
diff --git a/Hotline/Application-macOS.swift b/Hotline/Application-macOS.swift
index 6b02024..9aec187 100644
--- a/Hotline/Application-macOS.swift
+++ b/Hotline/Application-macOS.swift
@@ -1,5 +1,6 @@
import SwiftUI
import SwiftData
+import CloudKit
import UniformTypeIdentifiers
@Observable
@@ -16,8 +17,50 @@ final class AppLaunchState {
}
class AppDelegate: NSObject, NSApplicationDelegate {
+ private var cloudKitObserverToken: Any? = nil
+
func applicationDidFinishLaunching(_ notification: Notification) {
AppLaunchState.shared.launchState = .launched
+
+ CKContainer.default().accountStatus { status, error in
+ switch status {
+ case .noAccount:
+ print("iCloud Unavailable")
+
+ // We mark CloudKit has available now since we're not waiting on
+ // a server sync or anything.
+ ApplicationState.shared.cloudKitReady = true
+ default:
+ print("iCloud Available")
+
+ self.cloudKitObserverToken = NotificationCenter.default.addObserver(forName: NSPersistentCloudKitContainer.eventChangedNotification, object: nil, queue: OperationQueue.main) { [weak self] note in
+ print("iCloud Changed!")
+ ApplicationState.shared.cloudKitReady = true
+
+ guard let token = self?.cloudKitObserverToken else { return }
+ NotificationCenter.default.removeObserver(token)
+ }
+ }
+ }
+
+// if FileManager.default.ubiquityIdentityToken == nil {
+// print("iCloud Unavailable")
+//
+// // We mark CloudKit has available now since we're not waiting on
+// // a server sync or anything.
+// ApplicationState.shared.cloudKitReady = true
+// }
+// else {
+// print("iCloud Available")
+//
+// self.cloudKitObserverToken = NotificationCenter.default.addObserver(forName: NSPersistentCloudKitContainer.eventChangedNotification, object: nil, queue: OperationQueue.main) { [weak self] note in
+// print("iCloud Changed!")
+// ApplicationState.shared.cloudKitReady = true
+//
+// guard let token = self?.cloudKitObserverToken else { return }
+// NotificationCenter.default.removeObserver(token)
+// }
+// }
}
func applicationWillTerminate(_ notification: Notification) {
@@ -37,6 +80,19 @@ struct Application: App {
@FocusedValue(\.activeHotlineModel) private var activeHotline: Hotline?
@FocusedValue(\.activeServerState) private var activeServerState: ServerState?
+
+ private var modelContainer: ModelContainer = {
+ let schema = Schema([
+ Bookmark.self
+ ])
+ let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .private("iCloud.co.goodmake.hotline"))
+ let modelContainer = try! ModelContainer(for: schema, configurations: [config])
+
+ // Print local SwiftData sqlite file.
+// print(modelContainer.configurations.first?.url.path(percentEncoded: false))
+
+ return modelContainer
+ }()
var body: some Scene {
// MARK: Tracker Window
@@ -44,7 +100,7 @@ struct Application: App {
TrackerView()
.frame(minWidth: 250, minHeight: 250)
}
- .modelContainer(for: [Bookmark.self])
+ .modelContainer(self.modelContainer)
.defaultSize(width: 700, height: 550)
.defaultPosition(.center)
.keyboardShortcut(.init("R"), modifiers: .command)
@@ -81,7 +137,7 @@ struct Application: App {
} defaultValue: {
Server(name: nil, description: nil, address: "")
}
- .modelContainer(for: [Bookmark.self])
+ .modelContainer(self.modelContainer)
.defaultSize(width: 750, height: 700)
.defaultPosition(.center)
.onChange(of: activeServerState) {
diff --git a/Hotline/Models/ApplicationState.swift b/Hotline/Models/ApplicationState.swift
index 5814fba..6e077c5 100644
--- a/Hotline/Models/ApplicationState.swift
+++ b/Hotline/Models/ApplicationState.swift
@@ -11,4 +11,6 @@ final class ApplicationState {
var activeServerID: UUID? = nil
var activeServerBanner: NSImage? = nil
var activeServerName: String? = nil
+
+ var cloudKitReady: Bool = false
}
diff --git a/Hotline/Models/Bookmark.swift b/Hotline/Models/Bookmark.swift
index 3530b19..c713bb0 100644
--- a/Hotline/Models/Bookmark.swift
+++ b/Hotline/Models/Bookmark.swift
@@ -34,6 +34,10 @@ final class Bookmark {
@Transient
var servers: [Bookmark] = []
+ func hash(into hasher: inout Hasher) {
+
+ }
+
@Transient
var displayAddress: String {
switch self.type {
@@ -53,25 +57,6 @@ final class Bookmark {
return "\(self.address):\(String(self.port))"
}
}
-
-// if let s = server {
-// if s.port == HotlinePorts.DefaultServerPort {
-// return s.address
-// }
-// else {
-// return "\(s.address):\(s.port)"
-// }
-// }
-// else if let b = bookmark {
-// if b.port == HotlinePorts.DefaultServerPort {
-// return b.address
-// }
-// else {
-// return "\(b.address):\(b.port)"
-// }
-// }
-
-// return nil
}
@Transient
diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift
index ab70389..104e15d 100644
--- a/Hotline/macOS/TrackerView.swift
+++ b/Hotline/macOS/TrackerView.swift
@@ -11,6 +11,7 @@ struct TrackerView: View {
@State private var refreshing = false
@State private var trackerSheetPresented: Bool = false
@State private var trackerSheetBookmark: Bookmark? = nil
+ @State private var attemptedPrepopulate: Bool = false
@Query(sort: \Bookmark.order) private var bookmarks: [Bookmark]
@State private var selection: Bookmark? = nil
@@ -46,12 +47,22 @@ struct TrackerView: View {
.environment(\.defaultMinListRowHeight, 34)
.listStyle(.inset)
.alternatingRowBackgrounds(.enabled)
- .onAppear {
-// Bookmark.deleteAll(context: modelContext)
+ .onChange(of: ApplicationState.shared.cloudKitReady) {
+ if attemptedPrepopulate {
+ print("Tracker: Already attempted to prepopulate bookmarks")
+ return
+ }
+
+ print("Tracker: Prepopulating bookmarks")
+
+ attemptedPrepopulate = true
// Make sure default bookmarks are there when empty.
Bookmark.populateDefaults(context: modelContext)
}
+ .onAppear {
+// Bookmark.deleteAll(context: modelContext)
+ }
.contextMenu(forSelectionType: Bookmark.self) { items in
if let item = items.first {
if item.type == .temporary {
@@ -174,15 +185,6 @@ struct TrackerView: View {
.help("Connect to Server")
}
}
-// .onReceive(NotificationCenter.default.publisher(for: NSNotification.BookmarkAdded)) { notification in
-// guard let bookmarks = bookmarks.bookmarks, let userInfo = notification.userInfo else {
-// return
-// }
-//
-// if let i = userInfo["index"] as? Int, bookmarks.count > i {
-// self.servers.insert(TrackerItem(bookmark: bookmarks[i]), at: i)
-// }
-// }
.onOpenURL(perform: { url in
if let s = Server(url: url) {
openWindow(id: "server", value: s)
@@ -309,7 +311,7 @@ struct TrackerItemView: View {
let bookmark: Bookmark
var body: some View {
- HStack(alignment: .center, spacing: 8) {
+ HStack(alignment: .center, spacing: 6) {
if bookmark.type == .tracker {
Button {
bookmark.expanded.toggle()
@@ -323,6 +325,7 @@ struct TrackerItemView: View {
.buttonStyle(.plain)
.frame(width: 10)
.padding(.leading, 4)
+ .padding(.trailing, 2)
}
switch bookmark.type {
@@ -345,6 +348,7 @@ struct TrackerItemView: View {
.frame(width: 11, height: 11, alignment: .center)
.opacity(0.5)
.padding(.leading, 3)
+ .padding(.trailing, 2)
Image("Server")
.resizable()
.scaledToFit()