diff options
| author | Dustin Mierau <dustin@mierau.me> | 2025-11-07 12:44:55 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2025-11-07 12:44:55 -0800 |
| commit | a55318fa8d643160900bec3e6b14e7404c63497a (patch) | |
| tree | ab6a9eca9a368b35e1490becc70f94ebde6ac271 /Hotline | |
| parent | 786a387d58fc66ae20716a9dee46b74dff8e6894 (diff) | |
Organize Library folder a bit. Update Tracker add/edit sheet design.
Diffstat (limited to 'Hotline')
| -rw-r--r-- | Hotline/Hotline/HotlineProtocol.swift | 5 | ||||
| -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.swift | 23 | ||||
| -rw-r--r-- | Hotline/Library/Extensions.swift (renamed from Hotline/Utility/FoundationExtensions.swift) | 95 | ||||
| -rw-r--r-- | Hotline/Library/NetSocket/FileProgress.swift | 2 | ||||
| -rw-r--r-- | Hotline/Library/NetSocket/NetSocket.swift (renamed from Hotline/Library/NetSocket/NetSocketNew.swift) | 6 | ||||
| -rw-r--r-- | Hotline/Library/NetSocket/TransferRateEstimator.swift | 2 | ||||
| -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.swift | 55 | ||||
| -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.swift | 23 | ||||
| -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.swift | 8 | ||||
| -rw-r--r-- | Hotline/macOS/TrackerView.swift | 49 |
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") } } } |