Removed session management & use power mode with a new default mode.

This commit is contained in:
Beingpax 2025-08-12 22:33:10 +05:45
parent d96fbb1ba2
commit 6ad4d70760
5 changed files with 93 additions and 45 deletions

View File

@ -27,7 +27,6 @@ class ActiveWindowService: ObservableObject {
func applyConfigurationForCurrentApp() async {
guard let frontmostApp = NSWorkspace.shared.frontmostApplication,
let bundleIdentifier = frontmostApp.bundleIdentifier else {
await PowerModeSessionManager.shared.endSession()
return
}
@ -53,7 +52,7 @@ class ActiveWindowService: ObservableObject {
}
if configToApply == nil {
configToApply = PowerModeManager.shared.getWildcardConfiguration()
configToApply = PowerModeManager.shared.getDefaultConfiguration()
}
if let config = configToApply {
@ -61,11 +60,7 @@ class ActiveWindowService: ObservableObject {
PowerModeManager.shared.setActiveConfiguration(config)
}
await PowerModeSessionManager.shared.beginSession(with: config)
} else {
await MainActor.run {
PowerModeManager.shared.setActiveConfiguration(nil)
}
await PowerModeSessionManager.shared.endSession()
}
// If no config found, keep the current active configuration (don't clear it)
}
}

View File

