aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2025-11-07 12:44:55 -0800
committerDustin Mierau <dustin@mierau.me>2025-11-07 12:44:55 -0800
commita55318fa8d643160900bec3e6b14e7404c63497a (patch)
treeab6a9eca9a368b35e1490becc70f94ebde6ac271 /Hotline
parent786a387d58fc66ae20716a9dee46b74dff8e6894 (diff)
Organize Library folder a bit. Update Tracker add/edit sheet design.
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Hotline/HotlineProtocol.swift5
-rw-r--r--Hotline/Library/BookmarkDocument.swift (renamed from Hotline/Utility/BookmarkDocument.swift)0
-rw-r--r--Hotline/Library/ColorArt.swift (renamed from Hotline/Utility/ColorArt.swift)0
-rw-r--r--Hotline/Library/DataAdditions.swift23
-rw-r--r--Hotline/Library/Extensions.swift (renamed from Hotline/Utility/FoundationExtensions.swift)95
-rw-r--r--Hotline/Library/NetSocket/FileProgress.swift2
-rw-r--r--Hotline/Library/NetSocket/NetSocket.swift (renamed from Hotline/Library/NetSocket/NetSocketNew.swift)6
-rw-r--r--Hotline/Library/NetSocket/TransferRateEstimator.swift2
-rw-r--r--Hotline/Library/RegularExpressions.swift (renamed from Hotline/Utility/RegularExpressions.swift)0
-rw-r--r--Hotline/Library/SoundEffects.swift (renamed from Hotline/Utility/SoundEffects.swift)0
-rw-r--r--Hotline/Library/URLAdditions.swift55
-rw-r--r--Hotline/Library/Utility/DAKeychain.swift (renamed from Hotline/Utility/DAKeychain.swift)0
-rw-r--r--Hotline/Library/Utility/NSWindowBridge.swift (renamed from Hotline/Utility/NSWindowBridge.swift)0
-rw-r--r--Hotline/Library/Utility/ObservableScrollView.swift (renamed from Hotline/Utility/ObservableScrollView.swift)0
-rw-r--r--Hotline/Library/Utility/TextDocument.swift (renamed from Hotline/Utility/TextDocument.swift)0
-rw-r--r--Hotline/Library/Views/AsyncLinkPreview.swift (renamed from Hotline/Library/AsyncLinkPreview.swift)0
-rw-r--r--Hotline/Library/Views/BetterTextEditor.swift (renamed from Hotline/Library/TextView.swift)0
-rw-r--r--Hotline/Library/Views/FileIconView.swift (renamed from Hotline/Library/FileIconView.swift)0
-rw-r--r--Hotline/Library/Views/FileImageView.swift (renamed from Hotline/Library/FileImageView.swift)0
-rw-r--r--Hotline/Library/Views/GroupedIconView.swift23
-rw-r--r--Hotline/Library/Views/HotlinePanel.swift (renamed from Hotline/Library/HotlinePanel.swift)0
-rw-r--r--Hotline/Library/Views/QuickLookPreviewView.swift (renamed from Hotline/Library/QuickLookPreviewView.swift)0
-rw-r--r--Hotline/Library/Views/SpinningGlobeView.swift (renamed from Hotline/Library/SpinningGlobeView.swift)0
-rw-r--r--Hotline/Library/Views/VisualEffectView.swift (renamed from Hotline/Library/VisualEffectView.swift)0
-rw-r--r--Hotline/Utility/SwiftUIExtensions.swift8
-rw-r--r--Hotline/macOS/TrackerView.swift49
26 files changed, 157 insertions, 111 deletions
diff --git a/Hotline/Hotline/HotlineProtocol.swift b/Hotline/Hotline/HotlineProtocol.swift
index 927cf69..3870261 100644
--- a/Hotline/Hotline/HotlineProtocol.swift
+++ b/Hotline/Hotline/HotlineProtocol.swift
@@ -1,5 +1,10 @@
import Foundation
+enum Endianness {
+ case big
+ case little
+}
+
struct HotlinePorts {
static let DefaultServerPort: Int = 5500
static let DefaultTrackerPort: Int = 5498
diff --git a/Hotline/Utility/BookmarkDocument.swift b/Hotline/Library/BookmarkDocument.swift
index 47fa442..47fa442 100644
--- a/Hotline/Utility/BookmarkDocument.swift
+++ b/Hotline/Library/BookmarkDocument.swift
diff --git a/Hotline/Utility/ColorArt.swift b/Hotline/Library/ColorArt.swift
index 93889a3..93889a3 100644
--- a/Hotline/Utility/ColorArt.swift
+++ b/Hotline/Library/ColorArt.swift
diff --git a/Hotline/Library/DataAdditions.swift b/Hotline/Library/DataAdditions.swift
deleted file mode 100644
index 0e9dd96..0000000
--- a/Hotline/Library/DataAdditions.swift
+++ /dev/null
@@ -1,23 +0,0 @@
-import Foundation
-
-extension Data {
- func saveAsFileToDownloads(filename: String, bounceDock: Bool = true) -> Bool {
- let folderURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0]
- let filePath = folderURL.generateUniqueFilePath(filename: filename)
- if FileManager.default.createFile(atPath: filePath, contents: nil) {
- if let h = FileHandle(forWritingAtPath: filePath) {
- try? h.write(contentsOf: self)
- try? h.close()
- if bounceDock {
- #if os(macOS)
- var downloadURL = URL(filePath: filePath)
- downloadURL.resolveSymlinksInPath()
- DistributedNotificationCenter.default().post(name: .init("com.apple.DownloadFileFinished"), object: downloadURL.path)
- #endif
- }
- return true
- }
- }
- return false
- }
-}
diff --git a/Hotline/Utility/FoundationExtensions.swift b/Hotline/Library/Extensions.swift
index 90a3032..469676c 100644
--- a/Hotline/Utility/FoundationExtensions.swift
+++ b/Hotline/Library/Extensions.swift
@@ -1,11 +1,88 @@
import Foundation
import SwiftUI
+import UniformTypeIdentifiers
-enum Endianness {
- case big
- case little
+extension Data {
+ func saveAsFileToDownloads(filename: String, bounceDock: Bool = true) -> Bool {
+ let folderURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0]
+ let filePath = folderURL.generateUniqueFilePath(filename: filename)
+ if FileManager.default.createFile(atPath: filePath, contents: nil) {
+ if let h = FileHandle(forWritingAtPath: filePath) {
+ try? h.write(contentsOf: self)
+ try? h.close()
+ if bounceDock {
+ #if os(macOS)
+ var downloadURL = URL(filePath: filePath)
+ downloadURL.resolveSymlinksInPath()
+ DistributedNotificationCenter.default().post(name: .init("com.apple.DownloadFileFinished"), object: downloadURL.path)
+ #endif
+ }
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// MARK: -
+
+extension URL {
+ func generateUniqueFilePath(filename base: String) -> String {
+ let fileManager = FileManager.default
+ var finalName = base
+ var counter = 2
+
+ // Helper function to generate a new filename with a counter
+ func makeFileName() -> String {
+ let baseName = (base as NSString).deletingPathExtension
+ let extensionName = (base as NSString).pathExtension
+ return extensionName.isEmpty ? "\(baseName) \(counter)" : "\(baseName) \(counter).\(extensionName)"
+ }
+
+ // Check if file exists and append counter until a unique name is found
+ var filePath = self.appending(component: finalName).path(percentEncoded: false)
+ while fileManager.fileExists(atPath: filePath) {
+ finalName = makeFileName()
+ filePath = self.appending(component: finalName).path(percentEncoded: false)
+ counter += 1
+ }
+
+ return filePath
+ }
}
+// MARK: -
+
+extension UTType {
+ var canBePreviewedByQuickLook: Bool {
+ // QuickLook supports most common document types
+ let supportedSupertypes: [UTType] = [
+ .image,
+ .movie,
+ .audio,
+ .pdf,
+ .font,
+ .usdz,
+ .text,
+ .sourceCode,
+ .spreadsheet,
+ .presentation,
+
+// Microsoft Office
+ .init(filenameExtension: "doc")!,
+ .init(filenameExtension: "docx")!,
+ .init(filenameExtension: "xls")!,
+ .init(filenameExtension: "xlsx")!,
+ .init(filenameExtension: "ppt")!,
+ .init(filenameExtension: "pptx")!,
+ ]
+
+ return supportedSupertypes.contains { self.conforms(to: $0) }
+ }
+}
+
+// MARK: -
+
extension String {
func markdownToAttributedString() -> AttributedString {
@@ -79,14 +156,14 @@ extension String {
// if let _ = try? RegularExpressions.supportedLinkScheme.prefixMatch(in: linkText) {
// injectedScheme = ""
// }
-//
+//
// return "[\(linkText)](\(injectedScheme)\(linkText))"
// }
// return cp
}
}
-
+// MARK: -
extension Binding where Value: OptionSet, Value == Value.Element {
func bindedValue(_ options: Value) -> Bool {
@@ -105,3 +182,11 @@ extension Binding where Value: OptionSet, Value == Value.Element {
}
}
}
+
+// MARK: -
+
+extension Color {
+ init(hex: Int, opacity: Double = 1.0) {
+ self.init(red: Double((hex >> 16) & 0xFF) / 255.0, green: Double((hex >> 8) & 0xFF) / 255.0, blue: Double(hex & 0xFF) / 255.0, opacity: opacity)
+ }
+}
diff --git a/Hotline/Library/NetSocket/FileProgress.swift b/Hotline/Library/NetSocket/FileProgress.swift
index 1cc0228..c2306f3 100644
--- a/Hotline/Library/NetSocket/FileProgress.swift
+++ b/Hotline/Library/NetSocket/FileProgress.swift
@@ -1,4 +1,4 @@
-// NetSocketProgress
+// NetSocket FileProgress
// Dustin Mierau • @mierau
// MIT License
diff --git a/Hotline/Library/NetSocket/NetSocketNew.swift b/Hotline/Library/NetSocket/NetSocket.swift
index 12f4271..5c7d185 100644
--- a/Hotline/Library/NetSocket/NetSocketNew.swift
+++ b/Hotline/Library/NetSocket/NetSocket.swift
@@ -1,5 +1,6 @@
// NetSocket.swift
// Dustin Mierau • @mierau
+// MIT License
import Foundation
import Network
@@ -791,10 +792,7 @@ public actor NetSocket {
private func startReceiveLoop() {
@Sendable func loop(_ connection: NWConnection, chunk: Int, owner: NetSocket, connID: String) {
- print("NetSocket[\(connID)]: Calling connection.receive(\(chunk)) to request more data...")
-
connection.receive(minimumIncompleteLength: 1, maximumLength: chunk) { [weak owner] data, _, isComplete, error in
- print("NetSocket[\(connID)]: Receive callback - data: \(data?.count ?? 0) bytes, isComplete: \(isComplete), error: \(String(describing: error))")
Task {
guard let o = owner else {
return
@@ -808,7 +806,6 @@ public actor NetSocket {
await o.append(data, connID: connID)
}
if isComplete {
- print("NetSocket[\(connID)]: EOF from peer.")
await o.handleEOF()
return
}
@@ -950,7 +947,6 @@ public actor NetSocket {
}
private func append(_ data: Data, connID: String) {
- print("NetSocket[\(connID)]: Received \(data.count) bytes from network, buffer now has \(buffer.count - head + data.count) available")
buffer.append(data)
if buffer.count - head > config.maxBufferBytes {
// Hard stop: drop connection rather than OOM'ing.
diff --git a/Hotline/Library/NetSocket/TransferRateEstimator.swift b/Hotline/Library/NetSocket/TransferRateEstimator.swift
index 60647a7..badf87a 100644
--- a/Hotline/Library/NetSocket/TransferRateEstimator.swift
+++ b/Hotline/Library/NetSocket/TransferRateEstimator.swift
@@ -1,4 +1,4 @@
-// TransferRateEstimator
+// NetSocket: TransferRateEstimator
// Dustin Mierau • @mierau
// MIT License
diff --git a/Hotline/Utility/RegularExpressions.swift b/Hotline/Library/RegularExpressions.swift
index c1f2a18..c1f2a18 100644
--- a/Hotline/Utility/RegularExpressions.swift
+++ b/Hotline/Library/RegularExpressions.swift
diff --git a/Hotline/Utility/SoundEffects.swift b/Hotline/Library/SoundEffects.swift
index 93f8b9a..93f8b9a 100644
--- a/Hotline/Utility/SoundEffects.swift
+++ b/Hotline/Library/SoundEffects.swift
diff --git a/Hotline/Library/URLAdditions.swift b/Hotline/Library/URLAdditions.swift
deleted file mode 100644
index 0ba2100..0000000
--- a/Hotline/Library/URLAdditions.swift
+++ /dev/null
@@ -1,55 +0,0 @@
-import Foundation
-import UniformTypeIdentifiers
-
-extension URL {
- func generateUniqueFilePath(filename base: String) -> String {
- let fileManager = FileManager.default
- var finalName = base
- var counter = 2
-
- // Helper function to generate a new filename with a counter
- func makeFileName() -> String {
- let baseName = (base as NSString).deletingPathExtension
- let extensionName = (base as NSString).pathExtension
- return extensionName.isEmpty ? "\(baseName) \(counter)" : "\(baseName) \(counter).\(extensionName)"
- }
-
- // Check if file exists and append counter until a unique name is found
- var filePath = self.appending(component: finalName).path(percentEncoded: false)
- while fileManager.fileExists(atPath: filePath) {
- finalName = makeFileName()
- filePath = self.appending(component: finalName).path(percentEncoded: false)
- counter += 1
- }
-
- return filePath
- }
-}
-
-extension UTType {
- var canBePreviewedByQuickLook: Bool {
- // QuickLook supports most common document types
- let supportedSupertypes: [UTType] = [
- .image,
- .movie,
- .audio,
- .pdf,
- .font,
- .usdz,
- .text,
- .sourceCode,
- .spreadsheet,
- .presentation,
-
-// Microsoft Office
- .init(filenameExtension: "doc")!,
- .init(filenameExtension: "docx")!,
- .init(filenameExtension: "xls")!,
- .init(filenameExtension: "xlsx")!,
- .init(filenameExtension: "ppt")!,
- .init(filenameExtension: "pptx")!,
- ]
-
- return supportedSupertypes.contains { self.conforms(to: $0) }
- }
-}
diff --git a/Hotline/Utility/DAKeychain.swift b/Hotline/Library/Utility/DAKeychain.swift
index 8031886..8031886 100644
--- a/Hotline/Utility/DAKeychain.swift
+++ b/Hotline/Library/Utility/DAKeychain.swift
diff --git a/Hotline/Utility/NSWindowBridge.swift b/Hotline/Library/Utility/NSWindowBridge.swift
index 8f766d9..8f766d9 100644
--- a/Hotline/Utility/NSWindowBridge.swift
+++ b/Hotline/Library/Utility/NSWindowBridge.swift
diff --git a/Hotline/Utility/ObservableScrollView.swift b/Hotline/Library/Utility/ObservableScrollView.swift
index a6f46cc..a6f46cc 100644
--- a/Hotline/Utility/ObservableScrollView.swift
+++ b/Hotline/Library/Utility/ObservableScrollView.swift
diff --git a/Hotline/Utility/TextDocument.swift b/Hotline/Library/Utility/TextDocument.swift
index 82727de..82727de 100644
--- a/Hotline/Utility/TextDocument.swift
+++ b/Hotline/Library/Utility/TextDocument.swift
diff --git a/Hotline/Library/AsyncLinkPreview.swift b/Hotline/Library/Views/AsyncLinkPreview.swift
index 89b186f..89b186f 100644
--- a/Hotline/Library/AsyncLinkPreview.swift
+++ b/Hotline/Library/Views/AsyncLinkPreview.swift
diff --git a/Hotline/Library/TextView.swift b/Hotline/Library/Views/BetterTextEditor.swift
index 47746e2..47746e2 100644
--- a/Hotline/Library/TextView.swift
+++ b/Hotline/Library/Views/BetterTextEditor.swift
diff --git a/Hotline/Library/FileIconView.swift b/Hotline/Library/Views/FileIconView.swift
index d0949fa..d0949fa 100644
--- a/Hotline/Library/FileIconView.swift
+++ b/Hotline/Library/Views/FileIconView.swift
diff --git a/Hotline/Library/FileImageView.swift b/Hotline/Library/Views/FileImageView.swift
index 0cc50f1..0cc50f1 100644
--- a/Hotline/Library/FileImageView.swift
+++ b/Hotline/Library/Views/FileImageView.swift
diff --git a/Hotline/Library/Views/GroupedIconView.swift b/Hotline/Library/Views/GroupedIconView.swift
new file mode 100644
index 0000000..313fac6
--- /dev/null
+++ b/Hotline/Library/Views/GroupedIconView.swift
@@ -0,0 +1,23 @@
+import SwiftUI
+
+struct GroupedIconView: View {
+ let color: Color
+ let systemName: String
+ var padding: CGFloat = 6.0
+ var cornerRadius: CGFloat = 8.0
+
+ var body: some View {
+ RoundedRectangle(cornerRadius: self.cornerRadius, style: .continuous)
+ .fill(LinearGradient(colors: [self.color.mix(with: .white, by: 0.2), self.color], startPoint: .top, endPoint: .bottom))
+ .shadow(color: self.color.mix(with: .black, by: 0.5).opacity(0.2), radius: 1, x: 0, y: 1)
+ .overlay {
+ Image(systemName: self.systemName)
+ .resizable()
+ .scaledToFit()
+ .symbolRenderingMode(.palette)
+ .foregroundStyle(.white, .white.opacity(0.4))
+ .padding(self.padding)
+ .shadow(color: self.color.mix(with: .black, by: 0.5).opacity(0.2), radius: 0, x: 0, y: -1)
+ }
+ }
+}
diff --git a/Hotline/Library/HotlinePanel.swift b/Hotline/Library/Views/HotlinePanel.swift
index d7d8284..d7d8284 100644
--- a/Hotline/Library/HotlinePanel.swift
+++ b/Hotline/Library/Views/HotlinePanel.swift
diff --git a/Hotline/Library/QuickLookPreviewView.swift b/Hotline/Library/Views/QuickLookPreviewView.swift
index 6ba154e..6ba154e 100644
--- a/Hotline/Library/QuickLookPreviewView.swift
+++ b/Hotline/Library/Views/QuickLookPreviewView.swift
diff --git a/Hotline/Library/SpinningGlobeView.swift b/Hotline/Library/Views/SpinningGlobeView.swift
index bccb969..bccb969 100644
--- a/Hotline/Library/SpinningGlobeView.swift
+++ b/Hotline/Library/Views/SpinningGlobeView.swift
diff --git a/Hotline/Library/VisualEffectView.swift b/Hotline/Library/Views/VisualEffectView.swift
index e595c55..e595c55 100644
--- a/Hotline/Library/VisualEffectView.swift
+++ b/Hotline/Library/Views/VisualEffectView.swift
diff --git a/Hotline/Utility/SwiftUIExtensions.swift b/Hotline/Utility/SwiftUIExtensions.swift
deleted file mode 100644
index d0dfff4..0000000
--- a/Hotline/Utility/SwiftUIExtensions.swift
+++ /dev/null
@@ -1,8 +0,0 @@
-import SwiftUI
-import Foundation
-
-extension Color {
- init(hex: Int, opacity: Double = 1.0) {
- self.init(red: Double((hex >> 16) & 0xFF) / 255.0, green: Double((hex >> 8) & 0xFF) / 255.0, blue: Double(hex & 0xFF) / 255.0, opacity: opacity)
- }
-}
diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift
index 34f7a57..6fab091 100644
--- a/Hotline/macOS/TrackerView.swift
+++ b/Hotline/macOS/TrackerView.swift
@@ -485,38 +485,61 @@ struct TrackerBookmarkSheet: View {
var body: some View {
VStack(alignment: .leading) {
- if self.bookmark == nil {
- Text("Type the address and name of a Hotline Tracker:")
- .foregroundStyle(.secondary)
- .padding(.bottom, 8)
- }
-
Form {
+ if self.bookmark == nil {
+ HStack(alignment: .top, spacing: 10) {
+ GroupedIconView(color: .blue, systemName: "point.3.filled.connected.trianglepath.dotted", padding: 5.0)
+ .frame(width: 28, height: 28)
+
+ VStack(alignment: .leading) {
+ Text("Add a Hotline Tracker")
+
+ Text("Enter the address and name of a Hotline Tracker you want to add.")
+ .foregroundStyle(.secondary)
+ .font(.subheadline)
+ }
+ }
+ }
+ else {
+ HStack(alignment: .top, spacing: 10) {
+ GroupedIconView(color: .blue, systemName: "point.3.filled.connected.trianglepath.dotted", padding: 5.0)
+ .frame(width: 28, height: 28)
+
+ VStack(alignment: .leading) {
+ Text("Edit Hotline Tracker")
+
+ Text("Change the address and name of your Hotline Tracker.")
+ .foregroundStyle(.secondary)
+ .font(.subheadline)
+ }
+ }
+ }
+
Group {
TextField(text: $trackerAddress) {
- Text("Address:")
+ Text("Address")
}
TextField(text: $trackerName, prompt: Text("Optional")) {
- Text("Name:")
+ Text("Name")
}
}
- .textFieldStyle(.roundedBorder)
+// .textFieldStyle(.roundedBorder)
.controlSize(.large)
}
+ .formStyle(.grouped)
}
- .frame(width: 300)
+ .frame(width: 350)
.fixedSize(horizontal: true, vertical: true)
- .padding()
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button {
self.saveTracker()
} label: {
if self.bookmark != nil {
- Text("Save Tracker")
+ Text("Save")
}
else {
- Text("Add Tracker")
+ Text("Add")
}
}
}