commit 8a02bdb939406f9e6b1546f6e0da0c3d13f7d2eb
parent 25314131ae1515877569d17dd1c5ff6d3bac56e6
Author: FIGBERT <figbert@figbert.com>
Date: Fri, 21 Oct 2022 23:40:32 -0700
Add bookmarks
Diffstat:
5 files changed, 124 insertions(+), 5 deletions(-)
diff --git a/Gemenon.xcodeproj/project.pbxproj b/Gemenon.xcodeproj/project.pbxproj
@@ -21,6 +21,8 @@
3AB5B67E28BF23FF00F0C1A5 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB5B66C28BF23FF00F0C1A5 /* ContentView.swift */; };
3AB5B67F28BF23FF00F0C1A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AB5B66D28BF23FF00F0C1A5 /* Assets.xcassets */; };
3AB5B68028BF23FF00F0C1A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AB5B66D28BF23FF00F0C1A5 /* Assets.xcassets */; };
+ 3ABE77C32903B77600A7EE90 /* BookmarksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABE77C22903B77600A7EE90 /* BookmarksView.swift */; };
+ 3ABE77C42903B77600A7EE90 /* BookmarksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABE77C22903B77600A7EE90 /* BookmarksView.swift */; };
3AD4A8B928C3EE120095B98E /* SwiftGemini in Frameworks */ = {isa = PBXBuildFile; productRef = 3AD4A8B828C3EE120095B98E /* SwiftGemini */; };
3AD4A8BC28C3EE440095B98E /* SwiftGemtext in Frameworks */ = {isa = PBXBuildFile; productRef = 3AD4A8BB28C3EE440095B98E /* SwiftGemtext */; };
/* End PBXBuildFile section */
@@ -37,6 +39,7 @@
3AB5B67228BF23FF00F0C1A5 /* Gemenon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gemenon.app; sourceTree = BUILT_PRODUCTS_DIR; };
3AB5B67828BF23FF00F0C1A5 /* Gemenon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gemenon.app; sourceTree = BUILT_PRODUCTS_DIR; };
3AB5B67A28BF23FF00F0C1A5 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = "<group>"; };
+ 3ABE77C22903B77600A7EE90 /* BookmarksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -76,6 +79,7 @@
3A00265228C854A100625B2C /* StartPage.swift */,
3A00264F28C8398A00625B2C /* CapsuleView.swift */,
3A00264928C8340500625B2C /* HistoryView.swift */,
+ 3ABE77C22903B77600A7EE90 /* BookmarksView.swift */,
3A00264C28C8350200625B2C /* BrowserFunctions.swift */,
3AB5B66D28BF23FF00F0C1A5 /* Assets.xcassets */,
);
@@ -208,6 +212,7 @@
files = (
3AB5B67D28BF23FF00F0C1A5 /* ContentView.swift in Sources */,
3A00265328C854A100625B2C /* StartPage.swift in Sources */,
+ 3ABE77C32903B77600A7EE90 /* BookmarksView.swift in Sources */,
3A00265028C8398A00625B2C /* CapsuleView.swift in Sources */,
3A00264A28C8340500625B2C /* HistoryView.swift in Sources */,
3A00264D28C8350200625B2C /* BrowserFunctions.swift in Sources */,
@@ -221,6 +226,7 @@
files = (
3AB5B67E28BF23FF00F0C1A5 /* ContentView.swift in Sources */,
3A00265428C854A100625B2C /* StartPage.swift in Sources */,
+ 3ABE77C42903B77600A7EE90 /* BookmarksView.swift in Sources */,
3A00265128C8398A00625B2C /* CapsuleView.swift in Sources */,
3A00264B28C8340500625B2C /* HistoryView.swift in Sources */,
3A00264E28C8350200625B2C /* BrowserFunctions.swift in Sources */,
diff --git a/Shared/BookmarksView.swift b/Shared/BookmarksView.swift
@@ -0,0 +1,53 @@
+//
+// BookmarksView.swift
+// Gemenon
+//
+// Created by figbert on 10/21/22.
+//
+
+import SwiftUI
+
+struct BookmarksView: View {
+ @EnvironmentObject var data: BrowserData
+ @State private var editing: UUID?
+ @State private var url = ""
+ @State private var name = ""
+
+ var body: some View {
+ List {
+ ForEach(data.bookmarks.sorted(by: { a, b in a.timestamp < b.timestamp })) { bookmark in
+ HStack {
+ if editing == bookmark.id {
+ TextField("Bookmark URL", text: $url)
+ .textFieldStyle(.roundedBorder)
+ .autocorrectionDisabled(true)
+ TextField("Bookmark Name", text: $name)
+ .textFieldStyle(.roundedBorder)
+ .autocorrectionDisabled(true)
+ Button(action: {
+ if let url = URL(string: url) {
+ data.dropURLFromBookmarks(bookmark.url)
+ data.addURLToBookmarks(url, label: name, timestamp: bookmark.timestamp)
+ }
+ self.editing = nil
+ }) { Text("Done") }
+ } else {
+ Link(destination: bookmark.url) { Text(bookmark.name) }
+ Spacer()
+ Button(action: {
+ self.url = bookmark.url.absoluteString
+ self.name = bookmark.name
+ self.editing = bookmark.id
+ }) { Text("Edit") }
+ }
+ }
+ }
+ }
+ }
+}
+
+struct BookmarksView_Previews: PreviewProvider {
+ static var previews: some View {
+ BookmarksView()
+ }
+}
diff --git a/Shared/BrowserFunctions.swift b/Shared/BrowserFunctions.swift
@@ -14,8 +14,10 @@ class BrowserData: ObservableObject {
@Published var tab = Tab()
@Published var loading = false
+ @Published var bookmarks: [Bookmark] = []
+
@Published var currentView: GemenonView = .Capsule
- @Published var views: [GemenonView] = [.Capsule, .History]
+ @Published var views: [GemenonView] = [.Capsule, .History, .Bookmarks]
@Published var parser = SwiftGemtext.Gemtext()
@Published var engine = SwiftGemini.GeminiRequestor()
@@ -52,6 +54,25 @@ extension BrowserData {
}
extension BrowserData {
+ func hasURLInBookmarks(_ url: URL) -> Bool {
+ guard !self.bookmarks.isEmpty else { return false }
+ return bookmarks.contains(where: { bookmark in
+ bookmark.url == url
+ })
+ }
+ func addURLToBookmarks(_ url: URL, label: String, timestamp: Date) {
+ guard !self.hasURLInBookmarks(url) else { return }
+ self.bookmarks.append(Bookmark(url: url, name: label, timestamp: timestamp))
+ }
+ func dropURLFromBookmarks(_ url: URL) {
+ guard self.hasURLInBookmarks(url) else { return }
+ self.bookmarks.removeAll(where: { bookmark in
+ bookmark.url == url
+ })
+ }
+}
+
+extension BrowserData {
func openURL(_ url: URL) async {
self.loading = true
let response = try! await self.engine.request(url)
@@ -92,7 +113,16 @@ class Tab: Identifiable {
}
}
+struct Bookmark: Identifiable {
+ let id = UUID()
+
+ let url: URL
+ let name: String
+ let timestamp: Date
+}
+
enum GemenonView {
case Capsule
case History
+ case Bookmarks
}
diff --git a/Shared/ContentView.swift b/Shared/ContentView.swift
@@ -11,7 +11,6 @@ struct ContentView: View {
@EnvironmentObject var data: BrowserData
@State private var columnVisibility = NavigationSplitViewVisibility.detailOnly
- @State private var hoveringURLBar = false
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
@@ -22,6 +21,8 @@ struct ContentView: View {
CapsuleView()
case .History:
HistoryView()
+ case .Bookmarks:
+ BookmarksView()
}
} label: {
switch view {
@@ -33,6 +34,8 @@ struct ContentView: View {
}
case .History:
Label("History", systemImage: "clock")
+ case .Bookmarks:
+ Label("Bookmarks", systemImage: "star")
}
}
}
@@ -42,6 +45,8 @@ struct ContentView: View {
CapsuleView()
case .History:
HistoryView()
+ case .Bookmarks:
+ BookmarksView()
}
}
.toolbar {
@@ -50,9 +55,9 @@ struct ContentView: View {
.frame(minWidth: 500)
.textFieldStyle(.roundedBorder)
.autocorrectionDisabled(true)
- .onHover(perform: { hovering in hoveringURLBar = hovering })
.onSubmit { Task { await submitURLBar() } }
.overlay(HStack {
+ bookmarksButton
reloadButton
loading
}, alignment: .trailing)
@@ -91,8 +96,33 @@ struct ContentView: View {
})
}
+ @ViewBuilder private var bookmarksButton: some View {
+ if data.tab.response != nil {
+ if data.hasURLInBookmarks(data.tab.url!) {
+ Button(action: { data.dropURLFromBookmarks(data.tab.url!) }) {
+ Label("Drop from bookmarks", systemImage: "star.fill")
+ .labelStyle(.iconOnly)
+ }
+ .buttonStyle(.borderless)
+ .padding(.trailing, 2)
+ } else {
+ Button(action: {
+ data.addURLToBookmarks(
+ data.tab.url!,
+ label: data.tab.url?.host() ?? data.tab.url!.absoluteString,
+ timestamp: Date.now
+ )
+ }) {
+ Label("Add to bookmarks", systemImage: "star")
+ .labelStyle(.iconOnly)
+ }
+ .buttonStyle(.borderless)
+ .padding(.trailing, 2)
+ }
+ }
+ }
@ViewBuilder private var reloadButton: some View {
- if data.tab.response != nil && hoveringURLBar {
+ if data.tab.response != nil {
Button(action: { Task { await data.reload() } }) {
Label("Reload page", systemImage: "arrow.clockwise")
.labelStyle(.iconOnly)
diff --git a/todo b/todo
@@ -1,7 +1,7 @@
[ ] tabs
[ ] TOFU
[ ] ANSI in preformatted blocks
-[ ] bookmarks/favorites
+[X] bookmarks/favorites
[X] reload page
[X] share menu (link?)
[ ] better home/startpage