@ -15,9 +15,10 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
var selectedAIModel: String?
var isAutoSendEnabled: Bool = false
var isEnabled: Bool = true
var isDefault: Bool = false
enum CodingKeys: String, CodingKey {
case id, name, emoji, appConfigs, urlConfigs, isAIEnhancementEnabled, selectedPrompt, selectedLanguage, useScreenCapture, selectedAIProvider, selectedAIModel, isAutoSendEnabled, isEnabled
case id, name, emoji, appConfigs, urlConfigs, isAIEnhancementEnabled, selectedPrompt, selectedLanguage, useScreenCapture, selectedAIProvider, selectedAIModel, isAutoSendEnabled, isEnabled, isDefault
case selectedWhisperModel
case selectedTranscriptionModelName
}
@ -25,7 +26,7 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
init(id: UUID = UUID(), name: String, emoji: String, appConfigs: [AppConfig]? = nil,
urlConfigs: [URLConfig]? = nil, isAIEnhancementEnabled: Bool, selectedPrompt: String? = nil,
selectedTranscriptionModelName: String? = nil, selectedLanguage: String? = nil, useScreenCapture: Bool = false,
selectedAIProvider: String? = nil, selectedAIModel: String? = nil, isAutoSendEnabled: Bool = false, isEnabled: Bool = true) {
selectedAIProvider: String? = nil, selectedAIModel: String? = nil, isAutoSendEnabled: Bool = false, isEnabled: Bool = true, isDefault: Bool = false) {
self.id = id
self.name = name
self.emoji = emoji
@ -40,6 +41,7 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
self.selectedTranscriptionModelName = selectedTranscriptionModelName ?? UserDefaults.standard.string(forKey: "CurrentTranscriptionModel")
self.selectedLanguage = selectedLanguage ?? UserDefaults.standard.string(forKey: "SelectedLanguage") ?? "en"
self.isEnabled = isEnabled
self.isDefault = isDefault
}
init(from decoder: Decoder) throws {
@ -57,6 +59,7 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
selectedAIModel = try container.decodeIfPresent(String.self, forKey: .selectedAIModel)
isAutoSendEnabled = try container.decodeIfPresent(Bool.self, forKey: .isAutoSendEnabled) ?? false
isEnabled = try container.decodeIfPresent(Bool.self, forKey: .isEnabled) ?? true
isDefault = try container.decodeIfPresent(Bool.self, forKey: .isDefault) ?? false
if let newModelName = try container.decodeIfPresent(String.self, forKey: .selectedTranscriptionModelName) {
selectedTranscriptionModelName = newModelName
@ -83,6 +86,7 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
try container.encode(isAutoSendEnabled, forKey: .isAutoSendEnabled)
try container.encodeIfPresent(selectedTranscriptionModelName, forKey: .selectedTranscriptionModelName)
try container.encode(isEnabled, forKey: .isEnabled)
try container.encode(isDefault, forKey: .isDefault)
}
@ -204,15 +208,26 @@ class PowerModeManager: ObservableObject {
return nil
}
func getWildcardConfiguration() -> PowerModeConfig? {
for config in configurations.filter({ $0.isEnabled }) {
if let urlConfigs = config.urlConfigs {
if urlConfigs.contains(where: { $0.url == "*" }) {
return config
}
}
func getDefaultConfiguration() -> PowerModeConfig? {
return configurations.first { $0.isEnabled && $0.isDefault }
}
func hasDefaultConfiguration() -> Bool {
return configurations.contains { $0.isDefault }
}
func setAsDefault(configId: UUID) {
// Clear any existing default
for index in configurations.indices {
configurations[index].isDefault = false
}
return nil
// Set the specified config as default
if let index = configurations.firstIndex(where: { $0.id == configId }) {
configurations[index].isDefault = true
}
saveConfigurations()
}
func enableConfiguration(with id: UUID) {

View File

@ -36,6 +36,7 @@ struct ConfigurationView: View {
// New state for screen capture toggle
@State private var useScreenCapture = false
@State private var isAutoSendEnabled = false
@State private var isDefault = false
// State for prompt editing (similar to EnhancementSettingsView)
@State private var isEditingPrompt = false
@ -44,6 +45,14 @@ struct ConfigurationView: View {
// Whisper state for model selection
@EnvironmentObject private var whisperState: WhisperState
// Computed property to check if current config is the default
private var isCurrentConfigDefault: Bool {
if case .edit(let config) = mode {
return config.isDefault
}
return false
}
private var filteredApps: [(url: URL, name: String, bundleId: String, icon: NSImage)] {
if searchText.isEmpty {
return installedApps
@ -77,6 +86,7 @@ struct ConfigurationView: View {
_selectedEmoji = State(initialValue: "✏️")
_useScreenCapture = State(initialValue: false)
_isAutoSendEnabled = State(initialValue: false)
_isDefault = State(initialValue: false)
// Default to current global AI provider/model for new configurations - use UserDefaults only
_selectedAIProvider = State(initialValue: UserDefaults.standard.string(forKey: "selectedAIProvider"))
_selectedAIModel = State(initialValue: nil) // Initialize to nil and set it after view appears
@ -93,6 +103,7 @@ struct ConfigurationView: View {
_websiteConfigs = State(initialValue: latestConfig.urlConfigs ?? [])
_useScreenCapture = State(initialValue: latestConfig.useScreenCapture)
_isAutoSendEnabled = State(initialValue: latestConfig.isAutoSendEnabled)
_isDefault = State(initialValue: latestConfig.isDefault)
_selectedAIProvider = State(initialValue: latestConfig.selectedAIProvider)
_selectedAIModel = State(initialValue: latestConfig.selectedAIModel)
}
@ -131,33 +142,50 @@ struct ConfigurationView: View {
ScrollView {
VStack(spacing: 20) {
// Main Input Section
HStack(spacing: 16) {
Button(action: {
isShowingEmojiPicker.toggle()
}) {
ZStack {
Circle()
.fill(Color.accentColor.opacity(0.15))
.frame(width: 48, height: 48)
Text(selectedEmoji)
.font(.system(size: 24))
VStack(spacing: 16) {
HStack(spacing: 16) {
Button(action: {
isShowingEmojiPicker.toggle()
}) {
ZStack {
Circle()
.fill(Color.accentColor.opacity(0.15))
.frame(width: 48, height: 48)
Text(selectedEmoji)
.font(.system(size: 24))
}
}
}
.buttonStyle(.plain)
.popover(isPresented: $isShowingEmojiPicker, arrowEdge: .bottom) {
EmojiPickerView(
selectedEmoji: $selectedEmoji,
isPresented: $isShowingEmojiPicker
)
.buttonStyle(.plain)
.popover(isPresented: $isShowingEmojiPicker, arrowEdge: .bottom) {
EmojiPickerView(
selectedEmoji: $selectedEmoji,
isPresented: $isShowingEmojiPicker
)
}
TextField("Name your power mode", text: $configName)
.font(.system(size: 18, weight: .bold))
.textFieldStyle(.plain)
.foregroundColor(.primary)
.tint(.accentColor)
.focused($isNameFieldFocused)
}
TextField("Name your power mode", text: $configName)
.font(.system(size: 18, weight: .bold))
.textFieldStyle(.plain)
.foregroundColor(.primary)
.tint(.accentColor)
.focused($isNameFieldFocused)
// Default Power Mode Toggle
if !powerModeManager.hasDefaultConfiguration() || isCurrentConfigDefault {
HStack {
Toggle("Set as default power mode", isOn: $isDefault)
.font(.system(size: 14))
InfoTip(
title: "Default Power Mode",
message: "Default power mode is used when no specific app or website matches are found"
)
Spacer()
}
}
}
.padding(.horizontal, 20)
.padding(.vertical, 16)
@ -649,7 +677,8 @@ struct ConfigurationView: View {
useScreenCapture: useScreenCapture,
selectedAIProvider: selectedAIProvider,
selectedAIModel: selectedAIModel,
isAutoSendEnabled: isAutoSendEnabled
isAutoSendEnabled: isAutoSendEnabled,
isDefault: isDefault
)
case .edit(let config):
var updatedConfig = config
@ -665,6 +694,7 @@ struct ConfigurationView: View {
updatedConfig.isAutoSendEnabled = isAutoSendEnabled
updatedConfig.selectedAIProvider = selectedAIProvider
updatedConfig.selectedAIModel = selectedAIModel
updatedConfig.isDefault = isDefault
return updatedConfig
}
}
@ -753,6 +783,11 @@ struct ConfigurationView: View {
powerModeManager.updateConfiguration(config)
}
// Handle default flag separately to ensure only one config is default
if isDefault {
powerModeManager.setAsDefault(configId: config.id)
}
presentationMode.wrappedValue.dismiss()
}
}

View File

@ -158,6 +158,12 @@ struct ConfigurationRow: View {
HStack(spacing: 6) {
Text(config.name)
.font(.system(size: 15, weight: .semibold))
if config.isDefault {
Image(systemName: "star.fill")
.font(.system(size: 12))
.foregroundColor(.accentColor)
}
}
HStack(spacing: 12) {

View File

@ -220,7 +220,6 @@ class WhisperState: NSObject, ObservableObject {
await MainActor.run {
recordingState = .idle
}
await PowerModeSessionManager.shared.endSession()
await cleanupModelResources()
return
}
@ -377,7 +376,6 @@ class WhisperState: NSObject, ObservableObject {
}
await self.dismissMiniRecorder()
await PowerModeSessionManager.shared.endSession()
} catch {
do {
@ -412,7 +410,6 @@ class WhisperState: NSObject, ObservableObject {
}
await self.dismissMiniRecorder()
await PowerModeSessionManager.shared.endSession()
}
}