native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #58 from supabitapp/sunny-beaver

Add notification sound setting

authored by

khoi and committed by
GitHub
caee9f39 87beac0f

+52 -7
+14
supacode/Features/App/Reducer/AppFeature.swift
··· 1 + import AppKit 1 2 import ComposableArchitecture 2 3 import SwiftUI 4 + 5 + private let notificationSound: NSSound? = { 6 + guard let url = Bundle.main.url(forResource: "notification", withExtension: "wav") else { 7 + return nil 8 + } 9 + return NSSound(contentsOf: url, byReference: true) 10 + }() 3 11 4 12 @Reducer 5 13 struct AppFeature { ··· 191 199 192 200 case .updates: 193 201 return .none 202 + 203 + case .terminalEvent(.notificationReceived): 204 + guard state.settings.notificationSoundEnabled else { return .none } 205 + return .run { _ in 206 + await MainActor.run { _ = notificationSound?.play() } 207 + } 194 208 195 209 case .terminalEvent: 196 210 return .none
+12 -3
supacode/Features/Settings/Models/GlobalSettings.swift
··· 3 3 var updatesAutomaticallyCheckForUpdates: Bool 4 4 var updatesAutomaticallyDownloadUpdates: Bool 5 5 var inAppNotificationsEnabled: Bool 6 + var notificationSoundEnabled: Bool 6 7 7 8 static let `default` = GlobalSettings( 8 9 appearanceMode: .system, 9 10 updatesAutomaticallyCheckForUpdates: true, 10 11 updatesAutomaticallyDownloadUpdates: false, 11 - inAppNotificationsEnabled: true 12 + inAppNotificationsEnabled: true, 13 + notificationSoundEnabled: true 12 14 ) 13 15 14 16 init( 15 17 appearanceMode: AppearanceMode, 16 18 updatesAutomaticallyCheckForUpdates: Bool, 17 19 updatesAutomaticallyDownloadUpdates: Bool, 18 - inAppNotificationsEnabled: Bool 20 + inAppNotificationsEnabled: Bool, 21 + notificationSoundEnabled: Bool 19 22 ) { 20 23 self.appearanceMode = appearanceMode 21 24 self.updatesAutomaticallyCheckForUpdates = updatesAutomaticallyCheckForUpdates 22 25 self.updatesAutomaticallyDownloadUpdates = updatesAutomaticallyDownloadUpdates 23 26 self.inAppNotificationsEnabled = inAppNotificationsEnabled 27 + self.notificationSoundEnabled = notificationSoundEnabled 24 28 } 25 29 26 30 init(from decoder: any Decoder) throws { ··· 28 32 appearanceMode = try container.decode(AppearanceMode.self, forKey: .appearanceMode) 29 33 updatesAutomaticallyCheckForUpdates = try container.decode(Bool.self, forKey: .updatesAutomaticallyCheckForUpdates) 30 34 updatesAutomaticallyDownloadUpdates = try container.decode(Bool.self, forKey: .updatesAutomaticallyDownloadUpdates) 31 - inAppNotificationsEnabled = try container.decodeIfPresent(Bool.self, forKey: .inAppNotificationsEnabled) ?? Self.default.inAppNotificationsEnabled 35 + inAppNotificationsEnabled = 36 + try container.decodeIfPresent(Bool.self, forKey: .inAppNotificationsEnabled) 37 + ?? Self.default.inAppNotificationsEnabled 38 + notificationSoundEnabled = 39 + try container.decodeIfPresent(Bool.self, forKey: .notificationSoundEnabled) 40 + ?? Self.default.notificationSoundEnabled 32 41 } 33 42 }
+11 -1
supacode/Features/Settings/Reducer/SettingsFeature.swift
··· 9 9 var updatesAutomaticallyCheckForUpdates: Bool 10 10 var updatesAutomaticallyDownloadUpdates: Bool 11 11 var inAppNotificationsEnabled: Bool 12 + var notificationSoundEnabled: Bool 12 13 13 14 init(settings: GlobalSettings = .default) { 14 15 appearanceMode = settings.appearanceMode 15 16 updatesAutomaticallyCheckForUpdates = settings.updatesAutomaticallyCheckForUpdates 16 17 updatesAutomaticallyDownloadUpdates = settings.updatesAutomaticallyDownloadUpdates 17 18 inAppNotificationsEnabled = settings.inAppNotificationsEnabled 19 + notificationSoundEnabled = settings.notificationSoundEnabled 18 20 } 19 21 20 22 var globalSettings: GlobalSettings { ··· 22 24 appearanceMode: appearanceMode, 23 25 updatesAutomaticallyCheckForUpdates: updatesAutomaticallyCheckForUpdates, 24 26 updatesAutomaticallyDownloadUpdates: updatesAutomaticallyDownloadUpdates, 25 - inAppNotificationsEnabled: inAppNotificationsEnabled 27 + inAppNotificationsEnabled: inAppNotificationsEnabled, 28 + notificationSoundEnabled: notificationSoundEnabled 26 29 ) 27 30 } 28 31 } ··· 33 36 case setUpdatesAutomaticallyCheckForUpdates(Bool) 34 37 case setUpdatesAutomaticallyDownloadUpdates(Bool) 35 38 case setInAppNotificationsEnabled(Bool) 39 + case setNotificationSoundEnabled(Bool) 36 40 case delegate(Delegate) 37 41 } 38 42 ··· 70 74 71 75 case .setInAppNotificationsEnabled(let value): 72 76 state.inAppNotificationsEnabled = value 77 + let settings = state.globalSettings 78 + settingsClient.save(settings) 79 + return .send(.delegate(.settingsChanged(settings))) 80 + 81 + case .setNotificationSoundEnabled(let value): 82 + state.notificationSoundEnabled = value 73 83 let settings = state.globalSettings 74 84 settingsClient.save(settings) 75 85 return .send(.delegate(.settingsChanged(settings)))
+8
supacode/Features/Settings/Views/NotificationsSettingsView.swift
··· 16 16 ) 17 17 ) 18 18 .help("Show bell icon next to worktree (no shortcut)") 19 + Toggle( 20 + "Play notification sound", 21 + isOn: Binding( 22 + get: { store.notificationSoundEnabled }, 23 + set: { store.send(.setNotificationSoundEnabled($0)) } 24 + ) 25 + ) 26 + .help("Play a sound when a notification is received (no shortcut)") 19 27 } 20 28 } 21 29 .formStyle(.grouped)
supacode/notification.wav

