Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions freewrite/AudioManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import AVFoundation

struct KeySound {
let startTime: Double
let duration: Double
}

class AudioManager {
static let shared = AudioManager()
private var soundData: Data?
private var keySoundMap: [String: KeySound] = [:]
private(set) var isEnabled: Bool = false

private init() {
setupKeyboardSound()
loadKeyDefinitions()
}

private func setupKeyboardSound() {
if let soundURL = Bundle.main.url(forResource: "crystal_purple", withExtension: "mp3") {
loadSound(from: soundURL)
}
}

private func loadSound(from url: URL) -> Void {
do {
soundData = try Data(contentsOf: url)
} catch {}
}

private func loadKeyDefinitions() {
if let configURL = Bundle.main.url(forResource: "crystal_purple_config", withExtension: "json") {
loadConfig(from: configURL)
}
}

private func loadConfig(from url: URL) {
do {
let data = try Data(contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]

if let defines = json?["defines"] as? [String: [Double]] {
for (key, value) in defines {
if value.count == 2 {
let startTime = value[0] / 1000.0
let duration = value[1] / 1000.0
keySoundMap[key] = KeySound(startTime: startTime, duration: duration)
}
}
}
} catch {}
}

func toggleSound() {
isEnabled.toggle()
}

func playKeyboardSound(forKey key: String = "1") {
guard isEnabled,
let soundData = soundData,
let player = try? AVAudioPlayer(data: soundData) else {
return
}

let keySound = keySoundMap[key] ?? keySoundMap["1"]
if let soundInfo = keySound {
player.enableRate = true
player.volume = 0.5
player.currentTime = soundInfo.startTime
player.play()

DispatchQueue.main.asyncAfter(deadline: .now() + soundInfo.duration) {
player.stop()
}
}
}
}
38 changes: 37 additions & 1 deletion freewrite/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ struct ContentView: View {
@State private var isHoveringHistoryText = false
@State private var isHoveringHistoryPath = false
@State private var isHoveringHistoryArrow = false
@State private var isHoveringSound = false
@State private var isSoundEnabled = false
@State private var colorScheme: ColorScheme = .light // Add state for color scheme
@State private var isHoveringThemeToggle = false // Add state for theme toggle hover
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
Expand Down Expand Up @@ -396,6 +398,18 @@ struct ContentView: View {
TextEditor(text: Binding(
get: { text },
set: { newValue in
// Play keyboard sound when text changes
if newValue.count != text.count {
// Get the key that was pressed
if let event = NSApp.currentEvent, event.type == .keyDown {
let keyCode = String(event.keyCode)
AudioManager.shared.playKeyboardSound(forKey: keyCode)
} else {
// Fallback to default sound if we can't determine the key
AudioManager.shared.playKeyboardSound()
}
}

// Ensure the text always starts with two newlines
if !newValue.hasPrefix("\n\n") {
text = "\n\n" + newValue.trimmingCharacters(in: .newlines)
Expand Down Expand Up @@ -563,6 +577,28 @@ struct ContentView: View {

// Utility buttons (moved to right)
HStack(spacing: 8) {
Button(action: {
AudioManager.shared.toggleSound()
isSoundEnabled.toggle() // Update state immediately
}) {
Image(systemName: isSoundEnabled ? "speaker.wave.2.fill" : "speaker.slash.fill")
.frame(width: 20, height: 16) // Fixed frame size for both icons
}
.buttonStyle(.plain)
.foregroundColor(isHoveringSound ? .black : .gray)
.onHover { hovering in
isHoveringSound = hovering
isHoveringBottomNav = hovering
if hovering {
NSCursor.pointingHand.push()
} else {
NSCursor.pop()
}
}

Text("•")
.foregroundColor(.gray)

Button(timerButtonTitle) {
let now = Date()
if let lastClick = lastClickTime,
Expand Down Expand Up @@ -1305,4 +1341,4 @@ extension NSView {

#Preview {
ContentView()
}
}
Binary file added freewrite/Sounds/crystal_purple.mp3
Binary file not shown.
Loading