From 2caf86e633c1a121c8e23d068ac817ed8e80f6a7 Mon Sep 17 00:00:00 2001 From: Dustin Mierau Date: Sat, 8 Nov 2025 19:51:48 -0800 Subject: Moved SoundEffects to Managers. Updated connect form in ServerView. Changed some icons in context menus for bookmarks. --- Hotline.xcodeproj/project.pbxproj | 2 +- Hotline/Library/SoundEffects.swift | 41 ------------------ Hotline/Managers/SoundEffects.swift | 40 +++++++++++++++++ Hotline/macOS/ServerView.swift | 73 +++++++++++++++++--------------- Hotline/macOS/Trackers/TrackerView.swift | 7 ++- 5 files changed, 85 insertions(+), 78 deletions(-) delete mode 100644 Hotline/Library/SoundEffects.swift create mode 100644 Hotline/Managers/SoundEffects.swift diff --git a/Hotline.xcodeproj/project.pbxproj b/Hotline.xcodeproj/project.pbxproj index 3e600a4..f91bcf8 100644 --- a/Hotline.xcodeproj/project.pbxproj +++ b/Hotline.xcodeproj/project.pbxproj @@ -441,7 +441,6 @@ children = ( DAB4D8832B4CABEF0048A05C /* Extensions.swift */, DA5268AA2EB11EA300DCB941 /* ColorArt.swift */, - DAE735062B3251B3000C56F6 /* SoundEffects.swift */, DA55AC782BE6A1AD00034857 /* RegularExpressions.swift */, DA6980822BFFD06C003E434B /* BookmarkDocument.swift */, DA501BE02EBE844F001714F8 /* Views */, @@ -494,6 +493,7 @@ DAC6B2DF2EAC6236004E2CBA /* Managers */ = { isa = PBXGroup; children = ( + DAE735062B3251B3000C56F6 /* SoundEffects.swift */, DAC6B2DE2EAC6236004E2CBA /* ChatStore.swift */, ); path = Managers; diff --git a/Hotline/Library/SoundEffects.swift b/Hotline/Library/SoundEffects.swift deleted file mode 100644 index 4964b94..0000000 --- a/Hotline/Library/SoundEffects.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation -import AppKit - -enum SoundEffect: String { - case loggedIn = "logged-in" - case chatMessage = "chat-message" - case transferComplete = "transfer-complete" - case userLogin = "user-login" - case userLogout = "user-logout" - case newNews = "new-news" - case serverMessage = "server-message" - case error = "error" - - static var all: [SoundEffect] = [.loggedIn, .chatMessage, .transferComplete, .userLogin, .userLogout, .newNews, .serverMessage, .error] -} - -@Observable -class SoundEffects { - static let shared = SoundEffects() - - private var preloadedSounds: [SoundEffect: NSSound] = [:] - - private init() { - // Preload sound effects - for effect in SoundEffect.all { - if let soundFileURL = Bundle.main.url(forResource: effect.rawValue, withExtension: "aiff"), - let sound = NSSound(contentsOf: soundFileURL, byReference: true) { - sound.volume = 0.75 - self.preloadedSounds[effect] = sound - } - } - } - - static func play(_ name: SoundEffect) { - Self.shared.play(name) - } - - func play(_ name: SoundEffect) { - self.preloadedSounds[name]?.play() - } -} diff --git a/Hotline/Managers/SoundEffects.swift b/Hotline/Managers/SoundEffects.swift new file mode 100644 index 0000000..85a1c0e --- /dev/null +++ b/Hotline/Managers/SoundEffects.swift @@ -0,0 +1,40 @@ +import Foundation +import AppKit + +enum SoundEffect: String { + case loggedIn = "logged-in" + case chatMessage = "chat-message" + case transferComplete = "transfer-complete" + case userLogin = "user-login" + case userLogout = "user-logout" + case newNews = "new-news" + case serverMessage = "server-message" + case error = "error" + + static var all: [SoundEffect] = [.loggedIn, .chatMessage, .transferComplete, .userLogin, .userLogout, .newNews, .serverMessage, .error] +} + +class SoundEffects { + static let shared = SoundEffects() + + static func play(_ name: SoundEffect) { + Self.shared.play(name) + } + + private var preloadedSounds: [SoundEffect: NSSound] = [:] + + private init() { + // Preload sound effects + for effect in SoundEffect.all { + if let soundFileURL = Bundle.main.url(forResource: effect.rawValue, withExtension: "aiff"), + let sound = NSSound(contentsOf: soundFileURL, byReference: true) { + sound.volume = 0.75 + self.preloadedSounds[effect] = sound + } + } + } + + func play(_ name: SoundEffect) { + self.preloadedSounds[name]?.play() + } +} diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift index d2c503f..44274ea 100644 --- a/Hotline/macOS/ServerView.swift +++ b/Hotline/macOS/ServerView.swift @@ -121,8 +121,10 @@ struct ServerView: View { self.connectForm Spacer() } -// .frame(maxWidth: .infinity, maxHeight: .infinity) .navigationTitle("Connect to Server") + .onAppear { + self.focusedField = .address + } } else if case .failed(let error) = model.status { VStack { @@ -250,40 +252,47 @@ struct ServerView: View { } var connectForm: some View { - Form { - HStack(alignment: .top, spacing: 10) { - Image("Server Large") - .resizable() - .scaledToFit() - .frame(width: 28, height: 28) + VStack(alignment: .center, spacing: 0) { + Form { + HStack(alignment: .top, spacing: 10) { + Image("Server Large") + .resizable() + .scaledToFit() + .frame(width: 28, height: 28) + + VStack(alignment: .leading) { + Text("Connect to Server") + Text("Enter the address of a Hotline server to connect to.") + .foregroundStyle(.secondary) + .font(.subheadline) + } + } - VStack(alignment: .leading) { - Text("Connect to Server") - Text("Enter the address of a Hotline server to connect to.") - .foregroundStyle(.secondary) - .font(.subheadline) + TextField(text: $connectAddress) { + Text("Address") } + .focused($focusedField, equals: .address) + + TextField(text: $connectLogin, prompt: Text("Optional")) { + Text("Login") + } + .focused($focusedField, equals: .login) + + SecureField(text: $connectPassword, prompt: Text("Optional")) { + Text("Password") + } + .focused($focusedField, equals: .password) } - - TextField(text: $connectAddress) { - Text("Address:") - } - .focused($focusedField, equals: .address) - - TextField(text: $connectLogin, prompt: Text("Optional")) { - Text("Login:") - } - .focused($focusedField, equals: .login) - SecureField(text: $connectPassword, prompt: Text("Optional")) { - Text("Password:") - } - .focused($focusedField, equals: .password) + .formStyle(.grouped) + .fixedSize(horizontal: false, vertical: true) HStack { - Button("Save...") { + Button { if !connectAddress.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { connectNameSheetPresented = true } + } label: { + Image(systemName: "bookmark.fill") } .disabled(connectAddress.isEmpty) .controlSize(.regular) @@ -302,15 +311,12 @@ struct ServerView: View { Button("Connect") { connectToServer() } - .controlSize(.regular) .buttonStyle(.automatic) .keyboardShortcut(.defaultAction) } - .padding(.top, 8) + .padding(.horizontal, 20) } - .formStyle(.grouped) - .fixedSize(horizontal: false, vertical: true) .onChange(of: connectAddress) { let (a, p) = Server.parseServerAddressAndPort(connectAddress) server.address = a @@ -322,14 +328,11 @@ struct ServerView: View { .onChange(of: connectPassword) { server.password = connectPassword } - .onAppear { - focusedField = .address - } .frame(maxWidth: 380) .padding() .sheet(isPresented: $connectNameSheetPresented) { VStack(alignment: .leading) { - Text("Name this server bookmark:") + Text("Save Bookmark") .foregroundStyle(.secondary) .padding(.bottom, 4) TextField("Bookmark Name", text: $connectName) diff --git a/Hotline/macOS/Trackers/TrackerView.swift b/Hotline/macOS/Trackers/TrackerView.swift index dbbacaa..e0ca87d 100644 --- a/Hotline/macOS/Trackers/TrackerView.swift +++ b/Hotline/macOS/Trackers/TrackerView.swift @@ -480,7 +480,12 @@ struct TrackerView: View { Button { Bookmark.delete(bookmark, context: modelContext) } label: { - Label(bookmark.type == .tracker ? "Delete Tracker" : "Delete Bookmark", systemImage: "trash") + if bookmark.type == .tracker { + Label("Delete Tracker", systemImage: "xmark") + } + else { + Label("Delete Bookmark", systemImage: "bookmark.slash") + } } } -- cgit