aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2025-10-21 10:17:23 -0700
committerDustin Mierau <dustin@mierau.me>2025-10-21 10:17:23 -0700
commit926c92be7a32e374c8855b2eb8b5a49485dec072 (patch)
tree546d09d4b8c0e29a296fca93c8393cf9b2e18832 /Hotline
parentede41868962ffed386b0da694d14cdfe6cfdb34f (diff)
Add bookmark editing to TrackerView (you can add login/pass to bookmarks now). Fix macOS 26 border around images in toolbar.
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Models/Bookmark.swift2
-rw-r--r--Hotline/macOS/ServerView.swift26
-rw-r--r--Hotline/macOS/TrackerView.swift205
3 files changed, 167 insertions, 66 deletions
diff --git a/Hotline/Models/Bookmark.swift b/Hotline/Models/Bookmark.swift
index 394f9f6..80963f9 100644
--- a/Hotline/Models/Bookmark.swift
+++ b/Hotline/Models/Bookmark.swift
@@ -75,7 +75,7 @@ final class Bookmark {
}
static let DefaultBookmarks: [Bookmark] = [
- Bookmark(type: .server, name: "The Mobius Strip", address: "67.174.208.111", port: HotlinePorts.DefaultServerPort),
+ Bookmark(type: .server, name: "The Mobius Strip", address: "24.6.82.54", port: HotlinePorts.DefaultServerPort),
Bookmark(type: .server, name: "System 7 Today", address: "hotline.system7today.com", port: HotlinePorts.DefaultServerPort),
Bookmark(type: .tracker, name: "Featured Servers", address: "hltracker.com", port: HotlinePorts.DefaultTrackerPort)
]
diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift
index e9f4a96..154bd7c 100644
--- a/Hotline/macOS/ServerView.swift
+++ b/Hotline/macOS/ServerView.swift
@@ -212,14 +212,24 @@ struct ServerView: View {
.onChange(of: Prefs.shared.enableAutomaticMessage) { sendPreferences() }
.onChange(of: Prefs.shared.automaticMessage) { sendPreferences() }
.toolbar {
- ToolbarItem(placement: .navigation) {
- Image("Server Large")
-// .renderingMode(.template)
-
- .resizable()
- .scaledToFit()
- .frame(width: 28)
- .opacity(controlActiveState == .inactive ? 0.4 : 1.0)
+ if #available(macOS 26.0, *) {
+ ToolbarItem(placement: .navigation) {
+ Image("Server Large")
+ .resizable()
+ .scaledToFit()
+ .frame(width: 28)
+ .opacity(controlActiveState == .inactive ? 0.4 : 1.0)
+ }
+ .sharedBackgroundVisibility(.hidden)
+ }
+ else {
+ ToolbarItem(placement: .navigation) {
+ Image("Server Large")
+ .resizable()
+ .scaledToFit()
+ .frame(width: 28)
+ .opacity(controlActiveState == .inactive ? 0.4 : 1.0)
+ }
}
}
}
diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift
index 2fbce85..83a56b8 100644
--- a/Hotline/macOS/TrackerView.swift
+++ b/Hotline/macOS/TrackerView.swift
@@ -24,6 +24,7 @@ struct TrackerView: View {
@State private var refreshing = false
@State private var trackerSheetPresented: Bool = false
@State private var trackerSheetBookmark: Bookmark? = nil
+ @State private var serverSheetBookmark: Bookmark? = nil
@State private var attemptedPrepopulate: Bool = false
@State private var fileDropActive = false
@State private var bookmarkExportActive = false
@@ -270,22 +271,21 @@ struct TrackerView: View {
.sheet(isPresented: $trackerSheetPresented) {
TrackerBookmarkSheet()
}
+ .sheet(item: $serverSheetBookmark) { item in
+ ServerBookmarkSheet(item)
+ }
.navigationTitle("Servers")
.toolbar {
- ToolbarItem(placement: .navigation) {
- let image = Image("Hotline")
- .resizable()
- .renderingMode(.template)
- .scaledToFit()
- .foregroundColor(Color(hex: 0xE10000))
- .frame(width: 9)
- .opacity(controlActiveState == .inactive ? 0.5 : 1.0)
-
-// if #available(macOS 26, *) {
-// image.sharedBackgroundVisibility(.hidden)
-// } else {
- image
-// }
+ if #available(macOS 26.0, *) {
+ ToolbarItem(placement: .navigation) {
+ self.hotlineLogoImage
+ }
+ .sharedBackgroundVisibility(.hidden)
+ }
+ else {
+ ToolbarItem(placement: .navigation) {
+ self.hotlineLogoImage
+ }
}
ToolbarItem(placement: .primaryAction) {
@@ -326,6 +326,16 @@ struct TrackerView: View {
.searchable(text: $searchText, placement: .automatic, prompt: "Search")
}
+ private var hotlineLogoImage: some View {
+ Image("Hotline")
+ .resizable()
+ .renderingMode(.template)
+ .scaledToFit()
+ .foregroundColor(Color(hex: 0xE10000))
+ .frame(width: 9)
+ .opacity(controlActiveState == .inactive ? 0.5 : 1.0)
+ }
+
@ViewBuilder
func bookmarkServerContextMenu(_ server: BookmarkServer) -> some View {
Button {
@@ -368,10 +378,16 @@ struct TrackerView: View {
if bookmark.type == .server {
Button {
+ serverSheetBookmark = bookmark
+ } label: {
+ Label("Edit Bookmark...", systemImage: "pencil")
+ }
+
+ Button {
bookmarkExport = BookmarkDocument(bookmark: bookmark)
bookmarkExportActive = true
} label: {
- Label("Export Bookmark...", systemImage: "bookmark.square")
+ Label("Export Bookmark...", systemImage: "square.and.arrow.down")
}
}
@@ -481,9 +497,12 @@ struct TrackerBookmarkSheet: View {
var body: some View {
VStack(alignment: .leading) {
- Text("Type the address and name of a Hotline Tracker:")
- .foregroundStyle(.secondary)
- .padding(.bottom, 8)
+ if self.bookmark == nil {
+ Text("Type the address and name of a Hotline Tracker:")
+ .foregroundStyle(.secondary)
+ .padding(.bottom, 8)
+ }
+
Form {
Group {
TextField(text: $trackerAddress) {
@@ -502,33 +521,14 @@ struct TrackerBookmarkSheet: View {
.padding()
.toolbar {
ToolbarItem(placement: .confirmationAction) {
- Button(self.bookmark != nil ? "Save Tracker" : "Add Tracker") {
- var displayName = trackerName.trimmingCharacters(in: .whitespacesAndNewlines)
- let (host, port) = Tracker.parseTrackerAddressAndPort(trackerAddress)
-
- if displayName.isEmpty {
- displayName = host
+ Button {
+ self.saveTracker()
+ } label: {
+ if self.bookmark != nil {
+ Text("Save Tracker")
}
-
- if !displayName.isEmpty && !host.isEmpty {
- if !host.isEmpty {
- if self.bookmark != nil {
- // We're editing an existing bookmark.
- self.bookmark?.name = displayName
- self.bookmark?.address = host
- self.bookmark?.port = port
- }
- else {
- // We're creating a new bookmark.
- let newBookmark = Bookmark(type: .tracker, name: displayName, address: host, port: port)
- Bookmark.add(newBookmark, context: modelContext)
- }
-
- self.trackerName = ""
- self.trackerAddress = ""
-
- dismiss()
- }
+ else {
+ Text("Add Tracker")
}
}
}
@@ -537,7 +537,109 @@ struct TrackerBookmarkSheet: View {
self.trackerName = ""
self.trackerAddress = ""
- dismiss()
+ self.dismiss()
+ }
+ }
+ }
+ }
+
+ private func saveTracker() {
+ var displayName = trackerName.trimmingCharacters(in: .whitespacesAndNewlines)
+ let (host, port) = Tracker.parseTrackerAddressAndPort(trackerAddress)
+
+ if displayName.isEmpty {
+ displayName = host
+ }
+
+ if !displayName.isEmpty && !host.isEmpty {
+ if !host.isEmpty {
+ if self.bookmark != nil {
+ // We're editing an existing bookmark.
+ self.bookmark?.name = displayName
+ self.bookmark?.address = host
+ self.bookmark?.port = port
+ }
+ else {
+ // We're creating a new bookmark.
+ let newBookmark = Bookmark(type: .tracker, name: displayName, address: host, port: port)
+ Bookmark.add(newBookmark, context: modelContext)
+ }
+
+ self.trackerName = ""
+ self.trackerAddress = ""
+
+ self.dismiss()
+ }
+ }
+ }
+}
+
+struct ServerBookmarkSheet: View {
+ @Environment(\.dismiss) private var dismiss
+ @Environment(\.modelContext) private var modelContext
+
+ @State private var bookmark: Bookmark
+ @State private var serverName: String = ""
+ @State private var serverAddress: String = ""
+ @State private var serverLogin: String = ""
+ @State private var serverPassword: String = ""
+
+ init(_ editingBookmark: Bookmark) {
+ _bookmark = .init(initialValue: editingBookmark)
+ _serverName = .init(initialValue: editingBookmark.name)
+ _serverAddress = .init(initialValue: editingBookmark.displayAddress)
+ _serverLogin = .init(initialValue: editingBookmark.login ?? "")
+ _serverPassword = .init(initialValue: editingBookmark.password ?? "")
+ }
+
+ var body: some View {
+ VStack(alignment: .leading) {
+ Form {
+ Group {
+ TextField(text: $serverName) {
+ Text("Name:")
+ }
+ .padding(.bottom)
+
+ TextField(text: $serverAddress) {
+ Text("Address:")
+ }
+ TextField(text: $serverLogin, prompt: Text("Optional")) {
+ Text("Login:")
+ }
+ SecureField(text: $serverPassword, prompt: Text("Optional")) {
+ Text("Password:")
+ }
+ }
+ .textFieldStyle(.roundedBorder)
+ .controlSize(.large)
+ }
+ }
+ .frame(width: 300)
+ .fixedSize(horizontal: true, vertical: true)
+ .padding()
+ .toolbar {
+ ToolbarItem(placement: .confirmationAction) {
+ Button("Save Bookmark") {
+ let displayName = self.serverName.trimmingCharacters(in: .whitespacesAndNewlines)
+ let (host, port) = Server.parseServerAddressAndPort(self.serverAddress)
+ let login = self.serverLogin.trimmingCharacters(in: .whitespacesAndNewlines)
+ let password = self.serverPassword
+
+ if !displayName.isEmpty && !host.isEmpty {
+ self.bookmark.name = displayName
+ self.bookmark.address = host
+ self.bookmark.port = port
+ self.bookmark.login = login.isEmpty ? nil : login
+ self.bookmark.password = password.isEmpty ? nil : password
+
+ self.dismiss()
+ }
+ }
+ }
+ ToolbarItem(placement: .cancellationAction) {
+ Button("Cancel") {
+ self.dismiss()
}
}
}
@@ -575,7 +677,7 @@ struct TrackerBookmarkServerView: View {
content.opacity(opacity)
} keyframes: { _ in
CubicKeyframe(1.0, duration: 2.0) // Stay visible for 1 second
- CubicKeyframe(0.75, duration: 0.5) // Fade out quickly
+ CubicKeyframe(0.6, duration: 0.5) // Fade out quickly
CubicKeyframe(1.0, duration: 0.5) // Fade in quickly
}
.padding(.trailing, 6)
@@ -640,17 +742,6 @@ struct TrackerItemView: View {
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
-// .onChange(of: self.isExpanded) {
-// guard bookmark.type == .tracker else {
-// return
-// }
-//
-// if self.isExpanded {
-// Task {
-// await bookmark.fetchServers()
-// }
-// }
-// }
}
}