commit 6a90ed51d65f0bdda2979def3d3f7021151e520c
parent 9a034ea75b8f270165648446930125915d20d0c5
Author: FIGBERT <figbert@figbert.com>
Date: Wed, 14 Sep 2022 14:41:33 -0700
Implement more ergonomic Tab class
The new class will make implementing browser functionality (like
traversing history) much easier to implement.
History is no longer de-duplicated. This may return later. I am
undecided on the subject.
Diffstat:
4 files changed, 58 insertions(+), 33 deletions(-)
diff --git a/Shared/BrowserFunctions.swift b/Shared/BrowserFunctions.swift
@@ -11,12 +11,8 @@ import SwiftGemtext
@MainActor
class BrowserData: ObservableObject {
- @Published var url: String = ""
-
- @Published var history: [URL: Date] = [:]
-
- @Published var tabs: [UUID: SwiftGemini.GeminiResponse?] = [:]
- @Published var currentTab: UUID? = nil // tabs.isEmpty => nil
+ @Published var url = ""
+ @Published var tab = Tab()
@Published var currentView: GemenonView = .Capsule
@Published var views: [GemenonView] = [.Capsule, .History]
@@ -27,27 +23,43 @@ class BrowserData: ObservableObject {
extension BrowserData {
func goToStartPage() {
- guard self.currentTab != nil else { return }
- self.tabs[self.currentTab!] = nil
+ guard !self.tab.home else { return }
+ self.tab = Tab(prev: self.tab)
self.url = ""
}
- func showStartPage() -> Bool {
- return self.tabs.isEmpty || self.tabs[self.currentTab!] == nil
- }
}
extension BrowserData {
func openURL(_ url: URL) async {
- var uuid = UUID()
let response = try! await self.engine.request(url)
- if self.tabs.count == 1 {
- uuid = self.tabs.keys.first!
- }
- self.tabs[uuid] = response
- self.currentTab = uuid
- self.history[url] = Date.now
- self.currentView = .Capsule
+ self.tab = Tab(url, prev: self.tab, response: response)
self.url = url.absoluteString
+ self.currentView = .Capsule
+ }
+}
+
+class Tab: Identifiable {
+ let id = UUID()
+ let timestamp = Date.now
+
+ var home: Bool
+ var url: URL?
+ var next: Tab?
+ var prev: Tab?
+ var response: SwiftGemini.GeminiResponse?
+
+ init() {
+ self.home = true
+ }
+ init(prev: Tab) {
+ self.home = true
+ self.prev = prev
+ }
+ init(_ url: URL, prev: Tab, response: SwiftGemini.GeminiResponse) {
+ self.home = false
+ self.url = url
+ self.prev = prev
+ self.response = response
}
}
diff --git a/Shared/CapsuleView.swift b/Shared/CapsuleView.swift
@@ -11,15 +11,15 @@ struct CapsuleView: View {
@EnvironmentObject var data: BrowserData
var body: some View {
- if data.tabs.isEmpty {
+ if data.tab.home {
StartPage()
} else {
ScrollView {
HStack {
Spacer()
- if data.tabs[data.currentTab!]??.body?.gemtext != nil {
+ if data.tab.response?.body?.gemtext != nil {
VStack(alignment: .leading, spacing: 10) {
- renderGemtext((data.tabs[data.currentTab!]??.body?.gemtext)!, url: (data.tabs[data.currentTab!]??.url)!)
+ renderGemtext((data.tab.response?.body?.gemtext)!, url: data.tab.url)
}
}
Spacer()
@@ -29,7 +29,7 @@ struct CapsuleView: View {
}
}
- func renderGemtext(_ gemtext: String, url: URL) -> some View {
+ func renderGemtext(_ gemtext: String, url: URL?) -> some View {
ForEach(data.parser.parse(gemtext, url: url), id: \.self) { line in
switch line {
case .Text(let str):
diff --git a/Shared/ContentView.swift b/Shared/ContentView.swift
@@ -14,21 +14,21 @@ struct ContentView: View {
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
- List(data.views, id: \.self, selection: $data.currentView) { s in
+ List(data.views, id: \.self, selection: $data.currentView) { view in
NavigationLink {
- switch s {
+ switch view {
case .Capsule:
CapsuleView()
case .History:
HistoryView()
}
} label: {
- switch s {
+ switch view {
case .Capsule:
- if data.tabs.isEmpty {
+ if data.tab.home {
Label("Start Page", systemImage: "laptopcomputer")
} else {
- Label("\(data.tabs.count) Tab\(data.tabs.count > 1 ? "s" : "")", systemImage: "laptopcomputer")
+ Label("X Tabs", systemImage: "laptopcomputer")
}
case .History:
Label("History", systemImage: "clock")
diff --git a/Shared/HistoryView.swift b/Shared/HistoryView.swift
@@ -9,21 +9,34 @@ import SwiftUI
struct HistoryView: View {
@EnvironmentObject var data: BrowserData
+ @State var tabs: [Tab] = []
var body: some View {
List {
- ForEach(data.history.sorted(by: { first, second in first.value > second.value }), id: \.value) { url, date in
+ ForEach(tabs) { tab in
HStack {
- Link(destination: url) { Text(url.absoluteString) }
+ Link(destination: tab.url!) { Text(tab.url?.absoluteString ?? "error") }
Spacer()
- if date.timeIntervalSince(.now) <= -1*60*60*24 {
- Text(date.formatted(date: .long, time: .complete))
+ if tab.timestamp.timeIntervalSince(.now) <= -1*60*60*24 {
+ Text(tab.timestamp.formatted(date: .long, time: .complete))
} else {
- Text(date.formatted(date: .omitted, time: .complete))
+ Text(tab.timestamp.formatted(date: .omitted, time: .complete))
}
}
}
}
+ .onAppear {
+ appendToURLs(data.tab, list: &tabs)
+ }
+ }
+
+ func appendToURLs(_ tab: Tab, list: inout [Tab]) {
+ if !tab.home {
+ list.append(tab)
+ }
+ if tab.prev != nil {
+ appendToURLs(tab.prev!, list: &list)
+ }
}
}