Remove unnecessary code
This commit is contained in:
parent
7530d3e9e7
commit
117b1eb50b
@ -16,11 +16,10 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
|
||||
var isAutoSendEnabled: Bool = false
|
||||
var isEnabled: Bool = true
|
||||
|
||||
// Custom coding keys to handle migration from selectedWhisperModel
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, name, emoji, appConfigs, urlConfigs, isAIEnhancementEnabled, selectedPrompt, selectedLanguage, useScreenCapture, selectedAIProvider, selectedAIModel, isAutoSendEnabled, isEnabled
|
||||
case selectedWhisperModel // Old key
|
||||
case selectedTranscriptionModelName // New key
|
||||
case selectedWhisperModel
|
||||
case selectedTranscriptionModelName
|
||||
}
|
||||
|
||||
init(id: UUID = UUID(), name: String, emoji: String, appConfigs: [AppConfig]? = nil,
|
||||
@ -92,7 +91,6 @@ struct PowerModeConfig: Codable, Identifiable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
// App configuration
|
||||
struct AppConfig: Codable, Identifiable, Equatable {
|
||||
let id: UUID
|
||||
var bundleIdentifier: String
|
||||
@ -109,10 +107,9 @@ struct AppConfig: Codable, Identifiable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
// Simple URL configuration
|
||||
struct URLConfig: Codable, Identifiable, Equatable {
|
||||
let id: UUID
|
||||
var url: String // Simple URL like "google.com"
|
||||
var url: String
|
||||
|
||||
init(id: UUID = UUID(), url: String) {
|
||||
self.id = id
|
||||
@ -135,7 +132,6 @@ class PowerModeManager: ObservableObject {
|
||||
private init() {
|
||||
loadConfigurations()
|
||||
|
||||
// Set the active configuration from saved ID
|
||||
if let activeConfigIdString = UserDefaults.standard.string(forKey: activeConfigIdKey),
|
||||
let activeConfigId = UUID(uuidString: activeConfigIdString) {
|
||||
activeConfiguration = configurations.first { $0.id == activeConfigId }
|
||||
@ -180,7 +176,6 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Get configuration for a specific URL
|
||||
func getConfigurationForURL(_ url: String) -> PowerModeConfig? {
|
||||
let cleanedURL = cleanURL(url)
|
||||
|
||||
@ -198,7 +193,6 @@ class PowerModeManager: ObservableObject {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get configuration for an application bundle ID
|
||||
func getConfigurationForApp(_ bundleId: String) -> PowerModeConfig? {
|
||||
for config in configurations.filter({ $0.isEnabled }) {
|
||||
if let appConfigs = config.appConfigs {
|
||||
@ -210,7 +204,6 @@ class PowerModeManager: ObservableObject {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Enable a configuration
|
||||
func enableConfiguration(with id: UUID) {
|
||||
if let index = configurations.firstIndex(where: { $0.id == id }) {
|
||||
configurations[index].isEnabled = true
|
||||
@ -218,7 +211,6 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Disable a configuration
|
||||
func disableConfiguration(with id: UUID) {
|
||||
if let index = configurations.firstIndex(where: { $0.id == id }) {
|
||||
configurations[index].isEnabled = false
|
||||
@ -226,12 +218,10 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Get all enabled configurations
|
||||
var enabledConfigurations: [PowerModeConfig] {
|
||||
return configurations.filter { $0.isEnabled }
|
||||
}
|
||||
|
||||
// Add app configuration
|
||||
func addAppConfig(_ appConfig: AppConfig, to config: PowerModeConfig) {
|
||||
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
|
||||
var configs = updatedConfig.appConfigs ?? []
|
||||
@ -241,7 +231,6 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove app configuration
|
||||
func removeAppConfig(_ appConfig: AppConfig, from config: PowerModeConfig) {
|
||||
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
|
||||
updatedConfig.appConfigs?.removeAll(where: { $0.id == appConfig.id })
|
||||
@ -249,7 +238,6 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Add URL configuration
|
||||
func addURLConfig(_ urlConfig: URLConfig, to config: PowerModeConfig) {
|
||||
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
|
||||
var configs = updatedConfig.urlConfigs ?? []
|
||||
@ -259,7 +247,6 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove URL configuration
|
||||
func removeURLConfig(_ urlConfig: URLConfig, from config: PowerModeConfig) {
|
||||
if var updatedConfig = configurations.first(where: { $0.id == config.id }) {
|
||||
updatedConfig.urlConfigs?.removeAll(where: { $0.id == urlConfig.id })
|
||||
@ -267,7 +254,6 @@ class PowerModeManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean URL for comparison
|
||||
func cleanURL(_ url: String) -> String {
|
||||
return url.lowercased()
|
||||
.replacingOccurrences(of: "https://", with: "")
|
||||
@ -276,19 +262,16 @@ class PowerModeManager: ObservableObject {
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
// Set active configuration
|
||||
func setActiveConfiguration(_ config: PowerModeConfig?) {
|
||||
activeConfiguration = config
|
||||
UserDefaults.standard.set(config?.id.uuidString, forKey: activeConfigIdKey)
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
|
||||
// Get current active configuration
|
||||
var currentActiveConfiguration: PowerModeConfig? {
|
||||
return activeConfiguration
|
||||
}
|
||||
|
||||
// Get all available configurations in order
|
||||
func getAllAvailableConfigurations() -> [PowerModeConfig] {
|
||||
return configurations
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@ struct ConfigurationView: View {
|
||||
|
||||
// New state for screen capture toggle
|
||||
@State private var useScreenCapture = false
|
||||
// NEW: Auto-send toggle state
|
||||
@State private var isAutoSendEnabled = false
|
||||
|
||||
// State for prompt editing (similar to EnhancementSettingsView)
|
||||
@ -171,21 +170,9 @@ struct ConfigurationView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// Enhanced Emoji Picker with Custom Emoji Support
|
||||
// if isShowingEmojiPicker { // <<< This conditional block will be removed
|
||||
// EmojiPickerView(
|
||||
// selectedEmoji: $selectedEmoji,
|
||||
// isPresented: $isShowingEmojiPicker
|
||||
// )
|
||||
// .padding(.horizontal)
|
||||
// }
|
||||
|
||||
// SECTION 1: TRIGGERS
|
||||
VStack(spacing: 16) {
|
||||
// Section Header
|
||||
SectionHeader(title: "When to Trigger")
|
||||
|
||||
// Applications Subsection
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack {
|
||||
Text("Applications")
|
||||
@ -257,7 +244,6 @@ struct ConfigurationView: View {
|
||||
|
||||
Divider()
|
||||
|
||||
// Websites Subsection
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("Websites")
|
||||
.font(.subheadline)
|
||||
@ -328,12 +314,9 @@ struct ConfigurationView: View {
|
||||
.background(CardBackground(isSelected: false))
|
||||
.padding(.horizontal)
|
||||
|
||||
// SECTION 2: TRANSCRIPTION
|
||||
VStack(spacing: 16) {
|
||||
// Section Header
|
||||
SectionHeader(title: "Transcription")
|
||||
|
||||
// Whisper Model Selection Subsection
|
||||
if whisperState.usableModels.isEmpty {
|
||||
Text("No transcription models available. Please connect to a cloud service or download a local model in the AI Models tab.")
|
||||
.font(.subheadline)
|
||||
@ -342,7 +325,6 @@ struct ConfigurationView: View {
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(CardBackground(isSelected: false))
|
||||
} else {
|
||||
// Create a simple binding that uses current model if nil
|
||||
let modelBinding = Binding<String?>(
|
||||
get: {
|
||||
selectedTranscriptionModelName ?? whisperState.usableModels.first?.name
|
||||
@ -366,12 +348,10 @@ struct ConfigurationView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// Language Selection Subsection
|
||||
if let selectedModel = effectiveModelName,
|
||||
let modelInfo = whisperState.allAvailableModels.first(where: { $0.name == selectedModel }),
|
||||
modelInfo.isMultilingualModel {
|
||||
|
||||
// Create a simple binding that uses UserDefaults language if nil
|
||||
let languageBinding = Binding<String?>(
|
||||
get: {
|
||||
selectedLanguage ?? UserDefaults.standard.string(forKey: "SelectedLanguage") ?? "auto"
|
||||
@ -400,7 +380,6 @@ struct ConfigurationView: View {
|
||||
} else if let selectedModel = effectiveModelName,
|
||||
let modelInfo = whisperState.allAvailableModels.first(where: { $0.name == selectedModel }),
|
||||
!modelInfo.isMultilingualModel {
|
||||
// Silently set to English without showing UI
|
||||
let _ = { selectedLanguage = "en" }()
|
||||
}
|
||||
}
|
||||
@ -408,16 +387,13 @@ struct ConfigurationView: View {
|
||||
.background(CardBackground(isSelected: false))
|
||||
.padding(.horizontal)
|
||||
|
||||
// SECTION 3: AI ENHANCEMENT
|
||||
VStack(spacing: 16) {
|
||||
// Section Header
|
||||
SectionHeader(title: "AI Enhancement")
|
||||
|
||||
Toggle("Enable AI Enhancement", isOn: $isAIEnhancementEnabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.onChange(of: isAIEnhancementEnabled) { oldValue, newValue in
|
||||
if newValue {
|
||||
// When enabling AI enhancement, set default values if none are selected
|
||||
if selectedAIProvider == nil {
|
||||
selectedAIProvider = aiService.selectedProvider.rawValue
|
||||
}
|
||||
@ -429,21 +405,18 @@ struct ConfigurationView: View {
|
||||
|
||||
Divider()
|
||||
|
||||
// AI Provider Selection - Match style with Whisper model selection
|
||||
// Create a binding for the provider selection that falls back to global settings
|
||||
let providerBinding = Binding<AIProvider>(
|
||||
get: {
|
||||
if let providerName = selectedAIProvider,
|
||||
let provider = AIProvider(rawValue: providerName) {
|
||||
return provider
|
||||
}
|
||||
// Just return the global provider without modifying state
|
||||
return aiService.selectedProvider
|
||||
},
|
||||
set: { newValue in
|
||||
selectedAIProvider = newValue.rawValue // Update local state for UI responsiveness
|
||||
aiService.selectedProvider = newValue // Update global AI service state
|
||||
selectedAIModel = nil // Reset selected model when provider changes
|
||||
selectedAIProvider = newValue.rawValue
|
||||
aiService.selectedProvider = newValue
|
||||
selectedAIModel = nil
|
||||
}
|
||||
)
|
||||
|
||||
@ -470,9 +443,7 @@ struct ConfigurationView: View {
|
||||
}
|
||||
.labelsHidden()
|
||||
.onChange(of: selectedAIProvider) { oldValue, newValue in
|
||||
// When provider changes, ensure we have a valid model for that provider
|
||||
if let provider = newValue.flatMap({ AIProvider(rawValue: $0) }) {
|
||||
// Set default model for this provider
|
||||
selectedAIModel = provider.defaultModel
|
||||
}
|
||||
}
|
||||
@ -480,7 +451,6 @@ struct ConfigurationView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// AI Model Selection - Match style with whisper language selection
|
||||
let providerName = selectedAIProvider ?? aiService.selectedProvider.rawValue
|
||||
if let provider = AIProvider(rawValue: providerName),
|
||||
provider != .custom {
|
||||
@ -496,18 +466,15 @@ struct ConfigurationView: View {
|
||||
.italic()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
} else {
|
||||
// Create binding that falls back to current model for the selected provider
|
||||
let modelBinding = Binding<String>(
|
||||
get: {
|
||||
if let model = selectedAIModel, !model.isEmpty {
|
||||
return model
|
||||
}
|
||||
// Just return the current model without modifying state
|
||||
return aiService.currentModel
|
||||
},
|
||||
set: { newModelValue in
|
||||
selectedAIModel = newModelValue // Update local state
|
||||
// Update the model in AIService for the current provider
|
||||
selectedAIModel = newModelValue
|
||||
aiService.selectModel(newModelValue)
|
||||
}
|
||||
)
|
||||
@ -539,7 +506,6 @@ struct ConfigurationView: View {
|
||||
}
|
||||
|
||||
|
||||
// Enhancement Prompts Section (reused from EnhancementSettingsView)
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("Enhancement Prompt")
|
||||
.font(.headline)
|
||||
@ -576,7 +542,6 @@ struct ConfigurationView: View {
|
||||
.background(CardBackground(isSelected: false))
|
||||
.padding(.horizontal)
|
||||
|
||||
// SECTION 4: ADVANCED
|
||||
VStack(spacing: 16) {
|
||||
SectionHeader(title: "Advanced")
|
||||
|
||||
@ -595,7 +560,6 @@ struct ConfigurationView: View {
|
||||
.background(CardBackground(isSelected: false))
|
||||
.padding(.horizontal)
|
||||
|
||||
// Save Button
|
||||
VoiceInkButton(
|
||||
title: mode.isAdding ? "Add New Power Mode" : "Save Changes",
|
||||
action: saveConfiguration,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import SwiftUI
|
||||
|
||||
// Power Mode Popover for recorder views
|
||||
struct PowerModePopover: View {
|
||||
@ObservedObject var powerModeManager = PowerModeManager.shared
|
||||
@State private var selectedConfig: PowerModeConfig?
|
||||
@ -18,13 +17,10 @@ struct PowerModePopover: View {
|
||||
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
// "Disable" option if a power mode is active
|
||||
if powerModeManager.activeConfiguration != nil {
|
||||
Button(action: {
|
||||
powerModeManager.setActiveConfiguration(nil)
|
||||
selectedConfig = nil
|
||||
// Here we might want to revert to a default state,
|
||||
// but for now, we'll just deactivate the power mode.
|
||||
}) {
|
||||
HStack {
|
||||
Text("Disable Power Mode")
|
||||
@ -40,7 +36,6 @@ struct PowerModePopover: View {
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
// Custom Configurations
|
||||
ForEach(powerModeManager.configurations) { config in
|
||||
PowerModeRow(
|
||||
config: config,
|
||||
@ -48,7 +43,6 @@ struct PowerModePopover: View {
|
||||
action: {
|
||||
powerModeManager.setActiveConfiguration(config)
|
||||
selectedConfig = config
|
||||
// Apply configuration immediately
|
||||
applySelectedConfiguration()
|
||||
}
|
||||
)
|
||||
@ -63,12 +57,10 @@ struct PowerModePopover: View {
|
||||
.background(Color.black)
|
||||
.environment(\.colorScheme, .dark)
|
||||
.onAppear {
|
||||
// Set the initially selected configuration
|
||||
selectedConfig = powerModeManager.activeConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to apply the selected configuration
|
||||
private func applySelectedConfiguration() {
|
||||
Task {
|
||||
if let config = selectedConfig {
|
||||
@ -78,7 +70,6 @@ struct PowerModePopover: View {
|
||||
}
|
||||
}
|
||||
|
||||
// Row view for each power mode in the popover
|
||||
struct PowerModeRow: View {
|
||||
let config: PowerModeConfig
|
||||
let isSelected: Bool
|
||||
@ -87,7 +78,6 @@ struct PowerModeRow: View {
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
HStack(spacing: 8) {
|
||||
// Always use the emoji from the configuration
|
||||
Text(config.emoji)
|
||||
.font(.system(size: 14))
|
||||
|
||||
|
||||
@ -1,19 +1,16 @@
|
||||
import Foundation
|
||||
import AppKit
|
||||
|
||||
// Represents the state of the application that can be modified by a Power Mode.
|
||||
// This struct captures the settings that will be temporarily overridden.
|
||||
struct ApplicationState: Codable {
|
||||
var isEnhancementEnabled: Bool
|
||||
var useScreenCaptureContext: Bool
|
||||
var selectedPromptId: String? // Storing as String for Codable simplicity
|
||||
var selectedPromptId: String?
|
||||
var selectedAIProvider: String?
|
||||
var selectedAIModel: String?
|
||||
var selectedLanguage: String?
|
||||
var transcriptionModelName: String?
|
||||
}
|
||||
|
||||
// Represents an active Power Mode session.
|
||||
struct PowerModeSession: Codable {
|
||||
let id: UUID
|
||||
let startTime: Date
|
||||
@ -29,7 +26,6 @@ class PowerModeSessionManager {
|
||||
private var enhancementService: AIEnhancementService?
|
||||
|
||||
private init() {
|
||||
// Attempt to recover a session on startup in case of a crash.
|
||||
recoverSession()
|
||||
}
|
||||
|
||||
@ -38,15 +34,12 @@ class PowerModeSessionManager {
|
||||
self.enhancementService = enhancementService
|
||||
}
|
||||
|
||||
// Begins a new Power Mode session. It captures the current state,
|
||||
// applies the new configuration, and saves the session.
|
||||
func beginSession(with config: PowerModeConfig) async {
|
||||
guard let whisperState = whisperState, let enhancementService = enhancementService else {
|
||||
print("SessionManager not configured.")
|
||||
return
|
||||
}
|
||||
|
||||
// 1. Capture the current application state.
|
||||
let originalState = ApplicationState(
|
||||
isEnhancementEnabled: enhancementService.isEnhancementEnabled,
|
||||
useScreenCaptureContext: enhancementService.useScreenCaptureContext,
|
||||
@ -57,7 +50,6 @@ class PowerModeSessionManager {
|
||||
transcriptionModelName: whisperState.currentTranscriptionModel?.name
|
||||
)
|
||||
|
||||
// 2. Create and save the session.
|
||||
let newSession = PowerModeSession(
|
||||
id: UUID(),
|
||||
startTime: Date(),
|
||||
@ -65,22 +57,17 @@ class PowerModeSessionManager {
|
||||
)
|
||||
saveSession(newSession)
|
||||
|
||||
// 3. Apply the new configuration's settings.
|
||||
await applyConfiguration(config)
|
||||
}
|
||||
|
||||
// Ends the current Power Mode session and restores the original state.
|
||||
func endSession() async {
|
||||
guard let session = loadSession() else { return }
|
||||
|
||||
// Restore the original state from the session.
|
||||
await restoreState(session.originalState)
|
||||
|
||||
// Clear the session from UserDefaults.
|
||||
clearSession()
|
||||
}
|
||||
|
||||
// Applies the settings from a PowerModeConfig.
|
||||
private func applyConfiguration(_ config: PowerModeConfig) async {
|
||||
guard let enhancementService = enhancementService else { return }
|
||||
|
||||
@ -117,7 +104,6 @@ class PowerModeSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Restores the application state from a saved state object.
|
||||
private func restoreState(_ state: ApplicationState) async {
|
||||
guard let enhancementService = enhancementService else { return }
|
||||
|
||||
@ -149,7 +135,6 @@ class PowerModeSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Handles the logic for switching transcription models.
|
||||
private func handleModelChange(to newModel: any TranscriptionModel) async {
|
||||
guard let whisperState = whisperState else { return }
|
||||
|
||||
@ -162,13 +147,11 @@ class PowerModeSessionManager {
|
||||
do {
|
||||
try await whisperState.loadModel(localModel)
|
||||
} catch {
|
||||
// Log error appropriately
|
||||
print("Power Mode: Failed to load local model '\(localModel.name)': \(error)")
|
||||
}
|
||||
}
|
||||
case .parakeet:
|
||||
await whisperState.cleanupModelResources()
|
||||
// Parakeet models are loaded on demand, so we only need to clean up.
|
||||
|
||||
default:
|
||||
await whisperState.cleanupModelResources()
|
||||
@ -183,8 +166,6 @@ class PowerModeSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UserDefaults Persistence
|
||||
|
||||
private func saveSession(_ session: PowerModeSession) {
|
||||
do {
|
||||
let data = try JSONEncoder().encode(session)
|
||||
|
||||
@ -41,20 +41,15 @@ struct PowerModeValidator {
|
||||
self.powerModeManager = powerModeManager
|
||||
}
|
||||
|
||||
/// Validates a power mode configuration when the user tries to save it.
|
||||
/// This validation only happens at save time, not during editing.
|
||||
func validateForSave(config: PowerModeConfig, mode: ConfigurationMode) -> [PowerModeValidationError] {
|
||||
var errors: [PowerModeValidationError] = []
|
||||
|
||||
// Validate name
|
||||
if config.name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
errors.append(.emptyName)
|
||||
}
|
||||
|
||||
// Check for duplicate name
|
||||
let isDuplicateName = powerModeManager.configurations.contains { existingConfig in
|
||||
if case .edit(let editConfig) = mode, existingConfig.id == editConfig.id {
|
||||
// Skip checking against itself when editing
|
||||
return false
|
||||
}
|
||||
return existingConfig.name == config.name
|
||||
@ -64,17 +59,14 @@ struct PowerModeValidator {
|
||||
errors.append(.duplicateName(config.name))
|
||||
}
|
||||
|
||||
// For all modes, check that there's at least one trigger
|
||||
if (config.appConfigs == nil || config.appConfigs?.isEmpty == true) &&
|
||||
(config.urlConfigs == nil || config.urlConfigs?.isEmpty == true) {
|
||||
errors.append(.noTriggers)
|
||||
}
|
||||
|
||||
// Check for duplicate app configurations
|
||||
if let appConfigs = config.appConfigs {
|
||||
for appConfig in appConfigs {
|
||||
for existingConfig in powerModeManager.configurations {
|
||||
// Skip checking against itself when editing
|
||||
if case .edit(let editConfig) = mode, existingConfig.id == editConfig.id {
|
||||
continue
|
||||
}
|
||||
@ -87,11 +79,9 @@ struct PowerModeValidator {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate website configurations
|
||||
if let urlConfigs = config.urlConfigs {
|
||||
for urlConfig in urlConfigs {
|
||||
for existingConfig in powerModeManager.configurations {
|
||||
// Skip checking against itself when editing
|
||||
if case .edit(let editConfig) = mode, existingConfig.id == editConfig.id {
|
||||
continue
|
||||
}
|
||||
@ -108,7 +98,6 @@ struct PowerModeValidator {
|
||||
}
|
||||
}
|
||||
|
||||
// Alert extension for showing validation errors
|
||||
extension View {
|
||||
func powerModeValidationAlert(
|
||||
errors: [PowerModeValidationError],
|
||||
|
||||
@ -13,7 +13,6 @@ extension View {
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration Mode Enum
|
||||
enum ConfigurationMode: Hashable {
|
||||
case add
|
||||
case edit(PowerModeConfig)
|
||||
@ -30,18 +29,16 @@ enum ConfigurationMode: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
// Implement hash(into:) to conform to Hashable
|
||||
func hash(into hasher: inout Hasher) {
|
||||
switch self {
|
||||
case .add:
|
||||
hasher.combine(0) // Use a unique value for add
|
||||
hasher.combine(0)
|
||||
case .edit(let config):
|
||||
hasher.combine(1) // Use a unique value for edit
|
||||
hasher.combine(1)
|
||||
hasher.combine(config.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement == to conform to Equatable (required by Hashable)
|
||||
static func == (lhs: ConfigurationMode, rhs: ConfigurationMode) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.add, .add):
|
||||
@ -54,16 +51,13 @@ enum ConfigurationMode: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration Type
|
||||
enum ConfigurationType {
|
||||
case application
|
||||
case website
|
||||
}
|
||||
|
||||
// Common Emojis for selection
|
||||
let commonEmojis = ["🏢", "🏠", "💼", "🎮", "📱", "📺", "🎵", "📚", "✏️", "🎨", "🧠", "⚙️", "💻", "🌐", "📝", "📊", "🔍", "💬", "📈", "🔧"]
|
||||
|
||||
// Main Power Mode View with Navigation
|
||||
struct PowerModeView: View {
|
||||
@StateObject private var powerModeManager = PowerModeManager.shared
|
||||
@EnvironmentObject private var enhancementService: AIEnhancementService
|
||||
@ -74,7 +68,6 @@ struct PowerModeView: View {
|
||||
var body: some View {
|
||||
NavigationStack(path: $navigationPath) {
|
||||
VStack(spacing: 0) {
|
||||
// Header Section with proper macOS styling
|
||||
VStack(spacing: 12) {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
@ -83,8 +76,7 @@ struct PowerModeView: View {
|
||||
.font(.system(size: 28, weight: .bold, design: .default))
|
||||
.foregroundColor(.primary)
|
||||
|
||||
// InfoTip for Power Mode
|
||||
InfoTip(
|
||||
InfoTip(
|
||||
title: "What is Power Mode?",
|
||||
message: "Automatically apply custom configurations based on the app/website you are using",
|
||||
learnMoreURL: "https://www.youtube.com/watch?v=-xFLvgNs_Iw"
|
||||
@ -98,7 +90,6 @@ struct PowerModeView: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
// Add button in header for better macOS UX
|
||||
Button(action: {
|
||||
configurationMode = .add
|
||||
navigationPath.append(configurationMode!)
|
||||
@ -122,18 +113,15 @@ struct PowerModeView: View {
|
||||
.padding(.top, 20)
|
||||
.padding(.bottom, 16)
|
||||
|
||||
// Separator
|
||||
Rectangle()
|
||||
.fill(Color(NSColor.separatorColor))
|
||||
.frame(height: 1)
|
||||
.padding(.horizontal, 24)
|
||||
|
||||
// Main Content Area
|
||||
GeometryReader { geometry in
|
||||
ScrollView {
|
||||
VStack(spacing: 0) {
|
||||
if powerModeManager.configurations.isEmpty {
|
||||
// Empty State - Centered and symmetric
|
||||
VStack(spacing: 24) {
|
||||
Spacer()
|
||||
.frame(height: geometry.size.height * 0.2)
|
||||
@ -148,7 +136,7 @@ struct PowerModeView: View {
|
||||
.font(.system(size: 20, weight: .medium))
|
||||
.foregroundColor(.primary)
|
||||
|
||||
Text("Create your first power mode to enhance your productivity\nwith context-aware AI assistance")
|
||||
Text("Create your first power mode to enhance your VoiceInk experience\nwith context-aware speech-to-text AI transcription tool")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
@ -161,7 +149,6 @@ struct PowerModeView: View {
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(minHeight: geometry.size.height)
|
||||
} else {
|
||||
// Configurations Grid with symmetric padding
|
||||
VStack(spacing: 0) {
|
||||
PowerModeConfigurationsGrid(
|
||||
powerModeManager: powerModeManager,
|
||||
@ -173,7 +160,6 @@ struct PowerModeView: View {
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.vertical, 20)
|
||||
|
||||
// Bottom spacing for visual balance
|
||||
Spacer()
|
||||
.frame(height: 40)
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import SwiftUI
|
||||
// Supporting Views
|
||||
|
||||
// VoiceInk's consistent button component
|
||||
struct VoiceInkButton: View {
|
||||
let title: String
|
||||
let action: () -> Void
|
||||
@ -91,10 +89,8 @@ struct ConfigurationRow: View {
|
||||
@EnvironmentObject var enhancementService: AIEnhancementService
|
||||
@EnvironmentObject var whisperState: WhisperState
|
||||
|
||||
// How many app icons to show at maximum
|
||||
private let maxAppIconsToShow = 5
|
||||
|
||||
// Data properties
|
||||
private var selectedPrompt: CustomPrompt? {
|
||||
guard let promptId = config.selectedPrompt,
|
||||
let uuid = UUID(uuidString: promptId) else { return nil }
|
||||
@ -147,51 +143,46 @@ struct ConfigurationRow: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
// Top row: Emoji, Name, and App/Website counts
|
||||
HStack(spacing: 12) {
|
||||
// Left: Emoji/Icon
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(Color(NSColor.controlBackgroundColor))
|
||||
.frame(width: 40, height: 40)
|
||||
|
||||
Text(config.emoji)
|
||||
.font(.system(size: 20))
|
||||
}
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(Color(NSColor.controlBackgroundColor))
|
||||
.frame(width: 40, height: 40)
|
||||
|
||||
Text(config.emoji)
|
||||
.font(.system(size: 20))
|
||||
}
|
||||
|
||||
// Middle: Name and badge
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
HStack(spacing: 6) {
|
||||
Text(config.name)
|
||||
.font(.system(size: 15, weight: .semibold))
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
HStack(spacing: 6) {
|
||||
Text(config.name)
|
||||
.font(.system(size: 15, weight: .semibold))
|
||||
}
|
||||
|
||||
HStack(spacing: 12) {
|
||||
if appCount > 0 {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "app.fill")
|
||||
.font(.system(size: 10))
|
||||
Text(appText)
|
||||
.font(.caption2)
|
||||
}
|
||||
}
|
||||
|
||||
// Display app and website counts
|
||||
HStack(spacing: 12) {
|
||||
if appCount > 0 {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "app.fill")
|
||||
.font(.system(size: 10))
|
||||
Text(appText)
|
||||
.font(.caption2)
|
||||
}
|
||||
}
|
||||
|
||||
if websiteCount > 0 {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "globe")
|
||||
.font(.system(size: 10))
|
||||
Text(websiteText)
|
||||
.font(.caption2)
|
||||
}
|
||||
if websiteCount > 0 {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "globe")
|
||||
.font(.system(size: 10))
|
||||
Text(websiteText)
|
||||
.font(.caption2)
|
||||
}
|
||||
}
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
// Right: Toggle Switch
|
||||
Toggle("", isOn: $config.isEnabled)
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.labelsHidden()
|
||||
@ -199,14 +190,11 @@ struct ConfigurationRow: View {
|
||||
.padding(.vertical, 12)
|
||||
.padding(.horizontal, 14)
|
||||
|
||||
// Only add divider and settings row if we have settings
|
||||
if selectedModel != nil || selectedLanguage != nil || config.isAIEnhancementEnabled {
|
||||
Divider()
|
||||
.padding(.horizontal, 16)
|
||||
|
||||
// Settings badges in specified order
|
||||
HStack(spacing: 8) {
|
||||
// 1. Voice Model badge
|
||||
if let model = selectedModel, model != "Default" {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "waveform")
|
||||
@ -224,7 +212,6 @@ struct ConfigurationRow: View {
|
||||
)
|
||||
}
|
||||
|
||||
// 2. Language badge
|
||||
if let language = selectedLanguage, language != "Default" {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "globe")
|
||||
@ -242,12 +229,10 @@ struct ConfigurationRow: View {
|
||||
)
|
||||
}
|
||||
|
||||
// 3. AI Model badge if specified (moved before AI Enhancement)
|
||||
if config.isAIEnhancementEnabled, let modelName = config.selectedAIModel, !modelName.isEmpty {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "cpu")
|
||||
.font(.system(size: 10))
|
||||
// Display a shortened version of the model name if it's too long (increased limit)
|
||||
Text(modelName.count > 20 ? String(modelName.prefix(18)) + "..." : modelName)
|
||||
.font(.caption)
|
||||
}
|
||||
@ -261,9 +246,7 @@ struct ConfigurationRow: View {
|
||||
)
|
||||
}
|
||||
|
||||
// 4. AI Enhancement badge
|
||||
if config.isAIEnhancementEnabled {
|
||||
// Context Awareness badge (moved before AI Enhancement)
|
||||
if config.useScreenCapture {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "camera.viewfinder")
|
||||
@ -321,7 +304,6 @@ struct ConfigurationRow: View {
|
||||
}
|
||||
}
|
||||
|
||||
// App Icon View Component
|
||||
struct PowerModeAppIcon: View {
|
||||
let bundleId: String
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user