mirror of
				https://github.com/maxgoedjen/secretive.git
				synced 2025-10-31 07:20:57 +00:00 
			
		
		
		
	WIP
This commit is contained in:
		
							parent
							
								
									964ef1e201
								
							
						
					
					
						commit
						13f30f0343
					
				| @ -2,14 +2,14 @@ import SwiftUI | |||||||
| import SecretKit | import SecretKit | ||||||
| 
 | 
 | ||||||
| struct CreateSecretView<StoreType: SecretStoreModifiable>: View { | struct CreateSecretView<StoreType: SecretStoreModifiable>: View { | ||||||
|      | 
 | ||||||
|     @ObservedObject var store: StoreType |     @ObservedObject var store: StoreType | ||||||
|     @Binding var showing: Bool |     @Binding var showing: Bool | ||||||
|      | 
 | ||||||
|     @State private var name = "" |     @State private var name = "" | ||||||
|     @State private var requiresAuthentication = true |     @State private var requiresAuthentication = true | ||||||
|     @State private var test: ThumbnailPickerView.Item = ThumbnailPickerView.Item(name: "Test", thumbnail: Text("Hello")) |     @State private var test: ThumbnailPickerView.Item = ThumbnailPickerView.Item(name: "Test", description: "Hello", thumbnail: Text("Hello")) | ||||||
|      | 
 | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         VStack { |         VStack { | ||||||
|             HStack { |             HStack { | ||||||
| @ -24,20 +24,25 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View { | |||||||
|                         TextField("Shhhhh", text: $name) |                         TextField("Shhhhh", text: $name) | ||||||
|                             .focusable() |                             .focusable() | ||||||
|                     } |                     } | ||||||
|                     ThumbnailPickerView(items: [ |                     if #available(macOS 12.0, *) { | ||||||
|                         ThumbnailPickerView.Item(name: "Requires Authentication Before Use", thumbnail: Text("")), |                         ThumbnailPickerView(items: [ | ||||||
|                         ThumbnailPickerView.Item(name: "Notify on Use", thumbnail: Text("")) |                             ThumbnailPickerView.Item(name: "Requires Authentication Before Use", description: "You will be required to authenticate using Touch ID, Apple Watch, or password before each use.", thumbnail: AuthenticationView()), | ||||||
|                     ], selection: $test) |                             ThumbnailPickerView.Item(name: "Notify on Use", | ||||||
|                     //                    HStack { |                                                      description: "No authentication is required while your Mac is unlocked.", | ||||||
|                     //                        VStack(spacing: 20) { |                                                      thumbnail: NotificationView()) | ||||||
|                     //                            Picker("", selection: $requiresAuthentication) { |                         ], selection: $test) | ||||||
|                     //                                Text("Requires Authentication (Biometrics or Password) before each use").tag(true) |                     } else { | ||||||
|                     //                                Text("Authentication not required when Mac is unlocked").tag(false) |                         //                    HStack { | ||||||
|                     //                            } |                         //                        VStack(spacing: 20) { | ||||||
|                     //                            .pickerStyle(SegmentedPickerStyle()) |                         //                            Picker("", selection: $requiresAuthentication) { | ||||||
|                     //                        } |                         //                                Text("Requires Authentication (Biometrics or Password) before each use").tag(true) | ||||||
|                     //                        Spacer() |                         //                                Text("Authentication not required when Mac is unlocked").tag(false) | ||||||
|                     //                    } |                         //                            } | ||||||
|  |                         //                            .pickerStyle(SegmentedPickerStyle()) | ||||||
|  |                         //                        } | ||||||
|  |                         //                        Spacer() | ||||||
|  |                         //                    } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             HStack { |             HStack { | ||||||
| @ -52,7 +57,7 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View { | |||||||
|             } |             } | ||||||
|         }.padding() |         }.padding() | ||||||
|     } |     } | ||||||
|      | 
 | ||||||
|     func save() { |     func save() { | ||||||
|         try! store.create(name: name, requiresAuthentication: requiresAuthentication) |         try! store.create(name: name, requiresAuthentication: requiresAuthentication) | ||||||
|         showing = false |         showing = false | ||||||
| @ -60,60 +65,85 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct ThumbnailPickerView: View { | struct ThumbnailPickerView: View { | ||||||
|      | 
 | ||||||
|     let items: [Item] |     let items: [Item] | ||||||
|     let selection: Binding<Item> |     @Binding var selection: Item | ||||||
|      | 
 | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         HStack { |         HStack { | ||||||
|             ForEach(items) { item in |             ForEach(items) { item in | ||||||
|                 Text(item.name) |                 VStack { | ||||||
|  |                     item.thumbnail | ||||||
|  |                         .clipShape(RoundedRectangle(cornerRadius: 10)) | ||||||
|  |                         .overlay(RoundedRectangle(cornerRadius: 10) | ||||||
|  |                             .stroke(lineWidth: item.id == selection.id ? 5 : 0)) | ||||||
|  |                             .foregroundColor(.accentColor) | ||||||
|  |                     Text(item.name) | ||||||
|  |                         .bold() | ||||||
|  |                     Text(item.description) | ||||||
|  |                 }.onTapGesture { | ||||||
|  |                     selection = item | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |         }.onAppear { | ||||||
|  |             selection = items.first! | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| extension ThumbnailPickerView { | extension ThumbnailPickerView { | ||||||
|      | 
 | ||||||
|     struct Item: Identifiable { |     struct Item: Identifiable { | ||||||
|         let id = UUID() |         let id = UUID() | ||||||
|         let name: String |         let name: String | ||||||
|  |         let description: String | ||||||
|         let thumbnail: AnyView |         let thumbnail: AnyView | ||||||
|          | 
 | ||||||
|         init<ViewType: View>(name: String, thumbnail: ViewType) { |         init<ViewType: View>(name: String, description: String, thumbnail: ViewType) { | ||||||
|             self.name = name |             self.name = name | ||||||
|  |             self.description = description | ||||||
|             self.thumbnail = AnyView(thumbnail) |             self.thumbnail = AnyView(thumbnail) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @available(macOS 12.0, *) | ||||||
|  | struct SystemBackgroundView: View { | ||||||
|  | 
 | ||||||
|  |     let anchor: UnitPoint | ||||||
|  | 
 | ||||||
|  |     var body: some View { | ||||||
|  |         if let mainScreen = NSScreen.main, let imageURL = NSWorkspace.shared.desktopImageURL(for: mainScreen) { | ||||||
|  |             AsyncImage(url: imageURL) { phase in | ||||||
|  |                 switch phase { | ||||||
|  |                 case .empty, .failure: | ||||||
|  |                     Rectangle() | ||||||
|  |                         .foregroundColor(Color(.systemPurple)) | ||||||
|  |                 case .success(let image): | ||||||
|  |                     image | ||||||
|  |                         .resizable() | ||||||
|  |                         .scaleEffect(3, anchor: anchor) | ||||||
|  |                         .clipped() | ||||||
|  |                 @unknown default: | ||||||
|  |                     Rectangle() | ||||||
|  |                         .foregroundColor(Color(.systemPurple)) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             Rectangle() | ||||||
|  |                 .foregroundColor(Color(.systemPurple)) | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @available(macOS 12.0, *) | @available(macOS 12.0, *) | ||||||
| struct AuthenticationView: View { | struct AuthenticationView: View { | ||||||
|      | 
 | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         ZStack { |         ZStack { | ||||||
|             if let mainScreen = NSScreen.main, let imageURL = NSWorkspace.shared.desktopImageURL(for: mainScreen) { |             SystemBackgroundView(anchor: .center) | ||||||
|                 AsyncImage(url: imageURL) { phase in |  | ||||||
|                     switch phase { |  | ||||||
|                     case .empty, .failure: |  | ||||||
|                         Rectangle() |  | ||||||
|                             .foregroundColor(Color(.systemPurple)) |  | ||||||
|                     case .success(let image): |  | ||||||
|                         image |  | ||||||
|                             .resizable() |  | ||||||
|                             .scaleEffect(3) |  | ||||||
|                     @unknown default: |  | ||||||
|                         Rectangle() |  | ||||||
|                             .foregroundColor(Color(.systemPurple)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             RoundedRectangle(cornerRadius: 15) |  | ||||||
|                 .aspectRatio(0.8, contentMode: .fit) |  | ||||||
|                 .foregroundColor(Color(.windowBackgroundColor)) |  | ||||||
|                 .padding() |  | ||||||
|             VStack { |             VStack { | ||||||
|                 Spacer() |                 Spacer() | ||||||
|                 Image(systemName: "touchid") |                 Image(systemName: "touchid") | ||||||
| @ -124,38 +154,97 @@ struct AuthenticationView: View { | |||||||
|                 Spacer() |                 Spacer() | ||||||
|                 Text("Touch ID Prompt") |                 Text("Touch ID Prompt") | ||||||
|                     .font(.largeTitle) |                     .font(.largeTitle) | ||||||
|  |                     .foregroundColor(.primary) | ||||||
|                     .redacted(reason: .placeholder) |                     .redacted(reason: .placeholder) | ||||||
|                 Spacer() |                 Spacer() | ||||||
|                 VStack { |                 VStack { | ||||||
|                     Text("Touch ID Detail prompt.Detail two.") |                     Text("Touch ID Detail prompt.Detail two.") | ||||||
|                         .font(.title3) |                         .font(.title3) | ||||||
|  |                         .foregroundColor(.primary) | ||||||
|                     Text("Touch ID Detail prompt.Detail two.") |                     Text("Touch ID Detail prompt.Detail two.") | ||||||
|                         .font(.title3) |                         .font(.title3) | ||||||
|  |                         .foregroundColor(.primary) | ||||||
|                 } |                 } | ||||||
|                 .redacted(reason: .placeholder) |                 .redacted(reason: .placeholder) | ||||||
|                 Spacer() |                 Spacer() | ||||||
|                 RoundedRectangle(cornerRadius: 10) |                 RoundedRectangle(cornerRadius: 10) | ||||||
|                     .frame(width: 275, height: 40, alignment: .center) |                     .frame(width: 275, height: 40, alignment: .center) | ||||||
|                     .foregroundColor(Color(.controlAccentColor)) |                     .foregroundColor(.accentColor) | ||||||
|                 RoundedRectangle(cornerRadius: 10) |                 RoundedRectangle(cornerRadius: 10) | ||||||
|                     .frame(width: 275, height: 40, alignment: .center) |                     .frame(width: 275, height: 40, alignment: .center) | ||||||
|                     .foregroundColor(Color(.unemphasizedSelectedContentBackgroundColor)) |                     .foregroundColor(Color(.unemphasizedSelectedContentBackgroundColor)) | ||||||
|             }.padding().padding() |             } | ||||||
|  |             .padding() | ||||||
|  |             .background( | ||||||
|  |                 RoundedRectangle(cornerRadius: 15) | ||||||
|  |                     .foregroundStyle(.ultraThickMaterial) | ||||||
|  |             ) | ||||||
|  |             .padding() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @available(macOS 12.0, *) | ||||||
|  | struct NotificationView: View { | ||||||
|  | 
 | ||||||
|  |     var body: some View { | ||||||
|  |         ZStack { | ||||||
|  |             SystemBackgroundView(anchor: .topTrailing) | ||||||
|  |             VStack { | ||||||
|  |                 Rectangle() | ||||||
|  |                     .background(Color.clear) | ||||||
|  |                     .foregroundStyle(.thinMaterial) | ||||||
|  |                     .frame(height: 35) | ||||||
|  |                 VStack { | ||||||
|  |                     HStack { | ||||||
|  |                         Spacer() | ||||||
|  |                         HStack { | ||||||
|  |                             Image(nsImage: NSApplication.shared.applicationIconImage) | ||||||
|  |                                 .resizable() | ||||||
|  |                                 .frame(width: 64, height: 64) | ||||||
|  |                                 .foregroundColor(.primary) | ||||||
|  |                                 .padding() | ||||||
|  |                             VStack(alignment: .leading) { | ||||||
|  |                                 Text("Secretive") | ||||||
|  |                                     .font(.largeTitle) | ||||||
|  |                                     .foregroundColor(.primary) | ||||||
|  |                                 Text("Secretive wants to sign some request") | ||||||
|  |                                     .font(.title3) | ||||||
|  |                                     .foregroundColor(.primary) | ||||||
|  |                                 Text("Secretive wants to sign some request") | ||||||
|  |                                     .font(.title3) | ||||||
|  |                                     .foregroundColor(.primary) | ||||||
|  |                             } | ||||||
|  |                             .padding() | ||||||
|  |                         } | ||||||
|  |                         .redacted(reason: .placeholder) | ||||||
|  |                         .background( | ||||||
|  |                             RoundedRectangle(cornerRadius: 15) | ||||||
|  |                                 .foregroundStyle(.ultraThickMaterial) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                     Spacer() | ||||||
|  |                 } | ||||||
|  |                 .padding() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 
 | 
 | ||||||
| struct CreateSecretView_Previews: PreviewProvider { | struct CreateSecretView_Previews: PreviewProvider { | ||||||
|      | 
 | ||||||
|     static var previews: some View { |     static var previews: some View { | ||||||
|         Group { |         Group { | ||||||
|             CreateSecretView(store: Preview.StoreModifiable(), showing: .constant(true)) |             CreateSecretView(store: Preview.StoreModifiable(), showing: .constant(true)) | ||||||
|             if #available(macOS 12.0, *) { |             if #available(macOS 12.0, *) { | ||||||
|                 AuthenticationView().environment(\.colorScheme, .dark) |                 AuthenticationView().environment(\.colorScheme, .dark) | ||||||
|                 AuthenticationView().environment(\.colorScheme, .light) |                 AuthenticationView().environment(\.colorScheme, .light) | ||||||
|  |                 NotificationView().environment(\.colorScheme, .dark) | ||||||
|  |                 NotificationView().environment(\.colorScheme, .light) | ||||||
|             } else { |             } else { | ||||||
|                 // Fallback on earlier versions |                 // Fallback on earlier versions | ||||||
|             } |             } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user