ContentView.swift (6218B)
1 // 2 // ContentView.swift 3 // Shared 4 // 5 // Created by figbert on 8/30/22. 6 // 7 8 import SwiftUI 9 10 struct ContentView: View { 11 @EnvironmentObject var data: BrowserData 12 13 @State private var columnVisibility = NavigationSplitViewVisibility.detailOnly 14 15 var body: some View { 16 NavigationSplitView(columnVisibility: $columnVisibility) { 17 List(data.views, id: \.self, selection: $data.currentView) { view in 18 NavigationLink { 19 switch view { 20 case .Capsule: 21 CapsuleView() 22 case .History: 23 HistoryView() 24 case .Bookmarks: 25 BookmarksView() 26 } 27 } label: { 28 switch view { 29 case .Capsule: 30 if data.tab.home { 31 Label("Start Page", systemImage: "laptopcomputer") 32 } else { 33 Label("X Tabs", systemImage: "laptopcomputer") 34 } 35 case .History: 36 Label("History", systemImage: "clock") 37 case .Bookmarks: 38 Label("Bookmarks", systemImage: "star") 39 } 40 } 41 } 42 } detail: { 43 switch data.currentView { 44 case .Capsule: 45 CapsuleView() 46 case .History: 47 HistoryView() 48 case .Bookmarks: 49 BookmarksView() 50 } 51 } 52 .toolbar { 53 ToolbarItem(placement: .principal) { 54 TextField("Search or enter website name", text: $data.tab.urlBar) 55 .frame(minWidth: 500) 56 .textFieldStyle(.roundedBorder) 57 .autocorrectionDisabled(true) 58 .onSubmit { Task { await submitURLBar() } } 59 .overlay(HStack { 60 bookmarksButton 61 reloadButton 62 loading 63 }, alignment: .trailing) 64 } 65 ToolbarItem(placement: .navigation) { 66 Button(action: { data.goToStartPage() }) { 67 Label("Go to Start Page", systemImage: "house") 68 .labelStyle(.iconOnly) 69 } 70 } 71 ToolbarItem(placement: .navigation) { 72 Button(action: { Task { await data.goBack() } }) { 73 Label("Back", systemImage: "chevron.backward") 74 .labelStyle(.iconOnly) 75 } 76 .disabled(data.tab.prev == nil) 77 } 78 ToolbarItem(placement: .navigation) { 79 Button(action: { Task { await data.goForward() } }) { 80 Label("Forward", systemImage: "chevron.forward") 81 .labelStyle(.iconOnly) 82 } 83 .disabled(data.tab.next == nil) 84 } 85 ToolbarItem(placement: .secondaryAction) { 86 if data.tab.url != nil { 87 ShareLink(item: data.tab.url!) 88 } else { 89 ShareLink(item: "").disabled(true) 90 } 91 } 92 } 93 .handlesExternalEvents(preferring: ["gemini://*"], allowing: ["*"]) 94 .onOpenURL(perform: { url in 95 Task { await data.openURL(url) } 96 }) 97 } 98 99 @ViewBuilder private var bookmarksButton: some View { 100 if data.tab.response != nil { 101 if data.hasURLInBookmarks(data.tab.url!) { 102 Button(action: { data.dropURLFromBookmarks(data.tab.url!) }) { 103 Label("Drop from bookmarks", systemImage: "star.fill") 104 .labelStyle(.iconOnly) 105 } 106 .buttonStyle(.borderless) 107 .padding(.trailing, 2) 108 } else { 109 Button(action: { 110 data.addURLToBookmarks( 111 data.tab.url!, 112 label: data.tab.url?.host() ?? data.tab.url!.absoluteString, 113 timestamp: Date.now 114 ) 115 }) { 116 Label("Add to bookmarks", systemImage: "star") 117 .labelStyle(.iconOnly) 118 } 119 .buttonStyle(.borderless) 120 .padding(.trailing, 2) 121 } 122 } 123 } 124 @ViewBuilder private var reloadButton: some View { 125 if data.tab.response != nil { 126 Button(action: { Task { await data.reload() } }) { 127 Label("Reload page", systemImage: "arrow.clockwise") 128 .labelStyle(.iconOnly) 129 } 130 .buttonStyle(.borderless) 131 .padding(.trailing, data.loading ? 2 : 8) 132 } 133 } 134 @ViewBuilder private var loading: some View { 135 if data.loading { 136 ProgressView() 137 .scaleEffect(0.5) 138 .padding(.trailing, 4) 139 } 140 } 141 142 private func submitURLBar() async { 143 if let url = URL(string: data.tab.urlBar) { 144 if var components = URLComponents(url: url, resolvingAgainstBaseURL: false) { 145 if components.scheme?.isEmpty ?? true { 146 if components.host?.isEmpty ?? true { 147 let index = components.path.firstIndex(of: "/") ?? components.path.endIndex 148 components.host = String(components.path[..<index]) 149 components.path = String(components.path[index...]) 150 } 151 components.scheme = "gemini" 152 } 153 if let url = components.url { 154 await data.openURL(url) 155 } 156 } 157 } else { 158 var components = URLComponents(string: "gemini://geminispace.info/search") 159 components?.query = data.tab.urlBar 160 if let url = components?.url { 161 await data.openURL(url) 162 } 163 } 164 } 165 } 166 167 struct ContentView_Previews: PreviewProvider { 168 static var previews: some View { 169 ContentView() 170 } 171 }