Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
706aba5d30
commit
da7214a8f9
@ -10,32 +10,25 @@ import Foundation
|
||||
/// Configuration model for sound system loaded from JSON
|
||||
public struct SoundConfiguration: Codable {
|
||||
public let sounds: [Sound]
|
||||
public let categories: [SoundCategory]?
|
||||
public let settings: AudioSettings
|
||||
|
||||
public init(sounds: [Sound], categories: [SoundCategory]? = nil, settings: AudioSettings) {
|
||||
public init(sounds: [Sound], settings: AudioSettings) {
|
||||
self.sounds = sounds
|
||||
self.categories = categories
|
||||
self.settings = settings
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple struct for loading just the sounds array from category JSON files
|
||||
public struct SoundsOnly: Codable {
|
||||
public let sounds: [Sound]
|
||||
|
||||
/// Sound category configuration
|
||||
public struct SoundCategory: Codable, Identifiable {
|
||||
public let id: String
|
||||
public let name: String
|
||||
public let description: String
|
||||
public let bundleName: String? // Optional bundle name for this category
|
||||
|
||||
public init(id: String, name: String, description: String, bundleName: String? = nil) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.bundleName = bundleName
|
||||
public init(sounds: [Sound]) {
|
||||
self.sounds = sounds
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Audio settings configuration
|
||||
public struct AudioSettings: Codable {
|
||||
public let defaultVolume: Float
|
||||
@ -65,27 +58,78 @@ public class SoundConfigurationService {
|
||||
|
||||
private init() {}
|
||||
|
||||
/// Load sound configuration from JSON file
|
||||
public func loadConfiguration(from bundle: Bundle = .main, fileName: String = "sounds") -> SoundConfiguration {
|
||||
guard let url = bundle.url(forResource: fileName, withExtension: "json") else {
|
||||
fatalError("❌ \(fileName).json not found in bundle. Ensure the file exists in your app bundle.")
|
||||
|
||||
/// Load audio settings from SoundsSettings.json
|
||||
private func loadAudioSettings(from bundle: Bundle = .main) -> AudioSettings {
|
||||
guard let url = bundle.url(forResource: "SoundsSettings", withExtension: "json") else {
|
||||
print("⚠️ Warning: SoundsSettings.json not found, using default settings")
|
||||
return AudioSettings(
|
||||
defaultVolume: 0.8,
|
||||
defaultLoopCount: -1,
|
||||
preloadSounds: true,
|
||||
preloadStrategy: "category",
|
||||
audioSessionCategory: "playback",
|
||||
audioSessionMode: "default",
|
||||
audioSessionOptions: ["mixWithOthers"]
|
||||
)
|
||||
}
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: url)
|
||||
let config = try JSONDecoder().decode(SoundConfiguration.self, from: data)
|
||||
self.configuration = config
|
||||
print("✅ Loaded sound configuration with \(config.sounds.count) sounds")
|
||||
return config
|
||||
let settings = try JSONDecoder().decode(AudioSettings.self, from: data)
|
||||
print("✅ Loaded audio settings from SoundsSettings.json")
|
||||
return settings
|
||||
} catch {
|
||||
fatalError("❌ Error loading sound configuration: \(error)")
|
||||
print("⚠️ Warning: Error loading audio settings, using defaults: \(error)")
|
||||
return AudioSettings(
|
||||
defaultVolume: 0.8,
|
||||
defaultLoopCount: -1,
|
||||
preloadSounds: true,
|
||||
preloadStrategy: "category",
|
||||
audioSessionCategory: "playback",
|
||||
audioSessionMode: "default",
|
||||
audioSessionOptions: ["mixWithOthers"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Load sound configuration from multiple category-specific JSON files
|
||||
public func loadConfigurationFromBundles(from bundle: Bundle = .main) -> SoundConfiguration {
|
||||
let bundleNames = ["Colored", "Nature", "Mechanical", "Ambient"]
|
||||
var allSounds: [Sound] = []
|
||||
|
||||
for bundleName in bundleNames {
|
||||
guard let bundleURL = bundle.url(forResource: bundleName, withExtension: "bundle"),
|
||||
let categoryBundle = Bundle(url: bundleURL),
|
||||
let url = categoryBundle.url(forResource: "sounds", withExtension: "json") else {
|
||||
print("⚠️ Warning: Could not find sounds.json in \(bundleName).bundle")
|
||||
continue
|
||||
}
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: url)
|
||||
let soundsOnly = try JSONDecoder().decode(SoundsOnly.self, from: data)
|
||||
allSounds.append(contentsOf: soundsOnly.sounds)
|
||||
|
||||
print("✅ Loaded \(soundsOnly.sounds.count) sounds from \(bundleName).bundle")
|
||||
} catch {
|
||||
print("⚠️ Warning: Error loading sounds from \(bundleName).bundle: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// Load settings from separate file
|
||||
let settings = loadAudioSettings(from: bundle)
|
||||
|
||||
let config = SoundConfiguration(sounds: allSounds, settings: settings)
|
||||
self.configuration = config
|
||||
print("✅ Loaded combined sound configuration with \(allSounds.count) sounds from \(bundleNames.count) bundles")
|
||||
return config
|
||||
}
|
||||
|
||||
/// Get current configuration
|
||||
public func getConfiguration() -> SoundConfiguration {
|
||||
if configuration == nil {
|
||||
return loadConfiguration()
|
||||
return loadConfigurationFromBundles()
|
||||
}
|
||||
return configuration!
|
||||
}
|
||||
@ -101,16 +145,6 @@ public class SoundConfigurationService {
|
||||
.filter { $0.category == categoryId }
|
||||
}
|
||||
|
||||
/// Get sounds by bundle name
|
||||
public func getSoundsByBundle(_ bundleName: String) -> [Sound] {
|
||||
return getConfiguration().sounds
|
||||
.filter { $0.bundleName == bundleName }
|
||||
}
|
||||
|
||||
/// Get available categories
|
||||
public func getAvailableCategories() -> [SoundCategory] {
|
||||
return getConfiguration().categories ?? []
|
||||
}
|
||||
|
||||
/// Get audio settings
|
||||
public func getAudioSettings() -> AudioSettings {
|
||||
|
||||
@ -59,7 +59,7 @@ enum AppConstants {
|
||||
|
||||
// MARK: - System Sounds
|
||||
enum SystemSounds {
|
||||
static let defaultSound = "default"
|
||||
static let defaultSound = "digital-alarm.caf"
|
||||
static let availableSounds = ["default", "bell", "chimes", "ding", "glass", "silence"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ enum NotificationUtils {
|
||||
content.title = title
|
||||
content.body = body
|
||||
|
||||
if soundName == AppConstants.SystemSounds.defaultSound {
|
||||
if soundName == "default" {
|
||||
content.sound = UNNotificationSound.default
|
||||
print("🔔 Using default notification sound")
|
||||
} else {
|
||||
|
||||
@ -41,17 +41,5 @@
|
||||
"category": "alarm",
|
||||
"bundleName": null
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"defaultVolume": 1.0,
|
||||
"defaultLoopCount": -1,
|
||||
"preloadSounds": true,
|
||||
"preloadStrategy": "category",
|
||||
"audioSessionCategory": "playback",
|
||||
"audioSessionMode": "default",
|
||||
"audioSessionOptions": ["mixWithOthers"],
|
||||
"defaultSound": "digital-alarm.caf",
|
||||
"previewDuration": 3.0,
|
||||
"fadeInDuration": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
46
TheNoiseClock/Resources/Ambient.bundle/sounds.json
Normal file
46
TheNoiseClock/Resources/Ambient.bundle/sounds.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"sounds": [
|
||||
{
|
||||
"id": "ambient-pad",
|
||||
"name": "Atmospheric Pad",
|
||||
"fileName": "atmospheric-pad.mp3",
|
||||
"category": "ambient",
|
||||
"description": "Soothing atmospheric drone for meditation or focus",
|
||||
"bundleName": "Ambient",
|
||||
"sourceUrl": "https://pixabay.com/sound-effects/search/ambient%20drone/"
|
||||
},
|
||||
{
|
||||
"id": "calm-pad",
|
||||
"name": "Calm Ambient Pad",
|
||||
"fileName": "calm-ambient-pad.mp3",
|
||||
"category": "ambient",
|
||||
"description": "Soft, warm ambient pad for deep relaxation",
|
||||
"bundleName": "Ambient",
|
||||
"sourceUrl": "https://pixabay.com/sound-effects/search/ambient%20pad/"
|
||||
},
|
||||
{
|
||||
"id": "dark-ambient",
|
||||
"name": "Dark Ambient Atmosphere",
|
||||
"fileName": "dark-ambient.mp3",
|
||||
"category": "ambient",
|
||||
"description": "A moody, atmospheric soundscape with deep tones, ideal for introspection or creative focus.",
|
||||
"bundleName": "Ambient"
|
||||
},
|
||||
{
|
||||
"id": "ethereal-ambient",
|
||||
"name": "Ethereal Ambient Soundscape",
|
||||
"fileName": "ethereal-ambient.mp3",
|
||||
"category": "ambient",
|
||||
"description": "A dreamy, ethereal sound with delicate tones, perfect for relaxation or spiritual practices.",
|
||||
"bundleName": "Ambient"
|
||||
},
|
||||
{
|
||||
"id": "ambient-waves",
|
||||
"name": "Ambient Waves",
|
||||
"fileName": "ambient-waves.mp3",
|
||||
"category": "ambient",
|
||||
"description": "A smooth, wave-like ambient sound, evoking a sense of calm flow. Ideal for meditation or focus.",
|
||||
"bundleName": "Ambient"
|
||||
}
|
||||
]
|
||||
}
|
||||
45
TheNoiseClock/Resources/Colored.bundle/sounds.json
Normal file
45
TheNoiseClock/Resources/Colored.bundle/sounds.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"sounds": [
|
||||
{
|
||||
"id": "white-noise",
|
||||
"name": "White Noise",
|
||||
"fileName": "white-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Classic white noise with equal energy across frequencies for focus and relaxation",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "pink-noise",
|
||||
"name": "Pink Noise",
|
||||
"fileName": "pink-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Soft, warm noise resembling steady rain, ideal for relaxation",
|
||||
"bundleName": "Colored",
|
||||
"sourceUrl": "https://freesound.org/search/?q=pink+noise+loop"
|
||||
},
|
||||
{
|
||||
"id": "brown-noise",
|
||||
"name": "Brown Noise",
|
||||
"fileName": "brown-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Deep, rumbling noise like distant thunder, great for deep sleep",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "green-noise",
|
||||
"name": "Green Noise",
|
||||
"fileName": "green-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Mid-range noise resembling rustling leaves, soothing and nature-like",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "grey-noise",
|
||||
"name": "Grey Noise",
|
||||
"fileName": "grey-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Balanced noise adjusted for human hearing, perfect for calm focus",
|
||||
"bundleName": "Colored"
|
||||
}
|
||||
]
|
||||
}
|
||||
44
TheNoiseClock/Resources/Mechanical.bundle/sounds.json
Normal file
44
TheNoiseClock/Resources/Mechanical.bundle/sounds.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"sounds": [
|
||||
{
|
||||
"id": "fan-noise",
|
||||
"name": "Fan Heater",
|
||||
"fileName": "fan-heater.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "Fan and heater sounds for consistent background noise",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "air-conditioner",
|
||||
"name": "Air Conditioner Hum",
|
||||
"fileName": "air-conditioner-hum.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "Steady hum of an air conditioner for focus or sleep",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "clock-ticking",
|
||||
"name": "Clock Ticking Mechanism",
|
||||
"fileName": "clock-ticking.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "The rhythmic ticking of a clock, providing a consistent, hypnotic sound for focus or relaxation.",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "electric-fan",
|
||||
"name": "Electric Fan Whirring",
|
||||
"fileName": "electric-fan.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "The steady whir of an electric fan, creating a monotonous sound for sleep or concentration.",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "engine-idling",
|
||||
"name": "Engine Idling",
|
||||
"fileName": "engine-idling.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "A low, steady engine idle, offering a deep hum for background noise or relaxation.",
|
||||
"bundleName": "Mechanical"
|
||||
}
|
||||
]
|
||||
}
|
||||
44
TheNoiseClock/Resources/Nature.bundle/sounds.json
Normal file
44
TheNoiseClock/Resources/Nature.bundle/sounds.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"sounds": [
|
||||
{
|
||||
"id": "heavy-rain",
|
||||
"name": "Heavy Rain",
|
||||
"fileName": "heavy-rain.mp3",
|
||||
"category": "nature",
|
||||
"description": "Heavy rainfall sounds for peaceful sleep",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "ocean-waves",
|
||||
"name": "Ocean Waves",
|
||||
"fileName": "ocean-waves.mp3",
|
||||
"category": "nature",
|
||||
"description": "Gentle waves crashing on the shore for relaxation",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "forest-ambience",
|
||||
"name": "Forest Ambience",
|
||||
"fileName": "forest-ambience.mp3",
|
||||
"category": "nature",
|
||||
"description": "Calm forest sounds with birds and wind for nature lovers",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "crickets-night",
|
||||
"name": "Crickets at Night",
|
||||
"fileName": "crickets-night.mp3",
|
||||
"category": "nature",
|
||||
"description": "The rhythmic chirping of crickets under a night sky, perfect for calming sleep.",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "distant-thunderstorm",
|
||||
"name": "Distant Thunderstorm",
|
||||
"fileName": "distant-thunderstorm.mp3",
|
||||
"category": "nature",
|
||||
"description": "Soft thunder and rain in the distance, creating a soothing, stormy ambiance.",
|
||||
"bundleName": "Nature"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
TheNoiseClock/Resources/SoundsSettings.json
Normal file
9
TheNoiseClock/Resources/SoundsSettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"defaultVolume": 0.8,
|
||||
"defaultLoopCount": -1,
|
||||
"preloadSounds": true,
|
||||
"preloadStrategy": "category",
|
||||
"audioSessionCategory": "playback",
|
||||
"audioSessionMode": "default",
|
||||
"audioSessionOptions": ["mixWithOthers"]
|
||||
}
|
||||
@ -1,176 +0,0 @@
|
||||
{
|
||||
"sounds": [
|
||||
{
|
||||
"id": "white-noise",
|
||||
"name": "White Noise",
|
||||
"fileName": "white-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Classic white noise with equal energy across frequencies for focus and relaxation",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "pink-noise",
|
||||
"name": "Pink Noise",
|
||||
"fileName": "pink-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Soft, warm noise resembling steady rain, ideal for relaxation",
|
||||
"bundleName": "Colored",
|
||||
"sourceUrl": "https://freesound.org/search/?q=pink+noise+loop"
|
||||
},
|
||||
{
|
||||
"id": "brown-noise",
|
||||
"name": "Brown Noise",
|
||||
"fileName": "brown-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Deep, rumbling noise like distant thunder, great for deep sleep",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "green-noise",
|
||||
"name": "Green Noise",
|
||||
"fileName": "green-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Mid-range noise resembling rustling leaves, soothing and nature-like",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "grey-noise",
|
||||
"name": "Grey Noise",
|
||||
"fileName": "grey-noise.mp3",
|
||||
"category": "colored",
|
||||
"description": "Balanced noise adjusted for human hearing, perfect for calm focus",
|
||||
"bundleName": "Colored"
|
||||
},
|
||||
{
|
||||
"id": "heavy-rain",
|
||||
"name": "Heavy Rain",
|
||||
"fileName": "heavy-rain.mp3",
|
||||
"category": "nature",
|
||||
"description": "Heavy rainfall sounds for peaceful sleep",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "ocean-waves",
|
||||
"name": "Ocean Waves",
|
||||
"fileName": "ocean-waves.mp3",
|
||||
"category": "nature",
|
||||
"description": "Gentle waves crashing on the shore for relaxation",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "forest-ambience",
|
||||
"name": "Forest Ambience",
|
||||
"fileName": "forest-ambience.mp3",
|
||||
"category": "nature",
|
||||
"description": "Calm forest sounds with birds and wind for nature lovers",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "fan-noise",
|
||||
"name": "Fan Heater",
|
||||
"fileName": "fan-heater.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "Fan and heater sounds for consistent background noise",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "air-conditioner",
|
||||
"name": "Air Conditioner Hum",
|
||||
"fileName": "air-conditioner-hum.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "Steady hum of an air conditioner for focus or sleep",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "ambient-pad",
|
||||
"name": "Atmospheric Pad",
|
||||
"fileName": "atmospheric-pad.mp3",
|
||||
"category": "ambient",
|
||||
"description": "Soothing atmospheric drone for meditation or focus",
|
||||
"bundleName": "Ambient",
|
||||
"sourceUrl": "https://pixabay.com/sound-effects/search/ambient%20drone/"
|
||||
},
|
||||
{
|
||||
"id": "calm-pad",
|
||||
"name": "Calm Ambient Pad",
|
||||
"fileName": "calm-ambient-pad.mp3",
|
||||
"category": "ambient",
|
||||
"description": "Soft, warm ambient pad for deep relaxation",
|
||||
"bundleName": "Ambient",
|
||||
"sourceUrl": "https://pixabay.com/sound-effects/search/ambient%20pad/"
|
||||
},
|
||||
{
|
||||
"id": "dark-ambient",
|
||||
"name": "Dark Ambient Atmosphere",
|
||||
"fileName": "dark-ambient.mp3",
|
||||
"category": "ambient",
|
||||
"description": "A moody, atmospheric soundscape with deep tones, ideal for introspection or creative focus.",
|
||||
"bundleName": "Ambient"
|
||||
},
|
||||
{
|
||||
"id": "ethereal-ambient",
|
||||
"name": "Ethereal Ambient Soundscape",
|
||||
"fileName": "ethereal-ambient.mp3",
|
||||
"category": "ambient",
|
||||
"description": "A dreamy, ethereal sound with delicate tones, perfect for relaxation or spiritual practices.",
|
||||
"bundleName": "Ambient"
|
||||
},
|
||||
{
|
||||
"id": "ambient-waves",
|
||||
"name": "Ambient Waves",
|
||||
"fileName": "ambient-waves.mp3",
|
||||
"category": "ambient",
|
||||
"description": "A smooth, wave-like ambient sound, evoking a sense of calm flow. Ideal for meditation or focus.",
|
||||
"bundleName": "Ambient"
|
||||
},
|
||||
{
|
||||
"id": "clock-ticking",
|
||||
"name": "Clock Ticking Mechanism",
|
||||
"fileName": "clock-ticking.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "The rhythmic ticking of a clock, providing a consistent, hypnotic sound for focus or relaxation.",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "electric-fan",
|
||||
"name": "Electric Fan Whirring",
|
||||
"fileName": "electric-fan.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "The steady whir of an electric fan, creating a monotonous sound for sleep or concentration.",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "engine-idling",
|
||||
"name": "Engine Idling",
|
||||
"fileName": "engine-idling.mp3",
|
||||
"category": "mechanical",
|
||||
"description": "A low, steady engine idle, offering a deep hum for background noise or relaxation.",
|
||||
"bundleName": "Mechanical"
|
||||
},
|
||||
{
|
||||
"id": "crickets-night",
|
||||
"name": "Crickets at Night",
|
||||
"fileName": "crickets-night.mp3",
|
||||
"category": "nature",
|
||||
"description": "The rhythmic chirping of crickets under a night sky, perfect for calming sleep.",
|
||||
"bundleName": "Nature"
|
||||
},
|
||||
{
|
||||
"id": "distant-thunderstorm",
|
||||
"name": "Distant Thunderstorm",
|
||||
"fileName": "distant-thunderstorm.mp3",
|
||||
"category": "nature",
|
||||
"description": "Soft thunder and rain in the distance, creating a soothing, stormy ambiance.",
|
||||
"bundleName": "Nature"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"defaultVolume": 0.8,
|
||||
"defaultLoopCount": -1,
|
||||
"preloadSounds": true,
|
||||
"preloadStrategy": "category",
|
||||
"audioSessionCategory": "playback",
|
||||
"audioSessionMode": "default",
|
||||
"audioSessionOptions": ["mixWithOthers"]
|
||||
}
|
||||
}
|
||||
@ -18,21 +18,61 @@ class AlarmSoundService {
|
||||
|
||||
private init() {}
|
||||
|
||||
/// Load alarm sound configuration from alarm-sounds.json
|
||||
/// Load alarm sound configuration from AlarmSounds.bundle
|
||||
private func loadAlarmConfiguration() -> SoundConfiguration {
|
||||
guard let url = Bundle.main.url(forResource: "alarm-sounds", withExtension: "json") else {
|
||||
fatalError("❌ alarm-sounds.json not found in bundle. Ensure the file exists in your app bundle.")
|
||||
guard let bundleURL = Bundle.main.url(forResource: "AlarmSounds", withExtension: "bundle"),
|
||||
let alarmBundle = Bundle(url: bundleURL),
|
||||
let url = alarmBundle.url(forResource: "sounds", withExtension: "json") else {
|
||||
fatalError("❌ sounds.json not found in AlarmSounds.bundle. Ensure the bundle and file exist.")
|
||||
}
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: url)
|
||||
let config = try JSONDecoder().decode(SoundConfiguration.self, from: data)
|
||||
return config
|
||||
let soundsOnly = try JSONDecoder().decode(SoundsOnly.self, from: data)
|
||||
|
||||
// Load settings from separate SoundsSettings.json file
|
||||
let settings = loadAudioSettings()
|
||||
|
||||
return SoundConfiguration(sounds: soundsOnly.sounds, settings: settings)
|
||||
} catch {
|
||||
fatalError("❌ Error loading alarm sound configuration: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
/// Load audio settings from SoundsSettings.json
|
||||
private func loadAudioSettings() -> AudioSettings {
|
||||
guard let url = Bundle.main.url(forResource: "SoundsSettings", withExtension: "json") else {
|
||||
print("⚠️ Warning: SoundsSettings.json not found, using default alarm settings")
|
||||
return AudioSettings(
|
||||
defaultVolume: 1.0,
|
||||
defaultLoopCount: -1,
|
||||
preloadSounds: true,
|
||||
preloadStrategy: "category",
|
||||
audioSessionCategory: "playback",
|
||||
audioSessionMode: "default",
|
||||
audioSessionOptions: ["mixWithOthers"]
|
||||
)
|
||||
}
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: url)
|
||||
let settings = try JSONDecoder().decode(AudioSettings.self, from: data)
|
||||
print("✅ Loaded audio settings for alarms from SoundsSettings.json")
|
||||
return settings
|
||||
} catch {
|
||||
print("⚠️ Warning: Error loading audio settings for alarms, using defaults: \(error)")
|
||||
return AudioSettings(
|
||||
defaultVolume: 1.0,
|
||||
defaultLoopCount: -1,
|
||||
preloadSounds: true,
|
||||
preloadStrategy: "category",
|
||||
audioSessionCategory: "playback",
|
||||
audioSessionMode: "default",
|
||||
audioSessionOptions: ["mixWithOthers"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all available alarm sounds
|
||||
func getAlarmSounds() -> [Sound] {
|
||||
return loadAlarmConfiguration().sounds
|
||||
|
||||
@ -101,7 +101,7 @@ class FocusModeService {
|
||||
content.title = title
|
||||
content.body = body
|
||||
// Use the sound name directly since sounds.json now references CAF files
|
||||
if soundName == AppConstants.SystemSounds.defaultSound {
|
||||
if soundName == "default" {
|
||||
content.sound = UNNotificationSound.default
|
||||
print("🔔 Using default notification sound")
|
||||
} else {
|
||||
|
||||
@ -16,7 +16,7 @@ struct AddAlarmView: View {
|
||||
@Binding var isPresented: Bool
|
||||
|
||||
@State private var newAlarmTime = Calendar.current.date(bySettingHour: 6, minute: 0, second: 0, of: Date()) ?? Date()
|
||||
@State private var selectedSoundName = "digital-alarm.mp3"
|
||||
@State private var selectedSoundName = "digital-alarm.caf"
|
||||
@State private var alarmLabel = "Alarm"
|
||||
@State private var notificationMessage = "Your alarm is ringing"
|
||||
@State private var snoozeDuration = 9 // minutes
|
||||
|
||||
@ -27,7 +27,7 @@ struct AlarmRowView: View {
|
||||
.font(.subheadline)
|
||||
.foregroundColor(UIConstants.Colors.secondaryText)
|
||||
|
||||
Text("• \(alarm.soundName)")
|
||||
Text("• \(AlarmSoundService.shared.getSoundDisplayName(alarm.soundName))")
|
||||
.font(.caption)
|
||||
.foregroundColor(UIConstants.Colors.secondaryText)
|
||||
}
|
||||
|
||||
@ -126,6 +126,7 @@ struct SoundCategoryView: View {
|
||||
isPlaying: viewModel.isPlaying && selectedSound?.id == sound.id,
|
||||
isPreviewing: viewModel.isPreviewing && viewModel.previewSound?.id == sound.id,
|
||||
onSelect: {
|
||||
viewModel.selectSound(sound)
|
||||
selectedSound = sound
|
||||
},
|
||||
onPreview: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user