mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-04-10 17:47:19 +00:00
Quick prompting for stuff on debug/test builds
This commit is contained in:
parent
6eee29e1fa
commit
b8411008ae
@ -4,12 +4,14 @@ import Combine
|
|||||||
public protocol UpdaterProtocol: ObservableObject {
|
public protocol UpdaterProtocol: ObservableObject {
|
||||||
|
|
||||||
var update: Release? { get }
|
var update: Release? { get }
|
||||||
|
var testBuild: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Updater: ObservableObject, UpdaterProtocol {
|
public class Updater: ObservableObject, UpdaterProtocol {
|
||||||
|
|
||||||
@Published public var update: Release?
|
@Published public var update: Release?
|
||||||
|
|
||||||
|
public let testBuild: Bool
|
||||||
|
|
||||||
private let osVersion: SemVer
|
private let osVersion: SemVer
|
||||||
private let currentVersion: SemVer
|
private let currentVersion: SemVer
|
||||||
@ -17,6 +19,7 @@ public class Updater: ObservableObject, UpdaterProtocol {
|
|||||||
public init(checkOnLaunch: Bool, osVersion: SemVer = SemVer(ProcessInfo.processInfo.operatingSystemVersion), currentVersion: SemVer = SemVer(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0")) {
|
public init(checkOnLaunch: Bool, osVersion: SemVer = SemVer(ProcessInfo.processInfo.operatingSystemVersion), currentVersion: SemVer = SemVer(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0")) {
|
||||||
self.osVersion = osVersion
|
self.osVersion = osVersion
|
||||||
self.currentVersion = currentVersion
|
self.currentVersion = currentVersion
|
||||||
|
testBuild = currentVersion == SemVer("0.0.0")
|
||||||
if checkOnLaunch {
|
if checkOnLaunch {
|
||||||
// Don't do a launch check if the user hasn't seen the setup prompt explaining updater yet.
|
// Don't do a launch check if the user hasn't seen the setup prompt explaining updater yet.
|
||||||
checkForUpdates()
|
checkForUpdates()
|
||||||
|
@ -36,7 +36,7 @@ struct Secretive: App {
|
|||||||
if agentStatusChecker.running && justUpdatedChecker.justUpdated {
|
if agentStatusChecker.running && justUpdatedChecker.justUpdated {
|
||||||
// Relaunch the agent, since it'll be running from earlier update still
|
// Relaunch the agent, since it'll be running from earlier update still
|
||||||
reinstallAgent()
|
reinstallAgent()
|
||||||
} else if !agentStatusChecker.running {
|
} else if !agentStatusChecker.running && !agentStatusChecker.developmentBuild {
|
||||||
forceLaunchAgent()
|
forceLaunchAgent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import SecretKit
|
|||||||
|
|
||||||
protocol AgentStatusCheckerProtocol: ObservableObject {
|
protocol AgentStatusCheckerProtocol: ObservableObject {
|
||||||
var running: Bool { get }
|
var running: Bool { get }
|
||||||
|
var developmentBuild: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol {
|
class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol {
|
||||||
@ -36,6 +37,12 @@ class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Whether Secretive is being run in an Xcode environment.
|
||||||
|
var developmentBuild: Bool {
|
||||||
|
Bundle.main.bundleURL.absoluteString.contains("/Library/Developer/Xcode")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import Combine
|
|||||||
class PreviewAgentStatusChecker: AgentStatusCheckerProtocol {
|
class PreviewAgentStatusChecker: AgentStatusCheckerProtocol {
|
||||||
|
|
||||||
let running: Bool
|
let running: Bool
|
||||||
|
let developmentBuild = false
|
||||||
|
|
||||||
init(running: Bool = true) {
|
init(running: Bool = true) {
|
||||||
self.running = running
|
self.running = running
|
||||||
|
@ -5,6 +5,7 @@ import Brief
|
|||||||
class PreviewUpdater: UpdaterProtocol {
|
class PreviewUpdater: UpdaterProtocol {
|
||||||
|
|
||||||
let update: Release?
|
let update: Release?
|
||||||
|
let testBuild = false
|
||||||
|
|
||||||
init(update: Update = .none) {
|
init(update: Update = .none) {
|
||||||
switch update {
|
switch update {
|
||||||
|
@ -3,18 +3,18 @@ import SecretKit
|
|||||||
import Brief
|
import Brief
|
||||||
|
|
||||||
struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentStatusCheckerProtocol>: View {
|
struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentStatusCheckerProtocol>: View {
|
||||||
|
|
||||||
@Binding var showingCreation: Bool
|
@Binding var showingCreation: Bool
|
||||||
@Binding var runningSetup: Bool
|
@Binding var runningSetup: Bool
|
||||||
@Binding var hasRunSetup: Bool
|
@Binding var hasRunSetup: Bool
|
||||||
|
|
||||||
@EnvironmentObject private var storeList: SecretStoreList
|
@EnvironmentObject private var storeList: SecretStoreList
|
||||||
@EnvironmentObject private var updater: UpdaterType
|
@EnvironmentObject private var updater: UpdaterType
|
||||||
@EnvironmentObject private var agentStatusChecker: AgentStatusCheckerType
|
@EnvironmentObject private var agentStatusChecker: AgentStatusCheckerType
|
||||||
|
|
||||||
@State private var selectedUpdate: Release?
|
@State private var selectedUpdate: Release?
|
||||||
@State private var showingAppPathNotice = false
|
@State private var showingAppPathNotice = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
if storeList.anyAvailable {
|
if storeList.anyAvailable {
|
||||||
@ -31,11 +31,11 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
newItem
|
newItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ContentView {
|
extension ContentView {
|
||||||
|
|
||||||
var updateNotice: ToolbarItem<Void, AnyView> {
|
var updateNotice: ToolbarItem<Void, AnyView> {
|
||||||
guard let update = updater.update else {
|
guard let update = updater.update else {
|
||||||
return ToolbarItem { AnyView(EmptyView()) }
|
return ToolbarItem { AnyView(EmptyView()) }
|
||||||
@ -46,8 +46,13 @@ extension ContentView {
|
|||||||
text = "Critical Security Update Required"
|
text = "Critical Security Update Required"
|
||||||
color = .red
|
color = .red
|
||||||
} else {
|
} else {
|
||||||
text = "Update Available"
|
if updater.testBuild {
|
||||||
color = .orange
|
text = "Test Build"
|
||||||
|
color = .blue
|
||||||
|
} else {
|
||||||
|
text = "Update Available"
|
||||||
|
color = .orange
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ToolbarItem {
|
return ToolbarItem {
|
||||||
AnyView(
|
AnyView(
|
||||||
@ -58,15 +63,15 @@ extension ContentView {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
})
|
})
|
||||||
.background(color)
|
.background(color)
|
||||||
.cornerRadius(5)
|
.cornerRadius(5)
|
||||||
.popover(item: $selectedUpdate, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) { update in
|
.popover(item: $selectedUpdate, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) { update in
|
||||||
UpdateDetailView(update: update)
|
UpdateDetailView(update: update)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var newItem: ToolbarItem<Void, AnyView> {
|
var newItem: ToolbarItem<Void, AnyView> {
|
||||||
guard storeList.modifiableStore?.isAvailable ?? false else {
|
guard storeList.modifiableStore?.isAvailable ?? false else {
|
||||||
return ToolbarItem { AnyView(EmptyView()) }
|
return ToolbarItem { AnyView(EmptyView()) }
|
||||||
@ -78,21 +83,21 @@ extension ContentView {
|
|||||||
}, label: {
|
}, label: {
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
})
|
})
|
||||||
.popover(isPresented: $showingCreation, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
|
.popover(isPresented: $showingCreation, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
|
||||||
if let modifiable = storeList.modifiableStore {
|
if let modifiable = storeList.modifiableStore {
|
||||||
CreateSecretView(store: modifiable, showing: $showingCreation)
|
CreateSecretView(store: modifiable, showing: $showingCreation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var setupNotice: ToolbarItem<Void, AnyView> {
|
var setupNotice: ToolbarItem<Void, AnyView> {
|
||||||
return ToolbarItem {
|
return ToolbarItem {
|
||||||
AnyView(
|
AnyView(
|
||||||
Group {
|
Group {
|
||||||
if runningSetup || !hasRunSetup || !agentStatusChecker.running {
|
if (runningSetup || !hasRunSetup || !agentStatusChecker.running) && !agentStatusChecker.developmentBuild {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
runningSetup = true
|
runningSetup = true
|
||||||
}, label: {
|
}, label: {
|
||||||
@ -106,19 +111,19 @@ extension ContentView {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
})
|
})
|
||||||
.background(Color.orange)
|
.background(Color.orange)
|
||||||
.cornerRadius(5)
|
.cornerRadius(5)
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $runningSetup) {
|
.sheet(isPresented: $runningSetup) {
|
||||||
SetupView(visible: $runningSetup, setupComplete: $hasRunSetup)
|
SetupView(visible: $runningSetup, setupComplete: $hasRunSetup)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var appPathNotice: ToolbarItem<Void, AnyView> {
|
var appPathNotice: ToolbarItem<Void, AnyView> {
|
||||||
let controller = ApplicationDirectoryController()
|
let controller = ApplicationDirectoryController()
|
||||||
guard !controller.isInApplicationsDirectory else {
|
guard !controller.isInApplicationsDirectory else {
|
||||||
@ -135,29 +140,29 @@ extension ContentView {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
})
|
})
|
||||||
.background(Color.orange)
|
.background(Color.orange)
|
||||||
.cornerRadius(5)
|
.cornerRadius(5)
|
||||||
.popover(isPresented: $showingAppPathNotice, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
|
.popover(isPresented: $showingAppPathNotice, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
|
||||||
VStack {
|
VStack {
|
||||||
Image(systemName: "exclamationmark.triangle")
|
Image(systemName: "exclamationmark.triangle")
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.frame(width: 64)
|
.frame(width: 64)
|
||||||
Text("Secretive needs to be in your Applications folder to work properly. Please move it and relaunch.")
|
Text("Secretive needs to be in your Applications folder to work properly. Please move it and relaunch.")
|
||||||
.frame(maxWidth: 300)
|
.frame(maxWidth: 300)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
}
|
}
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
|
|
||||||
private static let storeList: SecretStoreList = {
|
private static let storeList: SecretStoreList = {
|
||||||
let list = SecretStoreList()
|
let list = SecretStoreList()
|
||||||
list.add(store: SecureEnclave.Store())
|
list.add(store: SecureEnclave.Store())
|
||||||
@ -166,11 +171,11 @@ struct ContentView_Previews: PreviewProvider {
|
|||||||
}()
|
}()
|
||||||
private static let agentStatusChecker = AgentStatusChecker()
|
private static let agentStatusChecker = AgentStatusChecker()
|
||||||
private static let justUpdatedChecker = JustUpdatedChecker()
|
private static let justUpdatedChecker = JustUpdatedChecker()
|
||||||
|
|
||||||
@State var hasRunSetup = false
|
@State var hasRunSetup = false
|
||||||
@State private var showingSetup = false
|
@State private var showingSetup = false
|
||||||
@State private var showingCreation = false
|
@State private var showingCreation = false
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
Group {
|
Group {
|
||||||
// Empty on modifiable and nonmodifiable
|
// Empty on modifiable and nonmodifiable
|
||||||
@ -178,7 +183,7 @@ struct ContentView_Previews: PreviewProvider {
|
|||||||
.environmentObject(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
|
.environmentObject(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
|
||||||
.environmentObject(PreviewUpdater())
|
.environmentObject(PreviewUpdater())
|
||||||
.environmentObject(agentStatusChecker)
|
.environmentObject(agentStatusChecker)
|
||||||
|
|
||||||
// 5 items on modifiable and nonmodifiable
|
// 5 items on modifiable and nonmodifiable
|
||||||
ContentView<PreviewUpdater, AgentStatusChecker>(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
|
ContentView<PreviewUpdater, AgentStatusChecker>(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
|
||||||
.environmentObject(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
|
.environmentObject(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
|
||||||
@ -186,7 +191,7 @@ struct ContentView_Previews: PreviewProvider {
|
|||||||
.environmentObject(agentStatusChecker)
|
.environmentObject(agentStatusChecker)
|
||||||
}
|
}
|
||||||
.environmentObject(agentStatusChecker)
|
.environmentObject(agentStatusChecker)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user