diff --git a/windy.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/windy.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/windy.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/windy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/windy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d549ccf..474925f 100644 --- a/windy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/windy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,7 +6,7 @@ "location" : "https://github.com/sindresorhus/KeyboardShortcuts", "state" : { "branch" : "main", - "revision" : "d168f629edcd687383e18c908168520b4f156324" + "revision" : "8b1a9ce78c2f35c8a55dcc95897573abd2cc4f6e" } }, { @@ -15,7 +15,7 @@ "location" : "https://github.com/sindresorhus/LaunchAtLogin", "state" : { "branch" : "main", - "revision" : "7ad6331f9c38953eb1ce8737758e18f7607e984a" + "revision" : "8e28b5e5a9561ace33a26c55d78f74963fbce6f9" } } ], diff --git a/windy.xcodeproj/project.xcworkspace/xcuserdata/lantos.xcuserdatad/IDEFindNavigatorScopes.plist b/windy.xcodeproj/project.xcworkspace/xcuserdata/lantos.xcuserdatad/IDEFindNavigatorScopes.plist new file mode 100644 index 0000000..5dd5da8 --- /dev/null +++ b/windy.xcodeproj/project.xcworkspace/xcuserdata/lantos.xcuserdatad/IDEFindNavigatorScopes.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/windy.xcodeproj/project.xcworkspace/xcuserdata/lantos.xcuserdatad/WorkspaceSettings.xcsettings b/windy.xcodeproj/project.xcworkspace/xcuserdata/lantos.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..bbfef02 --- /dev/null +++ b/windy.xcodeproj/project.xcworkspace/xcuserdata/lantos.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,14 @@ + + + + + BuildLocationStyle + UseAppPreferences + CustomBuildLocationType + RelativeToDerivedData + DerivedDataLocationStyle + Default + ShowSharedSchemesAutomaticallyEnabled + + + diff --git a/windy.xcodeproj/xcuserdata/lantos.xcuserdatad/xcschemes/xcschememanagement.plist b/windy.xcodeproj/xcuserdata/lantos.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..9aedfd6 --- /dev/null +++ b/windy.xcodeproj/xcuserdata/lantos.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + windy.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/windy/LicenseManager.swift b/windy/LicenseManager.swift index 7615ff4..bde5f31 100644 --- a/windy/LicenseManager.swift +++ b/windy/LicenseManager.swift @@ -8,197 +8,197 @@ import Foundation import IOKit import SwiftUI +// +// +//struct LicenseForm: View { +// @StateObject var windyData : WindyData +// var licenseManager : LicenseManager +// @State private var showingAlert = false +// @State private var alertTitle = "" +// @State private var alertMessage = "" +// +// var body: some View { +// VStack { +// TextField("Email", text: $windyData.email) +// TextField("License Key", text: $windyData.licenseKey) +// HStack{ +// Button("Close") { +// self.licenseManager.closeLicenseForm() +// } +// Button("Verify License") { +// self.licenseManager.verifyLicense() +// } +// .alert(isPresented: $showingAlert) { +// Alert(title: Text(alertTitle), message: Text(alertMessage), dismissButton: .default(Text("OK"))) +// } +// +// } +// }.padding() +// } +//} +// +// +//class LicenseManager { +// private let windyData : WindyData +// private var verificationTimer : Timer? +// private let verificationInterval: TimeInterval = 10000.0 // Set to desired interval in seconds +// private let gracePeriod : TimeInterval = 60.0 * 60.0 * 24.0 // 24 hours for example +// private var lastSuccessfulVerification: Date? = nil +// private static let licenseServer = "http://localhost:3000" +// private static let licenseURI = "/api/licenseHeartbeat" +// let licenseURL = URL(string: licenseServer + licenseURI)! +// +// private var licenseWindow: NSWindow? +// +// init(windyData: WindyData) { +// self.windyData = windyData +// } +// +// func closeLicenseForm() { +// self.licenseWindow?.close() +// self.licenseWindow = nil +// } +// +// func displayLicenseForm() { +// // check to see if window is avaliable +// if (self.licenseWindow != nil) { +// if(self.licenseWindow!.isVisible == false) { +// self.licenseWindow?.setIsVisible(true); +// return +// } +// return +// } +// +// // create the license window and show it +// +// self.licenseWindow = NSWindow( +// contentRect : NSRect(x: 0, y: 0, width: 400, height: 380), +// styleMask : [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], +// backing : .buffered, +// defer : false +// ) +// +// let licenseForm = LicenseForm(windyData: self.windyData, licenseManager: self) +// self.licenseWindow?.contentView = NSHostingView(rootView: licenseForm) +// self.licenseWindow?.collectionBehavior = .canJoinAllSpaces +// self.licenseWindow?.isReleasedWhenClosed = false +// self.licenseWindow?.setIsVisible(true) +// self.licenseWindow?.center() +// self.licenseWindow?.makeKeyAndOrderFront(nil) +// } +// +// func getComputerId() -> String? { +// var serialNumber: String? = nil +// let platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice")) +// if platformExpert != 0 { +// let serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey as CFString, kCFAllocatorDefault, 0) +// IOObjectRelease(platformExpert) +// if let serialNumberAsCFString = serialNumberAsCFString { +// serialNumber = serialNumberAsCFString.takeRetainedValue() as? String +// } +// } +// return serialNumber +// } -struct LicenseForm: View { - @StateObject var windyData : WindyData - var licenseManager : LicenseManager - @State private var showingAlert = false - @State private var alertTitle = "" - @State private var alertMessage = "" - - var body: some View { - VStack { - TextField("Email", text: $windyData.email) - TextField("License Key", text: $windyData.licenseKey) - HStack{ - Button("Close") { - self.licenseManager.closeLicenseForm() - } - Button("Verify License") { - self.licenseManager.verifyLicense() - } - .alert(isPresented: $showingAlert) { - Alert(title: Text(alertTitle), message: Text(alertMessage), dismissButton: .default(Text("OK"))) - } - - } - }.padding() - } -} - - - -class LicenseManager { - private let windyData : WindyData - private var verificationTimer : Timer? - private let verificationInterval: TimeInterval = 60.0 // Set to desired interval in seconds - private let gracePeriod : TimeInterval = 60.0 * 60.0 * 24.0 // 24 hours for example - private var lastSuccessfulVerification: Date? = nil - private static let licenseServer = "http://localhost:3000" - private static let licenseURI = "/api/licenseHeartbeat" - let licenseURL = URL(string: licenseServer + licenseURI)! - - private var licenseWindow: NSWindow? - - init(windyData: WindyData) { - self.windyData = windyData - } - - func closeLicenseForm() { - self.licenseWindow?.close() - self.licenseWindow = nil - } - - func displayLicenseForm() { - // check to see if window is avaliable - if (self.licenseWindow != nil) { - if(self.licenseWindow!.isVisible == false) { - self.licenseWindow?.setIsVisible(true); - return - } - return - } - - // create the license window and show it - - self.licenseWindow = NSWindow( - contentRect : NSRect(x: 0, y: 0, width: 400, height: 380), - styleMask : [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], - backing : .buffered, - defer : false - ) - - let licenseForm = LicenseForm(windyData: self.windyData, licenseManager: self) - self.licenseWindow?.contentView = NSHostingView(rootView: licenseForm) - self.licenseWindow?.collectionBehavior = .canJoinAllSpaces - self.licenseWindow?.isReleasedWhenClosed = false - self.licenseWindow?.setIsVisible(true) - self.licenseWindow?.center() - self.licenseWindow?.makeKeyAndOrderFront(nil) - } - - func getComputerId() -> String? { - var serialNumber: String? = nil - let platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice")) - if platformExpert != 0 { - let serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey as CFString, kCFAllocatorDefault, 0) - IOObjectRelease(platformExpert) - if let serialNumberAsCFString = serialNumberAsCFString { - serialNumber = serialNumberAsCFString.takeRetainedValue() as? String - } - } - return serialNumber - } - - - func sendHeartbeat(licenseKey: String, email: String, completion: @escaping (Result) -> Void) { - guard let computerId = getComputerId() else { - // Handle error: Could not get computer id - return - } - - if (licenseKey == "") { - displayLicenseForm() - return - } - - var request = URLRequest(url: licenseURL) - request.httpMethod = "POST" - request.addValue("application/json", forHTTPHeaderField: "Content-Type") - - - let body = [ - "licenseKey" : licenseKey, - "email" : email, - "computerId" : computerId - ] - - do { - request.httpBody = try JSONSerialization.data(withJSONObject: body) - } catch { - completion(.failure(error)) - return - } - - let task = URLSession.shared.dataTask(with: request) { - (data, response, error) in - if let error = error { - completion(.failure(error)) - return - } - - if let data = data { - do { - if let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any], - let message = jsonObject["message"] as? String { - completion(.success(message)) - } - } catch { - completion(.failure(error)) - } - } - } - - task.resume() - } - - - func startHeartbeat() { - self.verifyLicense() - self.verificationTimer = Timer.scheduledTimer(withTimeInterval: verificationInterval, repeats: true) { [weak self] _ in - self?.verifyLicense() - } - } - - func pauseHeartbeat() { - guard let timer = self.verificationTimer else { - return // already paused - } - if(timer.isValid) { - self.verificationTimer?.invalidate() - } - } +// +// func sendHeartbeat(licenseKey: String, email: String, completion: @escaping (Result) -> Void) { +// guard let computerId = getComputerId() else { +// // Handle error: Could not get computer id +// return +// } +// +// if (licenseKey == "") { +// displayLicenseForm() +// return +// } +// +// var request = URLRequest(url: licenseURL) +// request.httpMethod = "POST" +// request.addValue("application/json", forHTTPHeaderField: "Content-Type") +// +// +// let body = [ +// "licenseKey" : licenseKey, +// "email" : email, +// "computerId" : computerId +// ] +// +// do { +// request.httpBody = try JSONSerialization.data(withJSONObject: body) +// } catch { +// completion(.failure(error)) +// return +// } +// +// let task = URLSession.shared.dataTask(with: request) { +// (data, response, error) in +// if let error = error { +// completion(.failure(error)) +// return +// } +// +// if let data = data { +// do { +// if let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any], +// let message = jsonObject["message"] as? String { +// completion(.success(message)) +// } +// } catch { +// completion(.failure(error)) +// } +// } +// } +// +// task.resume() +// } - func verifyLicense() { - debugPrint("verifying license") - sendHeartbeat( - licenseKey: windyData.licenseKey, - email: windyData.email - ) { [weak self] result in - DispatchQueue.main.async { - guard self != nil else { return } - debugPrint("result", result) - - switch result { - case .success(let licenseStatus): - self?.windyData.licenseStatus = licenseStatus - UserDefaults.standard.set(self?.windyData.email, forKey: "email") - UserDefaults.standard.set(self?.windyData.licenseKey, forKey: "licenseKey") - self?.lastSuccessfulVerification = Date() - // Unlock app if necessary - debugPrint("verification successful") - - case .failure(_): - self?.windyData.licenseStatus = "License verification failed" - - let timeSinceLastSuccessfulVerification = Date().timeIntervalSince(self?.lastSuccessfulVerification ?? Date()) - if timeSinceLastSuccessfulVerification > self!.gracePeriod { - // Lock out app - debugPrint("verification unsuccessful") - } - } - } - } - } -} +// +// func startHeartbeat() { +// self.verifyLicense() +// self.verificationTimer = Timer.scheduledTimer(withTimeInterval: verificationInterval, repeats: true) { [weak self] _ in +// self?.verifyLicense() +// } +// } +// +// func pauseHeartbeat() { +// guard let timer = self.verificationTimer else { +// return // already paused +// } +// if(timer.isValid) { +// self.verificationTimer?.invalidate() +// } +// } +// +// func verifyLicense() { +// debugPrint("verifying license") +// sendHeartbeat( +// licenseKey: windyData.licenseKey, +// email: windyData.email +// ) { [weak self] result in +// DispatchQueue.main.async { +// guard self != nil else { return } +// debugPrint("result", result) +// +// switch result { +// case .success(let licenseStatus): +// self?.windyData.licenseStatus = licenseStatus +// UserDefaults.standard.set(self?.windyData.email, forKey: "email") +// UserDefaults.standard.set(self?.windyData.licenseKey, forKey: "licenseKey") +// self?.lastSuccessfulVerification = Date() +// // Unlock app if necessary +// debugPrint("verification successful") +// +// case .failure(_): +// self?.windyData.licenseStatus = "License verification failed" +// +// let timeSinceLastSuccessfulVerification = Date().timeIntervalSince(self?.lastSuccessfulVerification ?? Date()) +// if timeSinceLastSuccessfulVerification > self!.gracePeriod { +// // Lock out app +// debugPrint("verification unsuccessful") +// } +// } +// } +// } +// } +//} diff --git a/windy/MenuPopover.swift b/windy/MenuPopover.swift index ed8b35a..093d4e2 100644 --- a/windy/MenuPopover.swift +++ b/windy/MenuPopover.swift @@ -36,7 +36,7 @@ struct MenuPopover: View { @StateObject var windyData : WindyData @State var window : NSWindow? @State private var isPresentingConfirm : Bool = false - var openLicenseWindowFunc : () -> () +// var openLicenseWindowFunc : () -> () var body: some View { VStack { @@ -63,7 +63,7 @@ struct MenuPopover: View { }.confirmationDialog("Are you sure you want to reset all displaySettings", isPresented: $isPresentingConfirm) { Button("rest keyboard shortcuts", role: .destructive, action: resetKeyboardShortcuts) } - Button("Change License", action: openLicenseWindowFunc) +// Button("Change License", action: openLicenseWindowFunc) LaunchAtLogin.Toggle() Button("Quit Windy") { NSApplication.shared.terminate(self) diff --git a/windy/snapWindow.swift b/windy/snapWindow.swift index 2bb8ae1..1c9f44e 100644 --- a/windy/snapWindow.swift +++ b/windy/snapWindow.swift @@ -7,6 +7,27 @@ import Foundation import Combine +import SwiftUI + + + +struct SnapGridMessageView: View { + var body: some View { + VStack { + Spacer() // Pushes content to the center vertically + HStack { + Text("Hold ESC") + Image(systemName: "escape") + Text("and release window cancel snapping") + } + .padding() // Adds some padding around the HStack + .background() // Example background color + .cornerRadius(10) + Spacer() // Pushes content to the center vertically + } + } +} + class SnapWindowManager { var windyData : WindyData @@ -25,6 +46,11 @@ class SnapWindowManager { backing : .buffered, defer : false ) + + + let hostingView = NSHostingView(rootView: SnapGridMessageView().frame(maxWidth: .infinity, maxHeight: .infinity)) + hostingView.autoresizingMask = [.width, .height] + snapWindow?.contentView = hostingView snapWindow?.backgroundColor = NSColor(windyData.accentColour) snapWindow?.collectionBehavior = .canJoinAllSpaces // allow snap window to be shown on all virtual desktops (spaces) snapWindow?.setIsVisible(false) diff --git a/windy/windyApp.swift b/windy/windyApp.swift index 97afa0e..c7da12f 100644 --- a/windy/windyApp.swift +++ b/windy/windyApp.swift @@ -81,7 +81,7 @@ struct windyApp: App { var body: some Scene { WindowGroup { // disabled here and in the AppDelegate - if false {} + // if false {} } } } @@ -115,7 +115,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { // I have put these here as they need to exist before the Application logic, If this becomes unusable I should move it to windyManager. private var privilegeManager : PrivilegeManager! - private var licenseManager : LicenseManager! +// private var licenseManager : LicenseManager! func hideMainWindow() { @@ -132,7 +132,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { windyData = WindyData() windyManager = WindyManager(windyData: windyData) privilegeManager = PrivilegeManager() - licenseManager = LicenseManager(windyData: windyData) +// licenseManager = LicenseManager(windyData: windyData) // put the windy icon in the mac toolbar @@ -142,7 +142,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { statusBarButton.image!.size = NSSize ( width: 32 , height: 32 ) statusBarButton.action = #selector(togglePopover) - licenseManager.startHeartbeat() +// licenseManager.startHeartbeat() // open the MenuPopover when user clicks the status bar icon @@ -154,8 +154,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { popover.contentViewController = NSHostingController( rootView: MenuPopover( - windyData: self.windyData, - openLicenseWindowFunc: licenseManager.displayLicenseForm + windyData: self.windyData +// openLicenseWindowFunc: licenseManager.displayLicenseForm ) ) // add listener to close the rectangle preview