aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Shared
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-02-05 22:27:17 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-02-05 22:27:17 +0100
commit45829daa856b376b1ab04d415917110b71b1dec5 (patch)
tree8e52daed6897b6f489d455736fe256cb9bd90fef /Hotline/Shared
parent5c3ea897d062a47bc8cd6255fb8c36bad2f0733f (diff)
Apply formatting
Diffstat (limited to 'Hotline/Shared')
-rw-r--r--Hotline/Shared/AsyncLinkPreview.swift16
-rw-r--r--Hotline/Shared/DataAdditions.swift7
-rw-r--r--Hotline/Shared/FileIconView.swift85
-rw-r--r--Hotline/Shared/FileImageView.swift62
-rw-r--r--Hotline/Shared/HotlinePanel.swift39
-rw-r--r--Hotline/Shared/NetSocket.swift155
-rw-r--r--Hotline/Shared/TextView.swift62
-rw-r--r--Hotline/Shared/URLAdditions.swift9
-rw-r--r--Hotline/Shared/VisualEffectView.swift13
9 files changed, 228 insertions, 220 deletions
diff --git a/Hotline/Shared/AsyncLinkPreview.swift b/Hotline/Shared/AsyncLinkPreview.swift
index 89b186f..6f32abb 100644
--- a/Hotline/Shared/AsyncLinkPreview.swift
+++ b/Hotline/Shared/AsyncLinkPreview.swift
@@ -1,15 +1,17 @@
-import SwiftUI
import LinkPresentation
+import SwiftUI
-fileprivate class CustomLinkView: LPLinkView {
- override var intrinsicContentSize: CGSize { CGSize(width: 0, height: super.intrinsicContentSize.height) }
+private class CustomLinkView: LPLinkView {
+ override var intrinsicContentSize: CGSize {
+ CGSize(width: 0, height: super.intrinsicContentSize.height)
+ }
}
struct AsyncLinkPreview: View {
@State private var metadata: LPLinkMetadata?
@State private var isLoading = true
let url: URL?
-
+
func fetchMetadata() async {
guard let url else {
self.isLoading = false
@@ -24,7 +26,7 @@ struct AsyncLinkPreview: View {
self.isLoading = false
}
}
-
+
var body: some View {
if isLoading {
ProgressView()
@@ -45,12 +47,12 @@ struct AsyncLinkPreview: View {
struct LinkView: NSViewRepresentable {
var metadata: LPLinkMetadata
-
+
func makeNSView(context: Context) -> LPLinkView {
let linkView = CustomLinkView(metadata: metadata)
return linkView
}
-
+
func updateNSView(_ nsView: LPLinkView, context: Context) {
// Nothing required
}
diff --git a/Hotline/Shared/DataAdditions.swift b/Hotline/Shared/DataAdditions.swift
index 0e9dd96..1eb7f6f 100644
--- a/Hotline/Shared/DataAdditions.swift
+++ b/Hotline/Shared/DataAdditions.swift
@@ -10,9 +10,10 @@ extension Data {
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)
+ var downloadURL = URL(filePath: filePath)
+ downloadURL.resolveSymlinksInPath()
+ DistributedNotificationCenter.default().post(
+ name: .init("com.apple.DownloadFileFinished"), object: downloadURL.path)
#endif
}
return true
diff --git a/Hotline/Shared/FileIconView.swift b/Hotline/Shared/FileIconView.swift
index d0949fa..d39ff1e 100644
--- a/Hotline/Shared/FileIconView.swift
+++ b/Hotline/Shared/FileIconView.swift
@@ -3,13 +3,13 @@ import UniformTypeIdentifiers
struct FolderIconView: View {
private func folderIcon() -> Image {
-#if os(iOS)
- return Image(systemName: "folder.fill")
-#elseif os(macOS)
- return Image(nsImage: NSWorkspace.shared.icon(for: UTType.folder))
-#endif
+ #if os(iOS)
+ return Image(systemName: "folder.fill")
+ #elseif os(macOS)
+ return Image(nsImage: NSWorkspace.shared.icon(for: UTType.folder))
+ #endif
}
-
+
var body: some View {
folderIcon()
.resizable()
@@ -20,52 +20,47 @@ struct FolderIconView: View {
struct FileIconView: View {
let filename: String
let fileType: String?
-
+
#if os(iOS)
- private func fileIcon() -> Image {
- let fileExtension = (self.filename as NSString).pathExtension
- if let fileType = UTType(filenameExtension: fileExtension) {
- if fileType.isSubtype(of: .movie) {
- return Image(systemName: "play.rectangle")
- }
- else if fileType.isSubtype(of: .image) {
- return Image(systemName: "photo")
- }
- else if fileType.isSubtype(of: .archive) {
- return Image(systemName: "doc.zipper")
- }
- else if fileType.isSubtype(of: .text) {
- return Image(systemName: "doc.text")
- }
- else {
- return Image(systemName: "doc")
+ private func fileIcon() -> Image {
+ let fileExtension = (self.filename as NSString).pathExtension
+ if let fileType = UTType(filenameExtension: fileExtension) {
+ if fileType.isSubtype(of: .movie) {
+ return Image(systemName: "play.rectangle")
+ } else if fileType.isSubtype(of: .image) {
+ return Image(systemName: "photo")
+ } else if fileType.isSubtype(of: .archive) {
+ return Image(systemName: "doc.zipper")
+ } else if fileType.isSubtype(of: .text) {
+ return Image(systemName: "doc.text")
+ } else {
+ return Image(systemName: "doc")
+ }
}
+
+ return Image(systemName: "doc")
}
-
- return Image(systemName: "doc")
- }
#elseif os(macOS)
- private func fileIcon() -> Image {
- let fileExtension = (self.filename as NSString).pathExtension
-
- if !fileExtension.isEmpty,
- let uttype = UTType(filenameExtension: fileExtension) {
- return Image(nsImage: NSWorkspace.shared.icon(for: uttype))
- }
- else if let fileType = self.fileType,
- let fileTypeExtension = FileManager.HFSTypeToExtension[fileType.lowercased()],
- let uttype = UTType(filenameExtension: fileTypeExtension) {
- return Image(nsImage: NSWorkspace.shared.icon(for: uttype))
- }
- else {
- return Image(nsImage: NSWorkspace.shared.icon(for: UTType.data))
+ private func fileIcon() -> Image {
+ let fileExtension = (self.filename as NSString).pathExtension
+
+ if !fileExtension.isEmpty,
+ let uttype = UTType(filenameExtension: fileExtension)
+ {
+ return Image(nsImage: NSWorkspace.shared.icon(for: uttype))
+ } else if let fileType = self.fileType,
+ let fileTypeExtension = FileManager.HFSTypeToExtension[fileType.lowercased()],
+ let uttype = UTType(filenameExtension: fileTypeExtension)
+ {
+ return Image(nsImage: NSWorkspace.shared.icon(for: uttype))
+ } else {
+ return Image(nsImage: NSWorkspace.shared.icon(for: UTType.data))
+ }
+
+ // Image(nsImage: NSWorkspace.shared.icon(for: UTType(filenameExtension: (filename as NSString).pathExtension) ?? UTType.content))
}
-
-// Image(nsImage: NSWorkspace.shared.icon(for: UTType(filenameExtension: (filename as NSString).pathExtension) ?? UTType.content))
- }
#endif
-
var body: some View {
fileIcon()
.resizable()
diff --git a/Hotline/Shared/FileImageView.swift b/Hotline/Shared/FileImageView.swift
index 0cc50f1..141a71b 100644
--- a/Hotline/Shared/FileImageView.swift
+++ b/Hotline/Shared/FileImageView.swift
@@ -2,10 +2,10 @@ import SwiftUI
struct FileImageView: NSViewRepresentable {
var image: NSImage?
-
+
let minimumSize: CGSize = CGSize(width: 350, height: 350)
let presentationPaddingRatio: Double = 0.5
-
+
func makeNSView(context: Context) -> NSImageView {
let imageView = NSImageView()
imageView.imageScaling = .scaleProportionallyUpOrDown
@@ -14,85 +14,89 @@ struct FileImageView: NSViewRepresentable {
imageView.allowsCutCopyPaste = true
imageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
imageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
-
+
if let img = self.image {
imageView.image = img
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.resizeWindowForImageView(imageView)
}
}
-
+
return imageView
}
-
+
func updateNSView(_ nsView: NSImageView, context: Context) {
nsView.image = self.image
}
-
+
// MARK: -
-
+
func resizeWindowForImageView(_ imageView: NSImageView) {
guard let window = imageView.window, let img = imageView.image else {
return
}
-
+
var windowRect = window.contentLayoutRect
- let windowChromeSize = CGSize(width: window.frame.width - windowRect.width, height: window.frame.height - windowRect.height)
-
+ let windowChromeSize = CGSize(
+ width: window.frame.width - windowRect.width, height: window.frame.height - windowRect.height)
+
var windowMinSize: CGSize = windowRect.size
let centerPoint = CGPoint(x: window.frame.midX, y: window.frame.midY)
-
+
windowRect.size = img.size
-
+
if let screen = window.screen {
var paddedScreenSize = screen.frame.size
paddedScreenSize.width *= self.presentationPaddingRatio
paddedScreenSize.height *= self.presentationPaddingRatio
-
+
windowMinSize = aspectFit(source: windowRect.size, bounds: self.minimumSize)
- windowRect.size = aspectFit(source: windowRect.size, bounds: paddedScreenSize, minimum: windowMinSize)
+ windowRect.size = aspectFit(
+ source: windowRect.size, bounds: paddedScreenSize, minimum: windowMinSize)
}
-
+
windowRect.size.width += windowChromeSize.width
windowRect.size.height += windowChromeSize.height
-
+
windowRect.origin.x = centerPoint.x - windowRect.width / 2.0
windowRect.origin.y = centerPoint.y - windowRect.height / 2.0
-
+
window.setFrame(windowRect, display: true, animate: true)
-
-// Do these APIs even work??
-// window.aspectRatio = windowRect.size
-// window.contentAspectRatio = windowRect.size
+
+ // Do these APIs even work??
+ // window.aspectRatio = windowRect.size
+ // window.contentAspectRatio = windowRect.size
}
-
- func aspectFit(source sourceSize: CGSize, bounds boundingSize: CGSize, minimum minSize: CGSize? = nil) -> CGSize {
+
+ func aspectFit(
+ source sourceSize: CGSize, bounds boundingSize: CGSize, minimum minSize: CGSize? = nil
+ ) -> CGSize {
let sourceAspectRatio = sourceSize.width / sourceSize.height
-
+
var fitSize: CGSize = sourceSize
-
+
if fitSize.width > boundingSize.width {
fitSize.width = boundingSize.width
fitSize.height = fitSize.width / sourceAspectRatio
}
-
+
if fitSize.height > boundingSize.height {
fitSize.height = boundingSize.height
fitSize.width = fitSize.height * sourceAspectRatio
}
-
+
if let m = minSize {
if fitSize.width < m.width {
fitSize.width = m.width
fitSize.height = fitSize.width / sourceAspectRatio
}
-
+
if fitSize.height < m.height {
fitSize.height = m.height
fitSize.width = fitSize.height * sourceAspectRatio
}
}
-
+
return fitSize
}
}
diff --git a/Hotline/Shared/HotlinePanel.swift b/Hotline/Shared/HotlinePanel.swift
index 191e89a..6376a07 100644
--- a/Hotline/Shared/HotlinePanel.swift
+++ b/Hotline/Shared/HotlinePanel.swift
@@ -1,63 +1,68 @@
import Cocoa
import SwiftUI
-fileprivate let HOTLINE_PANEL_SIZE: CGSize = CGSizeMake(468, 114 - 10)
+private let HOTLINE_PANEL_SIZE: CGSize = CGSizeMake(468, 114 - 10)
class HotlinePanel: NSPanel {
init(_ view: HotlinePanelView) {
- super.init(contentRect: NSRect(x: 0, y: 0, width: HOTLINE_PANEL_SIZE.width, height: HOTLINE_PANEL_SIZE.height), styleMask: [.nonactivatingPanel, .titled, .closable, .utilityWindow, .fullSizeContentView], backing: .buffered, defer: false)
-
+ super.init(
+ contentRect: NSRect(
+ x: 0, y: 0, width: HOTLINE_PANEL_SIZE.width, height: HOTLINE_PANEL_SIZE.height),
+ styleMask: [.nonactivatingPanel, .titled, .closable, .utilityWindow, .fullSizeContentView],
+ backing: .buffered, defer: false)
+
// Make sure that the panel is in front of almost all other windows
self.isFloatingPanel = false
self.level = .floating
self.hidesOnDeactivate = true
self.animationBehavior = .utilityWindow
-
+
// Allow the panel to appear in a fullscreen space
-// self.collectionBehavior.insert(.fullScreenAuxiliary)
+ // self.collectionBehavior.insert(.fullScreenAuxiliary)
self.collectionBehavior.insert(.canJoinAllSpaces)
self.collectionBehavior.insert(.ignoresCycle)
-
-// self.appearance = NSAppearance(named: .vibrantDark)
+
+ // self.appearance = NSAppearance(named: .vibrantDark)
// Don't delete panel state when it's closed.
self.isReleasedWhenClosed = false
-
+
self.standardWindowButton(.closeButton)?.isHidden = true
self.standardWindowButton(.zoomButton)?.isHidden = true
self.standardWindowButton(.miniaturizeButton)?.isHidden = true
-
+
// Make it transparent, the view inside will have to set the background.
// This is necessary because otherwise, we will have some space for the titlebar on top of the height of the view itself which we don't want.
self.isOpaque = false
self.backgroundColor = .clear
-
+
// Since we don't show a statusbar, this allows us to drag the window by its background instead of the titlebar.
self.isMovableByWindowBackground = true
self.titlebarAppearsTransparent = true
-
+
let hostingView = NSHostingView(rootView: view.edgesIgnoringSafeArea(.top))
hostingView.sizingOptions = [.preferredContentSize]
- let visualEffectView = NSVisualEffectView(frame: NSRect(x: 0, y: 0, width: HOTLINE_PANEL_SIZE.width, height: HOTLINE_PANEL_SIZE.height))
+ let visualEffectView = NSVisualEffectView(
+ frame: NSRect(x: 0, y: 0, width: HOTLINE_PANEL_SIZE.width, height: HOTLINE_PANEL_SIZE.height))
visualEffectView.material = .sidebar
visualEffectView.blendingMode = .behindWindow
visualEffectView.state = NSVisualEffectView.State.active
visualEffectView.autoresizingMask = [.width, .height]
visualEffectView.autoresizesSubviews = true
visualEffectView.addSubview(hostingView)
-
+
self.contentView = visualEffectView
-
+
hostingView.frame = visualEffectView.bounds
-
+
self.cascadeTopLeft(from: NSMakePoint(16, 16))
}
-
+
override var canBecomeKey: Bool {
return false
}
-
+
override var canBecomeMain: Bool {
return false
}
diff --git a/Hotline/Shared/NetSocket.swift b/Hotline/Shared/NetSocket.swift
index 263487b..59c26af 100644
--- a/Hotline/Shared/NetSocket.swift
+++ b/Hotline/Shared/NetSocket.swift
@@ -1,4 +1,3 @@
-
// NetSocket.swift
// A simple delegate based buffered read/write TCP socket.
// Created by Dustin Mierau
@@ -27,56 +26,57 @@ enum NetSocketStatus {
final class NetSocket: NSObject, StreamDelegate {
weak var delegate: NetSocketDelegate? = nil
-
+
private var output: OutputStream? = nil
private var input: InputStream? = nil
-
+
private var outputBuffer: [UInt8] = []
private var inputBuffer: [UInt8] = []
-
+
private var readBuffer: [UInt8] = Array(repeating: 0, count: 4 * 1024)
-
+
public func peek() -> [UInt8] { self.inputBuffer }
public var available: Int { self.inputBuffer.count }
-
+
private var status: NetSocketStatus = .disconnected
-
+
@MainActor public func has(_ length: Int) -> Bool {
return (self.available >= length)
}
-
+
override init() {}
-
+
@MainActor public func connect(host: String, port: Int) {
self.close()
-
+
var outputStream: OutputStream? = nil
var inputStream: InputStream? = nil
-
+
self.status = .connecting
-
- Stream.getStreamsToHost(withName: host, port: port, inputStream: &inputStream, outputStream: &outputStream)
-
+
+ Stream.getStreamsToHost(
+ withName: host, port: port, inputStream: &inputStream, outputStream: &outputStream)
+
self.input = inputStream
self.output = outputStream
-
+
inputStream?.delegate = self
outputStream?.delegate = self
-
+
inputStream?.schedule(in: .current, forMode: .default)
outputStream?.schedule(in: .current, forMode: .default)
-
+
inputStream?.open()
outputStream?.open()
}
-
+
@MainActor public func close(_ err: Error? = nil) {
print("NetSocket: Closed")
-
+
let disconnected = (self.status != .disconnected)
-
+
self.status = .disconnected
-
+
self.input?.delegate = nil
self.output?.delegate = nil
self.input?.close()
@@ -87,122 +87,120 @@ final class NetSocket: NSObject, StreamDelegate {
self.output = nil
self.inputBuffer = []
self.outputBuffer = []
-
+
if disconnected {
self.delegate?.netsocketDisconnected(socket: self, error: err)
}
}
-
+
@MainActor public func write(_ data: Data) {
guard let output = self.output else {
return
}
-
+
self.outputBuffer.append(contentsOf: data)
-
+
if output.hasSpaceAvailable {
self.writeBufferToStream()
}
}
-
+
@MainActor public func write(_ data: [UInt8]) {
guard let output = self.output else {
return
}
-
+
self.outputBuffer.append(contentsOf: data)
-
+
if output.hasSpaceAvailable {
self.writeBufferToStream()
}
}
-
+
@MainActor public func read(count: Int) -> [UInt8] {
guard self.inputBuffer.count > 0, count > 0 else {
return []
}
-
+
let amountToRead = min(count, self.inputBuffer.count)
let dataRead: [UInt8] = Array(self.inputBuffer[0..<amountToRead])
self.inputBuffer.removeFirst(amountToRead)
-
+
return dataRead
}
-
+
@MainActor public func read(count: Int) -> Data {
guard self.inputBuffer.count > 0, count > 0 else {
return Data()
}
-
+
let amountToRead = min(count, self.inputBuffer.count)
-
+
let dataRead: Data = Data(self.inputBuffer[0..<amountToRead])
self.inputBuffer.removeFirst(amountToRead)
-
+
return dataRead
}
-
+
@MainActor public func readAll() -> [UInt8] {
guard self.inputBuffer.count > 0 else {
return []
}
-
+
let dataRead: [UInt8] = Array(self.inputBuffer)
self.inputBuffer = []
-
+
return dataRead
}
-
+
@MainActor public func readAll() -> Data {
guard self.inputBuffer.count > 0 else {
return Data()
}
-
+
let dataRead: Data = Data(self.inputBuffer)
self.inputBuffer = []
-
+
return dataRead
}
-
+
@MainActor private func writeBufferToStream() {
guard let output = self.output, self.outputBuffer.count > 0 else {
return
}
-
+
let bytesWritten = output.write(self.outputBuffer, maxLength: self.outputBuffer.count)
print("NetSocket => \(bytesWritten) bytes")
if bytesWritten > 0 {
self.outputBuffer.removeFirst(bytesWritten)
self.delegate?.netsocketSent(socket: self, count: bytesWritten)
- }
- else if bytesWritten == -1 {
+ } else if bytesWritten == -1 {
self.close(output.streamError)
}
}
-
+
@MainActor private func readStreamToBuffer() {
guard let input = self.input else {
return
}
-
+
let bytesRead = input.read(&self.readBuffer, maxLength: 4 * 1024)
print("NetSocket <= \(bytesRead) bytes")
if bytesRead > 0 {
self.inputBuffer.append(contentsOf: self.readBuffer[0..<bytesRead])
self.delegate?.netsocketReceived(socket: self, bytes: self.inputBuffer)
- }
- else if bytesRead == -1 {
+ } else if bytesRead == -1 {
self.close(input.streamError)
}
}
-
+
// MARK: -
-
+
@MainActor func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
guard let input = self.input, let output = self.output else {
return
}
-
+
switch eventCode {
case .openCompleted:
if aStream == input {
@@ -226,44 +224,49 @@ final class NetSocket: NSObject, StreamDelegate {
print("NetSocket: End encounterd")
self.close()
case .errorOccurred:
- print("NetSocket: Error encounterd", input.streamError.debugDescription, output.streamError.debugDescription)
+ print(
+ "NetSocket: Error encounterd", input.streamError.debugDescription,
+ output.streamError.debugDescription)
let err = input.streamError ?? output.streamError
self.close(err)
default:
break
}
}
-
+
// MARK: -
-
+
private func setupStreamOptions() {
if let input = self.input {
- let socketData: Data = CFReadStreamCopyProperty(input as CFReadStream, CFStreamPropertyKey.socketNativeHandle) as! Data;
- var socketHandle: CFSocketNativeHandle = 0;
- (socketData as NSData).getBytes(&socketHandle, length: MemoryLayout.size(ofValue: socketHandle));
-
- var value: Int = 0;
- let size = UInt32(MemoryLayout.size(ofValue: value));
-
- value = 1;
+ let socketData: Data =
+ CFReadStreamCopyProperty(input as CFReadStream, CFStreamPropertyKey.socketNativeHandle)
+ as! Data
+ var socketHandle: CFSocketNativeHandle = 0
+ (socketData as NSData).getBytes(
+ &socketHandle, length: MemoryLayout.size(ofValue: socketHandle))
+
+ var value: Int = 0
+ let size = UInt32(MemoryLayout.size(ofValue: value))
+
+ value = 1
if setsockopt(socketHandle, IPPROTO_TCP, TCP_NODELAY, &value, size) != 0 {
- print("NetSocket: failed to set TCP_NODELAY");
+ print("NetSocket: failed to set TCP_NODELAY")
}
// Enable keepalive
- value = 1;
+ value = 1
if setsockopt(socketHandle, SOL_SOCKET, SO_KEEPALIVE, &value, size) != 0 {
- print("NetSocket: failed to set SO_KEEPALIVE");
+ print("NetSocket: failed to set SO_KEEPALIVE")
}
-// // Number of keepalives before close (including first keepalive packet)
-// value = 5
-// if setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPCNT, &value, size) != 0 {
-// print("NetSocket: failed to set TCP_KEEPCNT");
-// }
-// // Idle time used when SO_KEEPALIVE is enabled. Sets how long connection must be idle before keepalive is sent.
-// value = 60
-// if setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPALIVE, &value, size) != 0 {
-// print("NetSocket: failed to set TCP_KEEPALIVE")
-// }
+ // // Number of keepalives before close (including first keepalive packet)
+ // value = 5
+ // if setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPCNT, &value, size) != 0 {
+ // print("NetSocket: failed to set TCP_KEEPCNT");
+ // }
+ // // Idle time used when SO_KEEPALIVE is enabled. Sets how long connection must be idle before keepalive is sent.
+ // value = 60
+ // if setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPALIVE, &value, size) != 0 {
+ // print("NetSocket: failed to set TCP_KEEPALIVE")
+ // }
}
}
}
diff --git a/Hotline/Shared/TextView.swift b/Hotline/Shared/TextView.swift
index 47746e2..6361823 100644
--- a/Hotline/Shared/TextView.swift
+++ b/Hotline/Shared/TextView.swift
@@ -1,41 +1,41 @@
import SwiftUI
struct BetterTextEditor: NSViewRepresentable {
-
+
@Environment(\.lineSpacing) private var lineSpacing
-
+
@Binding private var text: String
-
+
private var customizations: [(NSTextView) -> Void] = []
-
+
init(text: Binding<String>) {
self._text = text
}
-
+
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
-
+
func makeNSView(context: Context) -> NSScrollView {
let scrollview = NSTextView.scrollablePlainDocumentContentTextView()
let textview = scrollview.documentView as! NSTextView
-
+
textview.string = self.text
textview.delegate = context.coordinator
-
-// let p = NSMutableParagraphStyle()
-// p.lineSpacing = self.lineSpacing
-//// textview.defaultParagraphStyle = p
-// textview.typingAttributes = [
-// .paragraphStyle: p
-// ]
-
+
+ // let p = NSMutableParagraphStyle()
+ // p.lineSpacing = self.lineSpacing
+ //// textview.defaultParagraphStyle = p
+ // textview.typingAttributes = [
+ // .paragraphStyle: p
+ // ]
+
textview.isEditable = true
textview.isRichText = false
textview.allowsUndo = true
textview.isFieldEditor = false
textview.usesAdaptiveColorMappingForDarkAppearance = true
- textview.drawsBackground = false // true
+ textview.drawsBackground = false // true
textview.usesRuler = false
textview.usesFindBar = false
textview.isIncrementalSearchingEnabled = false
@@ -54,53 +54,53 @@ struct BetterTextEditor: NSViewRepresentable {
textview.isContinuousSpellCheckingEnabled = true
textview.setSelectedRange(NSMakeRange(0, 0))
self.customizations.forEach { $0(textview) }
-
+
scrollview.scrollerStyle = .overlay
-
+
return scrollview
}
-
+
func updateNSView(_ nsView: NSScrollView, context: Context) {
let textview = nsView.documentView as! NSTextView
-
+
if textview.string != text {
textview.string = text
}
-
+
self.customizations.forEach { $0(textview) }
}
-
+
func betterEditorFont(_ font: NSFont) -> Self {
self.customized { $0.font = font }
}
-
+
func betterEditorParagraphStyle(_ paragraphStyle: NSParagraphStyle) -> Self {
self.customized { $0.defaultParagraphStyle = paragraphStyle }
}
-
+
func betterEditorAutomaticDashSubstitution(_ enabled: Bool) -> Self {
self.customized { $0.isAutomaticDashSubstitutionEnabled = enabled }
}
-
+
func betterEditorAutomaticQuoteSubstitution(_ enabled: Bool) -> Self {
self.customized { $0.isAutomaticQuoteSubstitutionEnabled = enabled }
}
-
+
func betterEditorAutomaticSpellingCorrection(_ enabled: Bool) -> Self {
self.customized { $0.isAutomaticSpellingCorrectionEnabled = enabled }
}
-
+
func betterEditorTextInset(_ size: NSSize) -> Self {
self.customized { $0.textContainerInset = size }
}
-
+
class Coordinator: NSObject, NSTextViewDelegate {
var parent: BetterTextEditor
-
+
init(_ parent: BetterTextEditor) {
self.parent = parent
}
-
+
func textDidChange(_ notification: Notification) {
guard let textview = notification.object as? NSTextView else {
return
@@ -110,7 +110,7 @@ struct BetterTextEditor: NSViewRepresentable {
}
}
-private extension BetterTextEditor {
+extension BetterTextEditor {
private func customized(_ customization: @escaping (NSTextView) -> Void) -> Self {
var copy = self
copy.customizations.append(customization)
diff --git a/Hotline/Shared/URLAdditions.swift b/Hotline/Shared/URLAdditions.swift
index 1f25541..5e6a450 100644
--- a/Hotline/Shared/URLAdditions.swift
+++ b/Hotline/Shared/URLAdditions.swift
@@ -5,14 +5,15 @@ extension URL {
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)"
+ 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) {
@@ -20,7 +21,7 @@ extension URL {
filePath = self.appending(component: finalName).path(percentEncoded: false)
counter += 1
}
-
+
return filePath
}
}
diff --git a/Hotline/Shared/VisualEffectView.swift b/Hotline/Shared/VisualEffectView.swift
index e595c55..ec64111 100644
--- a/Hotline/Shared/VisualEffectView.swift
+++ b/Hotline/Shared/VisualEffectView.swift
@@ -1,21 +1,18 @@
import SwiftUI
-struct VisualEffectView: NSViewRepresentable
-{
+struct VisualEffectView: NSViewRepresentable {
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
-
- func makeNSView(context: Context) -> NSVisualEffectView
- {
+
+ func makeNSView(context: Context) -> NSVisualEffectView {
let visualEffectView = NSVisualEffectView()
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
visualEffectView.state = NSVisualEffectView.State.active
return visualEffectView
}
-
- func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context)
- {
+
+ func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context) {
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
}