diff --git a/Sources/Packages/Sources/Brief/Release.swift b/Sources/Packages/Sources/Brief/Release.swift index ebeedad..248fcd7 100644 --- a/Sources/Packages/Sources/Brief/Release.swift +++ b/Sources/Packages/Sources/Brief/Release.swift @@ -2,7 +2,7 @@ import Foundation import SwiftUI /// A release is a representation of a downloadable update. -public struct Release: Codable, Sendable { +public struct Release: Codable, Sendable, Hashable { /// The user-facing name of the release. Typically "Secretive 1.2.3" public let name: String @@ -62,9 +62,9 @@ fileprivate extension AttributedString { return AttributedString("\n") + string .transformingAttributes(\.font) { font in font.value = switch level { - case 2: .title3.bold() - case 3: .title3 - default: .body + case 2: .headline.bold() + case 3: .headline + default: .subheadline } } .transformingAttributes(\.underlineStyle) { underline in diff --git a/Sources/Secretive/Views/Modifiers/ActionButtonStyle.swift b/Sources/Secretive/Views/Modifiers/ActionButtonStyle.swift index 74284a7..70ab463 100644 --- a/Sources/Secretive/Views/Modifiers/ActionButtonStyle.swift +++ b/Sources/Secretive/Views/Modifiers/ActionButtonStyle.swift @@ -24,7 +24,7 @@ extension View { } -struct MenuButtonModifier: ViewModifier { +struct ToolbarCircleButtonModifier: ViewModifier { func body(content: Content) -> some View { if #available(macOS 26.0, *) { @@ -40,8 +40,8 @@ struct MenuButtonModifier: ViewModifier { extension View { - func menuButton() -> some View { - modifier(MenuButtonModifier()) + func toolbarCircleButton() -> some View { + modifier(ToolbarCircleButtonModifier()) } } diff --git a/Sources/Secretive/Views/Modifiers/ToolbarButtonStyle.swift b/Sources/Secretive/Views/Modifiers/ToolbarButtonStyle.swift index e175970..67cfe3c 100644 --- a/Sources/Secretive/Views/Modifiers/ToolbarButtonStyle.swift +++ b/Sources/Secretive/Views/Modifiers/ToolbarButtonStyle.swift @@ -1,6 +1,6 @@ import SwiftUI -struct ToolbarButtonStyle: ButtonStyle { +struct ToolbarStatusButtonStyle: ButtonStyle { private let lightColor: Color private let darkColor: Color @@ -56,3 +56,24 @@ struct ToolbarButtonStyle: ButtonStyle { } } } + +struct ToolbarButtonStyle: ButtonStyle { + + var tint: Color = .white.opacity(0.1) + + func makeBody(configuration: Configuration) -> some View { + if #available(macOS 26.0, *) { + configuration + .label + .padding(10) + .glassEffect(.regular.interactive().tint(tint)) + } else { + configuration + .label + .padding(EdgeInsets(top: 6, leading: 8, bottom: 6, trailing: 8)) + .foregroundColor(.white) + .clipShape(RoundedRectangle(cornerRadius: 5)) + } + } +} + diff --git a/Sources/Secretive/Views/Views/ContentView.swift b/Sources/Secretive/Views/Views/ContentView.swift index 76c9226..c461141 100644 --- a/Sources/Secretive/Views/Views/ContentView.swift +++ b/Sources/Secretive/Views/Views/ContentView.swift @@ -6,19 +6,21 @@ import Brief struct ContentView: View { - @AppStorage("defaultsHasRunSetup") var hasRunSetup = false - @State var showingCreation = false - @State var runningSetup = false - @State var showingAgentInfo = false @State var activeSecret: AnySecret? - @Environment(\.colorScheme) var colorScheme - - @Environment(\.secretStoreList) private var storeList - @Environment(\.updater) private var updater: any UpdaterProtocol - @Environment(\.agentStatusChecker) private var agentStatusChecker: any AgentStatusCheckerProtocol @State private var selectedUpdate: Release? + + @Environment(\.colorScheme) private var colorScheme + @Environment(\.openWindow) private var openWindow + @Environment(\.secretStoreList) private var storeList + @Environment(\.updater) private var updater + @Environment(\.agentStatusChecker) private var agentStatusChecker + + @AppStorage("defaultsHasRunSetup") private var hasRunSetup = false + @State private var showingCreation = false @State private var showingAppPathNotice = false + @State private var runningSetup = false + @State private var showingAgentInfo = false var body: some View { VStack { @@ -102,24 +104,9 @@ extension ContentView { .font(.headline) .foregroundColor(.white) }) - .buttonStyle(ToolbarButtonStyle(color: color)) + .buttonStyle(ToolbarStatusButtonStyle(color: color)) .sheet(item: $selectedUpdate) { update in - VStack { - if updater.currentVersion.isTestBuild { - VStack { - if let description = updater.currentVersion.previewDescription { - Text(description) - } - Link(destination: URL(string: "https://github.com/maxgoedjen/secretive/actions/workflows/nightly.yml")!) { - Button(.updaterDownloadLatestNightlyButton) {} - .frame(maxWidth: .infinity) - .primaryButton() - } - } - .padding() - } - UpdateDetailView(update: update) - } + UpdateDetailView(update: update) } } } @@ -130,7 +117,7 @@ extension ContentView { Button(.appMenuNewSecretButton, systemImage: "plus") { showingCreation = true } - .menuButton() + .toolbarCircleButton() } } @@ -157,7 +144,7 @@ extension ContentView { } }) .buttonStyle( - ToolbarButtonStyle( + ToolbarStatusButtonStyle( lightColor: agentStatusChecker.running ? .black.opacity(0.05) : .red.opacity(0.75), darkColor: agentStatusChecker.running ? .white.opacity(0.05) : .red.opacity(0.5), ) @@ -179,7 +166,7 @@ extension ContentView { .font(.headline) .foregroundColor(.white) }) - .buttonStyle(ToolbarButtonStyle(color: .orange)) + .buttonStyle(ToolbarStatusButtonStyle(color: .orange)) .popover(isPresented: $showingAppPathNotice, attachmentAnchor: attachmentAnchor, arrowEdge: .bottom) { VStack { Image(systemName: "exclamationmark.triangle") diff --git a/Sources/Secretive/Views/Views/UpdateView.swift b/Sources/Secretive/Views/Views/UpdateView.swift index 810e0e8..91f8513 100644 --- a/Sources/Secretive/Views/Views/UpdateView.swift +++ b/Sources/Secretive/Views/Views/UpdateView.swift @@ -3,61 +3,50 @@ import Brief struct UpdateDetailView: View { - @Environment(\.updater) var updater: any UpdaterProtocol + @Environment(\.updater) var updater + @Environment(\.openURL) var openURL let update: Release var body: some View { - VStack { - Text(.updateVersionName(updateName: update.name)).font(.title) - GroupBox(label: Text(.updateReleaseNotesTitle)) { - ScrollView { - attributedBody - } - } - HStack { - if !update.critical { - Button(.updateIgnoreButton) { - Task { - await updater.ignore(release: update) + VStack(spacing: 0) { + HStack { + if !update.critical { + Button(.updateIgnoreButton) { + Task { + await updater.ignore(release: update) + } } + .buttonStyle(ToolbarButtonStyle()) } Spacer() + if updater.currentVersion.isTestBuild { + Button(.updaterDownloadLatestNightlyButton) { + openURL(URL(string: "https://github.com/maxgoedjen/secretive/actions/workflows/nightly.yml")!) + } + .buttonStyle(ToolbarButtonStyle(tint: .accentColor)) + } + Button(.updateUpdateButton) { + openURL(update.html_url) + } + .buttonStyle(ToolbarButtonStyle(tint: .accentColor)) + .keyboardShortcut(.defaultAction) } - Button(.updateUpdateButton) { - NSWorkspace.shared.open(update.html_url) + .padding() + Divider() + Form { + Section { + Text(update.attributedBody) + } header: { + Text(.updateVersionName(updateName: update.name)) .headerProminence(.increased) + } } - .keyboardShortcut(.defaultAction) - } - + .formStyle(.grouped) } - .padding() - .frame(maxWidth: 500) - } - - var attributedBody: Text { - var text = Text(verbatim: "") - for line in update.body.split(whereSeparator: \.isNewline) { - let attributed: Text - let split = line.split(separator: " ") - let unprefixed = split.dropFirst().joined(separator: " ") - if let prefix = split.first { - switch prefix { - case "#": - attributed = Text(unprefixed).font(.title) + Text(verbatim: "\n") - case "##": - attributed = Text(unprefixed).font(.title2) + Text(verbatim: "\n") - case "###": - attributed = Text(unprefixed).font(.title3) + Text(verbatim: "\n") - default: - attributed = Text(line) + Text(verbatim: "\n\n") - } - } else { - attributed = Text(line) + Text(verbatim: "\n\n") - } - text = text + attributed - } - return text } } + +#Preview { + UpdateDetailView(update: .init(name: "3.0.0", prerelease: false, html_url: URL(string: "https://example.com")!, body: "Hello")) +}