diff --git a/Sources/Packages/Resources/Localizable.xcstrings b/Sources/Packages/Resources/Localizable.xcstrings index b316d10..89f8b34 100644 --- a/Sources/Packages/Resources/Localizable.xcstrings +++ b/Sources/Packages/Resources/Localizable.xcstrings @@ -2901,6 +2901,28 @@ } } }, + "empty_store_modifiable_empty_os_warning_description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "It looks like you may have recently updated macOS. Sometimes this puts the Secure Enclave into a weird state, and you might need to reboot your Mac before things start working again." + } + } + } + }, + "empty_store_modifiable_empty_os_warning_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Missing Secrets?" + } + } + } + }, "empty_store_nonmodifiable_description" : { "extractionState" : "manual", "localizations" : { diff --git a/Sources/Secretive.xcodeproj/project.pbxproj b/Sources/Secretive.xcodeproj/project.pbxproj index 1164461..96c6479 100644 --- a/Sources/Secretive.xcodeproj/project.pbxproj +++ b/Sources/Secretive.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 504788F22E681F3A00B4556F /* Instructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F12E681F3A00B4556F /* Instructions.swift */; }; 504788F42E681F6900B4556F /* ToolConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F32E681F6900B4556F /* ToolConfigurationView.swift */; }; 504788F62E68206F00B4556F /* GettingStartedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F52E68206F00B4556F /* GettingStartedView.swift */; }; + 504789232E697DD300B4556F /* BoxBackgroundStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */; }; 50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; }; 50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; }; 50617D8323FCE48E0099B055 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* App.swift */; }; @@ -118,6 +119,7 @@ 504788F12E681F3A00B4556F /* Instructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instructions.swift; sourceTree = ""; }; 504788F32E681F6900B4556F /* ToolConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolConfigurationView.swift; sourceTree = ""; }; 504788F52E68206F00B4556F /* GettingStartedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GettingStartedView.swift; sourceTree = ""; }; + 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxBackgroundStyle.swift; sourceTree = ""; }; 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = ""; }; 50571E0424393D1500F76F6C /* LaunchAgentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAgentController.swift; sourceTree = ""; }; 50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -198,6 +200,7 @@ children = ( 50CF4ABB2E601B0F005588DC /* ActionButtonStyle.swift */, 50BDCB732E6436C60072D2E7 /* ErrorStyle.swift */, + 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */, 5065E312295517C500E16645 /* ToolbarButtonStyle.swift */, ); path = Styles; @@ -491,6 +494,7 @@ 2C4A9D2F2636FFD3008CC8E2 /* EditSecretView.swift in Sources */, 5091D2BC25183B830049FD9B /* ApplicationDirectoryController.swift in Sources */, 504788EC2E680DC800B4556F /* URLs.swift in Sources */, + 504789232E697DD300B4556F /* BoxBackgroundStyle.swift in Sources */, 5066A6C22516F303004B5A36 /* SetupView.swift in Sources */, 5065E313295517C500E16645 /* ToolbarButtonStyle.swift in Sources */, 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */, diff --git a/Sources/Secretive/App.swift b/Sources/Secretive/App.swift index 93ecf03..64cc298 100644 --- a/Sources/Secretive/App.swift +++ b/Sources/Secretive/App.swift @@ -25,6 +25,9 @@ extension EnvironmentValues { }() @Entry var updater: any UpdaterProtocol = _updater + private static let _justUpdatedChecker = JustUpdatedChecker() + @Entry var justUpdatedChecker: any JustUpdatedCheckerProtocol = _justUpdatedChecker + @MainActor var secretStoreList: SecretStoreList { EnvironmentValues._secretStoreList } @@ -33,8 +36,8 @@ extension EnvironmentValues { @main struct Secretive: App { - private let justUpdatedChecker = JustUpdatedChecker() @Environment(\.agentStatusChecker) var agentStatusChecker + @Environment(\.justUpdatedChecker) var justUpdatedChecker @AppStorage("defaultsHasRunSetup") var hasRunSetup = false @State private var showingSetup = false @State private var showingIntegrations = false @@ -52,7 +55,7 @@ struct Secretive: App { .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in guard hasRunSetup else { return } agentStatusChecker.check() - if agentStatusChecker.running && justUpdatedChecker.justUpdated { + if agentStatusChecker.running && justUpdatedChecker.justUpdatedBuild { // Relaunch the agent, since it'll be running from earlier update still reinstallAgent() } else if !agentStatusChecker.running && !agentStatusChecker.developmentBuild { @@ -89,7 +92,6 @@ struct Secretive: App { extension Secretive { private func reinstallAgent() { - justUpdatedChecker.check() Task { _ = await LaunchAgentController().install() try? await Task.sleep(for: .seconds(1)) diff --git a/Sources/Secretive/Controllers/JustUpdatedChecker.swift b/Sources/Secretive/Controllers/JustUpdatedChecker.swift index 7b25eef..75e9483 100644 --- a/Sources/Secretive/Controllers/JustUpdatedChecker.swift +++ b/Sources/Secretive/Controllers/JustUpdatedChecker.swift @@ -1,23 +1,33 @@ import Foundation import AppKit -protocol JustUpdatedCheckerProtocol: Observable { - var justUpdated: Bool { get } +@MainActor protocol JustUpdatedCheckerProtocol: Observable { + var justUpdatedBuild: Bool { get } + var justUpdatedOS: Bool { get } } -@Observable class JustUpdatedChecker: JustUpdatedCheckerProtocol { +@Observable @MainActor class JustUpdatedChecker: JustUpdatedCheckerProtocol { - var justUpdated: Bool = false + var justUpdatedBuild: Bool = false + var justUpdatedOS: Bool = false - init() { - check() + nonisolated init() { + Task { @MainActor in + check() + } } - func check() { - let lastBuild = UserDefaults.standard.object(forKey: Constants.previousVersionUserDefaultsKey) as? String ?? "None" + private func check() { + let lastBuild = UserDefaults.standard.object(forKey: Constants.previousVersionUserDefaultsKey) as? String + let lastOS = UserDefaults.standard.object(forKey: Constants.previousOSVersionUserDefaultsKey) as? String let currentBuild = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String + let osRaw = ProcessInfo.processInfo.operatingSystemVersion + let currentOS = "\(osRaw.majorVersion).\(osRaw.minorVersion).\(osRaw.patchVersion)" UserDefaults.standard.set(currentBuild, forKey: Constants.previousVersionUserDefaultsKey) - justUpdated = lastBuild != currentBuild + UserDefaults.standard.set(currentOS, forKey: Constants.previousOSVersionUserDefaultsKey) + justUpdatedBuild = lastBuild != currentBuild + // To prevent this showing on first lauch for every user, only show if lastBuild is non-nil. + justUpdatedOS = lastBuild != nil && lastOS != currentOS } @@ -28,6 +38,7 @@ extension JustUpdatedChecker { enum Constants { static let previousVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastBuild" + static let previousOSVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastOS" } } diff --git a/Sources/Secretive/Views/Secrets/CreateSecretView.swift b/Sources/Secretive/Views/Secrets/CreateSecretView.swift index cbe4afe..78fd4e6 100644 --- a/Sources/Secretive/Views/Secrets/CreateSecretView.swift +++ b/Sources/Secretive/Views/Secrets/CreateSecretView.swift @@ -66,7 +66,7 @@ struct CreateSecretView: View { Text(.createSecretBiometryCurrentWarning) .padding(.horizontal, 10) .padding(.vertical, 3) - .background(.red.opacity(0.5), in: RoundedRectangle(cornerRadius: 5)) + .boxBackground(color: .red) } } @@ -85,7 +85,7 @@ struct CreateSecretView: View { Text(.createSecretMldsaWarning) .padding(.horizontal, 10) .padding(.vertical, 3) - .background(.red.opacity(0.5), in: RoundedRectangle(cornerRadius: 5)) + .boxBackground(color: .orange) } } VStack(alignment: .leading) { diff --git a/Sources/Secretive/Views/Secrets/EmptyStoreView.swift b/Sources/Secretive/Views/Secrets/EmptyStoreView.swift index 2552443..c21cf95 100644 --- a/Sources/Secretive/Views/Secrets/EmptyStoreView.swift +++ b/Sources/Secretive/Views/Secrets/EmptyStoreView.swift @@ -27,7 +27,9 @@ struct EmptyStoreImmutableView: View { } struct EmptyStoreModifiableView: View { - + + @Environment(\.justUpdatedChecker) var justUpdatedChecker + var body: some View { GeometryReader { windowGeometry in VStack { @@ -51,6 +53,21 @@ struct EmptyStoreModifiableView: View { }.frame(height: (windowGeometry.size.height/2) - 20).padding() Text(.emptyStoreModifiableClickHereTitle).bold() Text(.emptyStoreModifiableClickHereDescription) + if justUpdatedChecker.justUpdatedOS { + Spacer() + .frame(height: 20) + VStack(spacing: 10) { + Text(.emptyStoreModifiableEmptyOsWarningTitle) + .font(.title2) + .bold() + Text(.emptyStoreModifiableEmptyOsWarningDescription) + .fixedSize(horizontal: false, vertical: true) + .bold() + } + .padding() + .boxBackground(color: .orange) + .padding() + } Spacer() }.frame(maxWidth: .infinity, maxHeight: .infinity) } @@ -61,6 +78,10 @@ struct EmptyStoreModifiableView: View { #Preview { EmptyStoreImmutableView() } +#Preview { + EmptyStoreImmutableView() +// .environment(\.justUpdatedChecker, <#T##value: V##V#>) +} #Preview { EmptyStoreModifiableView() } diff --git a/Sources/Secretive/Views/Styles/BoxBackgroundStyle.swift b/Sources/Secretive/Views/Styles/BoxBackgroundStyle.swift new file mode 100644 index 0000000..8ffbf38 --- /dev/null +++ b/Sources/Secretive/Views/Styles/BoxBackgroundStyle.swift @@ -0,0 +1,32 @@ +import SwiftUI + +struct BoxBackgroundModifier: ViewModifier { + + let color: Color + + func body(content: Content) -> some View { + content + .background { + RoundedRectangle(cornerRadius: 5) + .fill(color.opacity(0.3)) + .stroke(color, lineWidth: 1) + } + } +} + +extension View { + + func boxBackground(color: Color) -> some View { + modifier(BoxBackgroundModifier(color: color)) + } + +} + +#Preview { + Text("Hello") + .boxBackground(color: .red) + .padding() + Text("Hello") + .boxBackground(color: .orange) + .padding() +}