@@ -65,6 +65,8 @@ data class FakeCallUiState(
6565 val quickTriggerCallerName : String = " " ,
6666 val quickTriggerCallerNumber : String = " " ,
6767 val quickTriggerDelaySeconds : Int = QuickTriggerManager .DEFAULT_DELAY_SECONDS ,
68+ val quickTriggerPresetName : String = " " ,
69+ val quickTriggerPresets : List <QuickTriggerPreset > = emptyList(),
6870 val startupUpdate : ReleaseInfo ? = null
6971)
7072
@@ -75,6 +77,7 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
7577 private val ivrStore = IvrConfigStore ()
7678 private val updateChecker = UpdateChecker ()
7779 private val quickTriggerDefaults = QuickTriggerManager .loadDefaults(application)
80+ private val quickTriggerPresets = QuickTriggerManager .loadPresets(application)
7881
7982 private val _uiState = MutableStateFlow (
8083 FakeCallUiState (
@@ -101,7 +104,9 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
101104 recordingsFolderName = prefs.getString(KEY_RECORDINGS_FOLDER_NAME , " Downloads/FakeCall" ).orEmpty(),
102105 quickTriggerCallerName = quickTriggerDefaults.callerName,
103106 quickTriggerCallerNumber = quickTriggerDefaults.callerNumber,
104- quickTriggerDelaySeconds = quickTriggerDefaults.delaySeconds
107+ quickTriggerDelaySeconds = quickTriggerDefaults.delaySeconds,
108+ quickTriggerPresetName = prefs.getString(KEY_QUICK_TRIGGER_PRESET_NAME , " " ).orEmpty(),
109+ quickTriggerPresets = quickTriggerPresets
105110 )
106111 )
107112 val uiState: StateFlow <FakeCallUiState > = _uiState .asStateFlow()
@@ -122,6 +127,8 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
122127 viewModelScope.launch {
123128 checkForUpdatesOnStartup()
124129 }
130+
131+ QuickTriggerManager .updateLauncherShortcuts(application)
125132 }
126133
127134 suspend fun checkForUpdatesManual (): UpdateCheckResult {
@@ -163,6 +170,56 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
163170 saveQuickTriggerDefaults(uiState.value.copy(quickTriggerDelaySeconds = delaySeconds))
164171 }
165172
173+ fun onQuickTriggerPresetNameChange (value : String ) {
174+ prefs.edit().putString(KEY_QUICK_TRIGGER_PRESET_NAME , value).apply ()
175+ _uiState .update { it.copy(quickTriggerPresetName = value) }
176+ }
177+
178+ fun saveQuickTriggerPreset () {
179+ val customName = uiState.value.quickTriggerPresetName.trim()
180+ val result = QuickTriggerManager .saveCurrentDefaultsAsPreset(
181+ context = getApplication(),
182+ customTitle = customName
183+ )
184+ val status = when (result) {
185+ QuickTriggerPresetSaveResult .SAVED -> " Quick trigger preset saved."
186+ QuickTriggerPresetSaveResult .LIMIT_REACHED -> " You can only save up to 5 quick trigger presets."
187+ QuickTriggerPresetSaveResult .INVALID_DATA -> " Enter a caller number before saving a preset."
188+ }
189+ refreshQuickTriggerPresets(status)
190+ if (result == QuickTriggerPresetSaveResult .SAVED ) {
191+ prefs.edit().putString(KEY_QUICK_TRIGGER_PRESET_NAME , " " ).apply ()
192+ _uiState .update { it.copy(quickTriggerPresetName = " " ) }
193+ }
194+ }
195+
196+ fun applyQuickTriggerPreset (slot : Int ) {
197+ val applied = QuickTriggerManager .applyPresetToDefaults(getApplication(), slot)
198+ if (! applied) {
199+ _uiState .update { it.copy(statusMessage = " Preset not found." ) }
200+ return
201+ }
202+ val defaults = QuickTriggerManager .loadDefaults(getApplication())
203+ _uiState .update {
204+ it.copy(
205+ quickTriggerCallerName = defaults.callerName,
206+ quickTriggerCallerNumber = defaults.callerNumber,
207+ quickTriggerDelaySeconds = defaults.delaySeconds,
208+ statusMessage = " Preset applied to quick trigger defaults."
209+ )
210+ }
211+ }
212+
213+ fun removeQuickTriggerPreset (slot : Int ) {
214+ val removed = QuickTriggerManager .removePreset(getApplication(), slot)
215+ val status = if (removed) {
216+ " Quick trigger preset removed."
217+ } else {
218+ " Preset not found."
219+ }
220+ refreshQuickTriggerPresets(status)
221+ }
222+
166223 fun onCallerNameChange (value : String ) {
167224 _uiState .update { it.copy(callerName = value) }
168225 }
@@ -603,6 +660,7 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
603660 }
604661
605662 prefs.edit().remove(KEY_TIMER_ENDS_AT ).apply ()
663+ prefs.edit().putInt(KEY_ACTIVE_PRESET_SLOT , - 1 ).apply ()
606664 _uiState .update {
607665 it.copy(
608666 isTimerRunning = false ,
@@ -614,6 +672,7 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
614672 }
615673 )
616674 }
675+ QuickTriggerManager .refreshQuickSettingsTiles(getApplication())
617676 return
618677 }
619678
@@ -633,26 +692,34 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
633692 return
634693 }
635694
636- prefs.edit().putLong(KEY_TIMER_ENDS_AT , triggerAtMillis).apply ()
695+ prefs.edit()
696+ .putLong(KEY_TIMER_ENDS_AT , triggerAtMillis)
697+ .putInt(KEY_ACTIVE_PRESET_SLOT , - 1 )
698+ .apply ()
637699 _uiState .update {
638700 it.copy(
639701 isTimerRunning = true ,
640702 timerEndsAtMillis = triggerAtMillis,
641703 statusMessage = buildScheduleStatus(state.scheduleKind, selectedDelaySeconds, triggerAtMillis)
642704 )
643705 }
706+ QuickTriggerManager .refreshQuickSettingsTiles(getApplication())
644707 }
645708
646709 private fun cancelTimer () {
647710 FakeCallAlarmScheduler .cancel(getApplication())
648- prefs.edit().remove(KEY_TIMER_ENDS_AT ).apply ()
711+ prefs.edit()
712+ .remove(KEY_TIMER_ENDS_AT )
713+ .putInt(KEY_ACTIVE_PRESET_SLOT , - 1 )
714+ .apply ()
649715 _uiState .update {
650716 it.copy(
651717 isTimerRunning = false ,
652718 timerEndsAtMillis = 0L ,
653719 statusMessage = " Timer cancelled."
654720 )
655721 }
722+ QuickTriggerManager .refreshQuickSettingsTiles(getApplication())
656723 }
657724
658725 private fun syncRunningTimerState () {
@@ -726,6 +793,15 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
726793 }
727794 }
728795
796+ private fun refreshQuickTriggerPresets (statusMessage : String ) {
797+ _uiState .update {
798+ it.copy(
799+ quickTriggerPresets = QuickTriggerManager .loadPresets(getApplication()),
800+ statusMessage = statusMessage
801+ )
802+ }
803+ }
804+
729805 private fun customCountdownSeconds (state : FakeCallUiState ): Int {
730806 val minutes = state.customCountdownMinutes.coerceAtLeast(0 )
731807 val seconds = state.customCountdownSeconds.coerceAtLeast(0 )
@@ -847,12 +923,14 @@ class FakeCallViewModel(application: Application) : AndroidViewModel(application
847923 private const val KEY_CUSTOM_EXACT_MINUTE = " custom_exact_minute"
848924 private const val KEY_CUSTOM_PRESETS = " custom_presets"
849925 private const val KEY_TIMER_ENDS_AT = " timer_ends_at"
926+ private const val KEY_ACTIVE_PRESET_SLOT = " quick_trigger_active_preset_slot"
850927 private const val KEY_AUDIO_URI = " audio_uri"
851928 private const val KEY_AUDIO_NAME = " audio_name"
852929 private const val KEY_RECORDING_ENABLED = " recording_enabled"
853930 private const val KEY_RECORDINGS_TREE_URI = " recordings_tree_uri"
854931 private const val KEY_RECORDINGS_FOLDER_NAME = " recordings_folder_name"
855932 private const val KEY_ONBOARDING_COMPLETE = " onboarding_complete"
933+ private const val KEY_QUICK_TRIGGER_PRESET_NAME = " quick_trigger_preset_name"
856934
857935 fun formatDelay (seconds : Int ): String {
858936 return when {
0 commit comments