This is a binary file and will not be displayed.

+7 -3
supacodeTests/SettingsFeatureTests.swift
··· 10 10 appearanceMode: .dark, 11 11 updatesAutomaticallyCheckForUpdates: false, 12 12 updatesAutomaticallyDownloadUpdates: true, 13 - inAppNotificationsEnabled: false 13 + inAppNotificationsEnabled: false, 14 + notificationSoundEnabled: true 14 15 ) 15 16 let store = TestStore(initialState: SettingsFeature.State()) { 16 17 SettingsFeature() ··· 23 24 $0.updatesAutomaticallyCheckForUpdates = false 24 25 $0.updatesAutomaticallyDownloadUpdates = true 25 26 $0.inAppNotificationsEnabled = false 27 + $0.notificationSoundEnabled = true 26 28 } 27 29 await store.receive(.delegate(.settingsChanged(loaded))) 28 30 } ··· 44 46 appearanceMode: .dark, 45 47 updatesAutomaticallyCheckForUpdates: true, 46 48 updatesAutomaticallyDownloadUpdates: false, 47 - inAppNotificationsEnabled: true 49 + inAppNotificationsEnabled: true, 50 + notificationSoundEnabled: true 48 51 )))) 49 52 50 53 #expect(saved.value == GlobalSettings( 51 54 appearanceMode: .dark, 52 55 updatesAutomaticallyCheckForUpdates: true, 53 56 updatesAutomaticallyDownloadUpdates: false, 54 - inAppNotificationsEnabled: true 57 + inAppNotificationsEnabled: true, 58 + notificationSoundEnabled: true 55 59 )) 56 60 } 57 61 }