diff --git a/.github/readme/app-dark.png b/.github/readme/app-dark.png index c7f5e8d..68bf4eb 100644 Binary files a/.github/readme/app-dark.png and b/.github/readme/app-dark.png differ diff --git a/.github/readme/app-light.png b/.github/readme/app-light.png index d0ecb89..d231aaa 100644 Binary files a/.github/readme/app-light.png and b/.github/readme/app-light.png differ diff --git a/.github/readme/notification.png b/.github/readme/notification.png index 069ee07..47d53fc 100644 Binary files a/.github/readme/notification.png and b/.github/readme/notification.png differ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 555a43c..1aa1eaf 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -9,7 +9,7 @@ jobs: runs-on: macos-15 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup Signing env: SIGNING_DATA: ${{ secrets.SIGNING_DATA }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb58539..be8cc51 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: runs-on: macos-15 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup Signing env: SIGNING_DATA: ${{ secrets.SIGNING_DATA }} @@ -32,7 +32,7 @@ jobs: runs-on: macos-15 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup Signing env: SIGNING_DATA: ${{ secrets.SIGNING_DATA }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20b4db8..f9d9048 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: runs-on: macos-15 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set Environment run: sudo xcrun xcode-select -s /Applications/Xcode_26_beta_5.app - name: Test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8503c33..902fddc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ If you'd like to contribute a translation, please see [Localizing](LOCALIZING.md ## Credits -If you make a material contribution to the app, please add yourself to the end of the [credits](https://github.com/maxgoedjen/secretive/blob/main/Secretive/Credits.rtf). +If you make a material contribution to the app, please add yourself to the end of the [credits](https://github.com/maxgoedjen/secretive/blob/main/Sources/Secretive/Credits.rtf). ## Collaborator Status diff --git a/DESIGN.md b/Design/DESIGN.md similarity index 100% rename from DESIGN.md rename to Design/DESIGN.md diff --git a/Design/Icon.icon/Assets/Icon 7.png b/Design/Icon.icon/Assets/Icon 7.png new file mode 100644 index 0000000..2bfab03 Binary files /dev/null and b/Design/Icon.icon/Assets/Icon 7.png differ diff --git a/Design/Icon.icon/Assets/Rectangle 2 8.png b/Design/Icon.icon/Assets/Rectangle 2 8.png new file mode 100644 index 0000000..7ed1192 Binary files /dev/null and b/Design/Icon.icon/Assets/Rectangle 2 8.png differ diff --git a/Design/Icon.icon/Assets/Rectangle Copy 10.png b/Design/Icon.icon/Assets/Rectangle Copy 10.png new file mode 100644 index 0000000..7b118b6 Binary files /dev/null and b/Design/Icon.icon/Assets/Rectangle Copy 10.png differ diff --git a/Design/Icon.icon/icon.json b/Design/Icon.icon/icon.json new file mode 100644 index 0000000..8c665bb --- /dev/null +++ b/Design/Icon.icon/icon.json @@ -0,0 +1,59 @@ +{ + "fill" : { + "solid" : "srgb:0.00000,0.53333,1.00000,0.00000" + }, + "groups" : [ + { + "blur-material" : 0.5, + "layers" : [ + { + "image-name" : "Icon 7.png", + "name" : "Signature", + "position" : { + "scale" : 1, + "translation-in-points" : [ + 64.00083178971097, + -58.21801551632592 + ] + } + }, + { + "image-name" : "Rectangle Copy 10.png", + "name" : "Border" + }, + { + "fill-specializations" : [ + { + "appearance" : "tinted", + "value" : { + "solid" : "display-p3:0.00000,0.00000,0.00000,0.50000" + } + } + ], + "image-name" : "Rectangle 2 8.png", + "name" : "Backing", + "opacity-specializations" : [ + { + "appearance" : "tinted", + "value" : 1 + } + ] + } + ], + "shadow" : { + "kind" : "layer-color", + "opacity" : 0.5 + }, + "specular" : true, + "translucency" : { + "enabled" : true, + "value" : 0.5 + } + } + ], + "supported-platforms" : { + "squares" : [ + "macOS" + ] + } +} \ No newline at end of file diff --git a/Sources/Packages/Package.swift b/Sources/Packages/Package.swift index afe1965..820da97 100644 --- a/Sources/Packages/Package.swift +++ b/Sources/Packages/Package.swift @@ -88,6 +88,6 @@ var localization: Resource { var swiftSettings: [PackageDescription.SwiftSetting] { [ .swiftLanguageMode(.v6), - .unsafeFlags(["-warnings-as-errors"]), + .treatAllWarnings(as: .error), ] } diff --git a/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index c14ca73..0000000 --- a/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "filename" : "Mac Icon.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "filename" : "Mac Icon@0.25x.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Mac Icon.png b/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Mac Icon.png deleted file mode 100644 index 99a172b..0000000 Binary files a/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Mac Icon.png and /dev/null differ diff --git a/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png b/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png deleted file mode 100644 index 8b7b7ae..0000000 Binary files a/Sources/SecretAgent/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png and /dev/null differ diff --git a/Sources/SecretAgent/Assets.xcassets/Contents.json b/Sources/SecretAgent/Assets.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/Sources/SecretAgent/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/Secretive.xcodeproj/project.pbxproj b/Sources/Secretive.xcodeproj/project.pbxproj index 945b664..0c85007 100644 --- a/Sources/Secretive.xcodeproj/project.pbxproj +++ b/Sources/Secretive.xcodeproj/project.pbxproj @@ -19,7 +19,8 @@ 5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */; }; 5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF642780081B00DF2006 /* SmartCardSecretKit */; }; 5008C23E2E525D8900507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; }; - 5008C23F2E525D8900507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; }; + 5008C2402E52792400507AC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; }; + 5008C2412E52D18700507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; }; 501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; }; 501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; }; @@ -46,7 +47,6 @@ 508BF2AA25B4F1CB009EFB7E /* InternetAccessPolicy.plist in Resources */ = {isa = PBXBuildFile; fileRef = 508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */; }; 5091D2BC25183B830049FD9B /* ApplicationDirectoryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */; }; 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */; }; - 50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; }; 50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79324026B7600D209EA /* Preview Assets.xcassets */; }; 50A3B79724026B7600D209EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79524026B7600D209EA /* Main.storyboard */; }; 50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; }; @@ -133,7 +133,6 @@ 5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDirectoryController.swift; sourceTree = ""; }; 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSecretView.swift; sourceTree = ""; }; 50A3B78A24026B7500D209EA /* SecretAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecretAgent.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 50A3B79024026B7600D209EA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50A3B79324026B7600D209EA /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 50A3B79624026B7600D209EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50A3B79824026B7600D209EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -281,7 +280,6 @@ children = ( 50020BAF24064869003D4025 /* AppDelegate.swift */, 5018F54E24064786002EB505 /* Notifier.swift */, - 50A3B79024026B7600D209EA /* Assets.xcassets */, 50A3B79524026B7600D209EA /* Main.storyboard */, 50A3B79824026B7600D209EA /* Info.plist */, 508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */, @@ -418,10 +416,10 @@ buildActionMask = 2147483647; files = ( 50A3B79724026B7600D209EA /* Main.storyboard in Resources */, - 5008C23F2E525D8900507AC2 /* Localizable.xcstrings in Resources */, + 5008C2412E52D18700507AC2 /* Localizable.xcstrings in Resources */, 50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */, - 50A3B79124026B7600D209EA /* Assets.xcassets in Resources */, 508BF2AA25B4F1CB009EFB7E /* InternetAccessPolicy.plist in Resources */, + 5008C2402E52792400507AC2 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json index c14ca73..a78196d 100644 --- a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,53 +1,61 @@ { "images" : [ { + "filename" : "Icon-macOS-ClearDark-16x16@1x.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { + "filename" : "Icon-macOS-ClearDark-16x16@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { + "filename" : "Icon-macOS-ClearDark-32x32@1x.png", "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { + "filename" : "Icon-macOS-ClearDark-32x32@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { + "filename" : "Icon-macOS-ClearDark-128x128@1x.png", "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { + "filename" : "Icon-macOS-ClearDark-128x128@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { - "filename" : "Mac Icon.png", + "filename" : "Icon-macOS-ClearDark-256x256@1x.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { - "filename" : "Mac Icon@0.25x.png", + "filename" : "Icon-macOS-ClearDark-256x256@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { + "filename" : "Icon-macOS-ClearDark-512x512@1x.png", "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { + "filename" : "Icon-macOS-ClearDark-1024x1024@1x.png", "idiom" : "mac", "scale" : "2x", "size" : "512x512" diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-1024x1024@1x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-1024x1024@1x.png new file mode 100644 index 0000000..d4a5a06 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-1024x1024@1x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-128x128@1x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-128x128@1x.png new file mode 100644 index 0000000..639811c Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-128x128@1x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-128x128@2x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-128x128@2x.png new file mode 100644 index 0000000..68c79a1 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-128x128@2x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-16x16@1x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-16x16@1x.png new file mode 100644 index 0000000..13e16f5 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-16x16@1x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-16x16@2x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-16x16@2x.png new file mode 100644 index 0000000..0f9c355 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-16x16@2x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-256x256@1x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-256x256@1x.png new file mode 100644 index 0000000..68c79a1 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-256x256@1x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-256x256@2x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-256x256@2x.png new file mode 100644 index 0000000..e433fab Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-256x256@2x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-32x32@1x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-32x32@1x.png new file mode 100644 index 0000000..29ffd13 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-32x32@1x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-32x32@2x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-32x32@2x.png new file mode 100644 index 0000000..8b67748 Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-32x32@2x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-512x512@1x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-512x512@1x.png new file mode 100644 index 0000000..e433fab Binary files /dev/null and b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Icon-macOS-ClearDark-512x512@1x.png differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon.png deleted file mode 100644 index 99a172b..0000000 Binary files a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon.png and /dev/null differ diff --git a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png b/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png deleted file mode 100644 index 8b7b7ae..0000000 Binary files a/Sources/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png and /dev/null differ diff --git a/Sources/Secretive/Assets.xcassets/Contents.json b/Sources/Secretive/Assets.xcassets/Contents.json index da4a164..73c0059 100644 --- a/Sources/Secretive/Assets.xcassets/Contents.json +++ b/Sources/Secretive/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Sources/Secretive/Views/ContentView.swift b/Sources/Secretive/Views/ContentView.swift index bd13227..e57f5d8 100644 --- a/Sources/Secretive/Views/ContentView.swift +++ b/Sources/Secretive/Views/ContentView.swift @@ -30,7 +30,7 @@ struct ContentView: View { } .frame(minWidth: 640, minHeight: 320) .toolbar { - toolbarItem(updateNoticeView, id: "update") +// toolbarItem(updateNoticeView, id: "update") toolbarItem(runningOrRunSetupView, id: "setup") toolbarItem(appPathNoticeView, id: "appPath") toolbarItem(newItemView, id: "new") @@ -45,10 +45,16 @@ struct ContentView: View { extension ContentView { - func toolbarItem(_ view: some View, id: String) -> ToolbarItem { - ToolbarItem(id: id) { view } + @ToolbarContentBuilder + func toolbarItem(_ view: some View, id: String) -> some ToolbarContent { + if #available(macOS 26.0, *) { + ToolbarItem(id: id) { view } + .sharedBackgroundVisibility(.hidden) + } else { + ToolbarItem(id: id) { view } + } } - + var needsSetup: Bool { (runningSetup || !hasRunSetup || !agentStatusChecker.running) && !agentStatusChecker.developmentBuild } diff --git a/Sources/Secretive/Views/CopyableView.swift b/Sources/Secretive/Views/CopyableView.swift index c62e595..a5d6e1a 100644 --- a/Sources/Secretive/Views/CopyableView.swift +++ b/Sources/Secretive/Views/CopyableView.swift @@ -8,9 +8,8 @@ struct CopyableView: View { var text: String @State private var interactionState: InteractionState = .normal - @Environment(\.colorScheme) private var colorScheme - - var body: some View { + + var content: some View { VStack(alignment: .leading) { HStack { image @@ -22,7 +21,7 @@ struct CopyableView: View { .foregroundColor(primaryTextColor) Spacer() if interactionState != .normal { - Text(hoverText) + hoverIcon .bold() .textCase(.uppercase) .foregroundColor(secondaryTextColor) @@ -39,17 +38,23 @@ struct CopyableView: View { .multilineTextAlignment(.leading) .font(.system(.body, design: .monospaced)) } - .background(backgroundColor) + ._background(interactionState: interactionState) .frame(minWidth: 150, maxWidth: .infinity) - .cornerRadius(10) + } + + var body: some View { + content .onHover { hovering in withAnimation { interactionState = hovering ? .hovering : .normal } } - .onDrag { + .onDrag({ NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: UTType.utf8PlainText.identifier) - } + }, preview: { + content + ._background(interactionState: .dragging) + }) .onTapGesture { copy() withAnimation { @@ -66,31 +71,23 @@ struct CopyableView: View { ) } - var hoverText: LocalizedStringResource { + @ViewBuilder + var hoverIcon: some View { switch interactionState { case .hovering: - return .copyableClickToCopyButton + Image(systemName: "document.on.document") + .accessibilityLabel(String(localized: "copyable_click_to_copy_button")) case .clicking: - return .copyableCopied - case .normal: - fatalError() - } - } - - var backgroundColor: Color { - switch interactionState { - case .normal: - return colorScheme == .dark ? Color(white: 0.2) : Color(white: 0.885) - case .hovering: - return colorScheme == .dark ? Color(white: 0.275) : Color(white: 0.82) - case .clicking: - return .accentColor + Image(systemName: "checkmark.circle.fill") + .accessibilityLabel(String(localized: "copyable_copied")) + case .normal, .dragging: + EmptyView() } } var primaryTextColor: Color { switch interactionState { - case .normal, .hovering: + case .normal, .hovering, .dragging: return Color(.textColor) case .clicking: return .white @@ -99,7 +96,7 @@ struct CopyableView: View { var secondaryTextColor: Color { switch interactionState { - case .normal, .hovering: + case .normal, .hovering, .dragging: return Color(.secondaryLabelColor) case .clicking: return .white @@ -111,10 +108,57 @@ struct CopyableView: View { NSPasteboard.general.setString(text, forType: .string) } - private enum InteractionState { - case normal, hovering, clicking +} + +fileprivate enum InteractionState { + case normal, hovering, clicking, dragging +} + +extension View { + + fileprivate func _background(interactionState: InteractionState) -> some View { + modifier(BackgroundViewModifier(interactionState: interactionState)) + } + +} + +fileprivate struct BackgroundViewModifier: ViewModifier { + + @Environment(\.colorScheme) private var colorScheme + + let interactionState: InteractionState + + func body(content: Content) -> some View { + if interactionState == .dragging { + content + .background(backgroundColor(interactionState: interactionState), in: RoundedRectangle(cornerRadius: 15)) + } else { + if #available(macOS 26.0, *) { + content + // Very thin opacity lets user hover anywhere over the view, glassEffect doesn't allow. + .background(.white.opacity(0.01), in: RoundedRectangle(cornerRadius: 15)) + .glassEffect(.regular.tint(backgroundColor(interactionState: interactionState)), in: RoundedRectangle(cornerRadius: 15)) + + } else { + content + .background(backgroundColor(interactionState: interactionState)) + .cornerRadius(10) + } + } + } + + func backgroundColor(interactionState: InteractionState) -> Color { + switch interactionState { + case .normal: + return colorScheme == .dark ? Color(white: 0.2) : Color(white: 0.885) + case .hovering, .dragging: + return colorScheme == .dark ? Color(white: 0.275) : Color(white: 0.82) + case .clicking: + return .accentColor + } } + } #if DEBUG diff --git a/Sources/Secretive/Views/ToolbarButtonStyle.swift b/Sources/Secretive/Views/ToolbarButtonStyle.swift index a80cde4..7dd1f65 100644 --- a/Sources/Secretive/Views/ToolbarButtonStyle.swift +++ b/Sources/Secretive/Views/ToolbarButtonStyle.swift @@ -16,22 +16,42 @@ struct ToolbarButtonStyle: ButtonStyle { self.lightColor = lightColor self.darkColor = darkColor } + + @available(macOS 26.0, *) + private var glassTint: Color { + if !hovering { + colorScheme == .light ? lightColor : darkColor + } else { + colorScheme == .light ? lightColor.exposureAdjust(1) : darkColor.exposureAdjust(1) + } + } func makeBody(configuration: Configuration) -> some View { - configuration.label - .padding(EdgeInsets(top: 6, leading: 8, bottom: 6, trailing: 8)) - .background(colorScheme == .light ? lightColor : darkColor) - .foregroundColor(.white) - .clipShape(RoundedRectangle(cornerRadius: 5)) - .overlay( - RoundedRectangle(cornerRadius: 5) - .stroke(colorScheme == .light ? .black.opacity(0.15) : .white.opacity(0.15), lineWidth: 1) - .background(hovering ? (colorScheme == .light ? .black.opacity(0.1) : .white.opacity(0.05)) : Color.clear) - ) - .onHover { hovering in - withAnimation { + if #available(macOS 26.0, *) { + configuration + .label + .foregroundColor(.white) + .padding(EdgeInsets(top: 6, leading: 8, bottom: 6, trailing: 8)) + .glassEffect(.regular.tint(glassTint), in: .capsule) + .onHover { hovering in self.hovering = hovering } - } + } else { + configuration + .label + .background(colorScheme == .light ? lightColor : darkColor) + .foregroundColor(.white) + .clipShape(RoundedRectangle(cornerRadius: 5)) + .overlay( + RoundedRectangle(cornerRadius: 5) + .stroke(colorScheme == .light ? .black.opacity(0.15) : .white.opacity(0.15), lineWidth: 1) + .background(hovering ? (colorScheme == .light ? .black.opacity(0.1) : .white.opacity(0.05)) : Color.clear) + ) + .onHover { hovering in + withAnimation { + self.hovering = hovering + } + } + } } }