secretive/Sources/Secretive/Views/ContentView.swift

201 lines
7.0 KiB
Swift
Raw Normal View History

2020-02-19 03:36:41 +00:00
import SwiftUI
2020-02-19 04:52:00 +00:00
import SecretKit
import SecureEnclaveSecretKit
import SmartCardSecretKit
2020-03-22 01:43:26 +00:00
import Brief
2020-02-19 04:52:00 +00:00
struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentStatusCheckerProtocol>: View {
2020-09-22 06:12:50 +00:00
@Binding var showingCreation: Bool
@Binding var runningSetup: Bool
@Binding var hasRunSetup: Bool
@EnvironmentObject private var storeList: SecretStoreList
@EnvironmentObject private var updater: UpdaterType
@EnvironmentObject private var agentStatusChecker: AgentStatusCheckerType
@State private var selectedUpdate: Release?
@State private var showingAppPathNotice = false
2020-02-19 03:36:41 +00:00
var body: some View {
2020-03-15 08:01:40 +00:00
VStack {
2020-03-21 03:20:20 +00:00
if storeList.anyAvailable {
2020-09-22 06:12:50 +00:00
StoreListView(showingCreation: $showingCreation)
2020-03-21 03:20:20 +00:00
} else {
NoStoresView()
}
2020-09-22 06:12:50 +00:00
}
.frame(minWidth: 640, minHeight: 320)
.toolbar {
updateNotice
setupNotice
appPathNotice
newItem
}
2020-02-19 03:36:41 +00:00
}
2020-03-15 08:01:40 +00:00
2020-09-22 06:12:50 +00:00
}
extension ContentView {
var updateNotice: ToolbarItem<Void, AnyView> {
guard let update = updater.update else {
return ToolbarItem { AnyView(EmptyView()) }
}
let color: Color
2020-03-15 08:01:40 +00:00
let text: String
if update.critical {
text = "Critical Security Update Required"
2020-09-22 06:12:50 +00:00
color = .red
2020-03-15 08:01:40 +00:00
} else {
if updater.testBuild {
text = "Test Build"
color = .blue
} else {
text = "Update Available"
color = .orange
}
2020-09-22 06:12:50 +00:00
}
return ToolbarItem {
AnyView(
Button(action: {
selectedUpdate = update
}, label: {
Text(text)
.font(.headline)
.foregroundColor(.white)
})
.background(color)
.cornerRadius(5)
.popover(item: $selectedUpdate, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) { update in
UpdateDetailView(update: update)
}
2020-09-22 06:12:50 +00:00
)
2020-03-15 08:01:40 +00:00
}
}
2020-09-22 06:12:50 +00:00
var newItem: ToolbarItem<Void, AnyView> {
guard storeList.modifiableStore?.isAvailable ?? false else {
return ToolbarItem { AnyView(EmptyView()) }
}
return ToolbarItem {
AnyView(
Button(action: {
showingCreation = true
}, label: {
Image(systemName: "plus")
})
.popover(isPresented: $showingCreation, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
if let modifiable = storeList.modifiableStore {
CreateSecretView(store: modifiable, showing: $showingCreation)
}
}
2020-09-22 06:12:50 +00:00
)
}
}
2020-09-22 06:12:50 +00:00
var setupNotice: ToolbarItem<Void, AnyView> {
return ToolbarItem {
AnyView(
Group {
if (runningSetup || !hasRunSetup || !agentStatusChecker.running) && !agentStatusChecker.developmentBuild {
2020-09-22 06:12:50 +00:00
Button(action: {
runningSetup = true
}, label: {
Group {
if hasRunSetup && !agentStatusChecker.running {
Text("Secret Agent Is Not Running")
} else {
Text("Setup Secretive")
}
}
.font(.headline)
.foregroundColor(.white)
})
.background(Color.orange)
.cornerRadius(5)
2020-09-22 06:12:50 +00:00
} else {
EmptyView()
}
}
.sheet(isPresented: $runningSetup) {
SetupView(visible: $runningSetup, setupComplete: $hasRunSetup)
}
2020-09-22 06:12:50 +00:00
)
}
2020-03-04 07:14:38 +00:00
}
2020-03-15 21:03:57 +00:00
2020-09-22 06:12:50 +00:00
var appPathNotice: ToolbarItem<Void, AnyView> {
let controller = ApplicationDirectoryController()
guard !controller.isInApplicationsDirectory else {
return ToolbarItem { AnyView(EmptyView()) }
}
return ToolbarItem {
AnyView(
Button(action: {
showingAppPathNotice = true
}, label: {
Group {
Text("Secretive Is Not in Applications Folder")
}
.font(.headline)
.foregroundColor(.white)
})
.background(Color.orange)
.cornerRadius(5)
.popover(isPresented: $showingAppPathNotice, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
VStack {
Image(systemName: "exclamationmark.triangle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 64)
Text("Secretive needs to be in your Applications folder to work properly. Please move it and relaunch.")
.frame(maxWidth: 300)
}
.padding()
2020-09-22 06:12:50 +00:00
}
)
2020-03-15 21:03:57 +00:00
}
}
2020-03-11 08:53:31 +00:00
}
2020-03-12 06:07:22 +00:00
#if DEBUG
struct ContentView_Previews: PreviewProvider {
2020-09-22 06:12:50 +00:00
private static let storeList: SecretStoreList = {
let list = SecretStoreList()
list.add(store: SecureEnclave.Store())
list.add(store: SmartCard.Store())
return list
}()
private static let agentStatusChecker = AgentStatusChecker()
private static let justUpdatedChecker = JustUpdatedChecker()
@State var hasRunSetup = false
@State private var showingSetup = false
@State private var showingCreation = false
static var previews: some View {
Group {
2020-09-22 06:12:50 +00:00
// Empty on modifiable and nonmodifiable
ContentView<PreviewUpdater, AgentStatusChecker>(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
.environmentObject(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
.environmentObject(PreviewUpdater())
.environmentObject(agentStatusChecker)
// 5 items on modifiable and nonmodifiable
ContentView<PreviewUpdater, AgentStatusChecker>(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
.environmentObject(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
.environmentObject(PreviewUpdater())
.environmentObject(agentStatusChecker)
}
2020-09-22 06:12:50 +00:00
.environmentObject(agentStatusChecker)
}
}
2020-03-12 06:07:22 +00:00
#endif