Redesign recorder views with reusable components

This commit is contained in:
Beingpax 2025-08-06 13:10:21 +05:45
parent 36f33e5a83
commit f7987cd4bd
4 changed files with 86 additions and 104 deletions

View File

@ -11,8 +11,8 @@
E1A261122CC143AC00B233D1 /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = E1A261112CC143AC00B233D1 /* KeyboardShortcuts */; };
E1ADD45A2CC5352A00303ECB /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = E1ADD4592CC5352A00303ECB /* LaunchAtLogin */; };
E1ADD45F2CC544F100303ECB /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = E1ADD45E2CC544F100303ECB /* Sparkle */; };
E1B2DCAB2E3DE70A008DFD68 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1B2DCAA2E3DE70A008DFD68 /* whisper.xcframework */; };
E1B2DCAC2E3DE70A008DFD68 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E1B2DCAA2E3DE70A008DFD68 /* whisper.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E1CE28782E4336150082B758 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1CE28772E4336150082B758 /* whisper.xcframework */; };
E1CE28792E4336150082B758 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E1CE28772E4336150082B758 /* whisper.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E1D7EF992E35E16C00640029 /* MediaRemoteAdapter in Frameworks */ = {isa = PBXBuildFile; productRef = E1D7EF982E35E16C00640029 /* MediaRemoteAdapter */; };
E1D7EF9A2E35E19B00640029 /* MediaRemoteAdapter in Embed Frameworks */ = {isa = PBXBuildFile; productRef = E1D7EF982E35E16C00640029 /* MediaRemoteAdapter */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
E1F5FA7A2DA6CBF900B1FD8A /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = E1F5FA792DA6CBF900B1FD8A /* Zip */; };
@ -42,7 +42,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
E1B2DCAC2E3DE70A008DFD68 /* whisper.xcframework in Embed Frameworks */,
E1CE28792E4336150082B758 /* whisper.xcframework in Embed Frameworks */,
E1D7EF9A2E35E19B00640029 /* MediaRemoteAdapter in Embed Frameworks */,
);
name = "Embed Frameworks";
@ -55,6 +55,7 @@
E11473C32CBE0F0B00318EE4 /* VoiceInkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoiceInkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E11473CD2CBE0F0B00318EE4 /* VoiceInkUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoiceInkUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E1B2DCAA2E3DE70A008DFD68 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = whisper.xcframework; path = "../Downloads/build-apple/whisper.xcframework"; sourceTree = "<group>"; };
E1CE28772E4336150082B758 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = whisper.xcframework; path = "../build-apple/whisper.xcframework"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
@ -83,7 +84,7 @@
E1ADD45A2CC5352A00303ECB /* LaunchAtLogin in Frameworks */,
E1D7EF992E35E16C00640029 /* MediaRemoteAdapter in Frameworks */,
E10F06092E3F390600F7FBDC /* FluidAudio in Frameworks */,
E1B2DCAB2E3DE70A008DFD68 /* whisper.xcframework in Frameworks */,
E1CE28782E4336150082B758 /* whisper.xcframework in Frameworks */,
E1ADD45F2CC544F100303ECB /* Sparkle in Frameworks */,
E1A261122CC143AC00B233D1 /* KeyboardShortcuts in Frameworks */,
E1F5FA7A2DA6CBF900B1FD8A /* Zip in Frameworks */,
@ -131,6 +132,7 @@
E114741C2CBE1DE200318EE4 /* Frameworks */ = {
isa = PBXGroup;
children = (
E1CE28772E4336150082B758 /* whisper.xcframework */,
E1B2DCAA2E3DE70A008DFD68 /* whisper.xcframework */,
);
name = Frameworks;

View File

@ -34,44 +34,7 @@ struct MiniRecorderView: View {
)
}
private var rightButton: some View {
Group {
if !powerModeManager.enabledConfigurations.isEmpty && false {
RecorderToggleButton(
isEnabled: !powerModeManager.enabledConfigurations.isEmpty,
icon: powerModeManager.currentActiveConfiguration?.emoji ?? "⚙️",
color: .orange,
disabled: false
) {
showPowerModePopover.toggle()
}
.frame(width: 24)
.padding(.trailing, 8)
.popover(isPresented: $showPowerModePopover, arrowEdge: .bottom) {
PowerModePopover()
}
} else {
RecorderToggleButton(
isEnabled: enhancementService.isEnhancementEnabled,
icon: enhancementService.activePrompt?.icon.rawValue ?? "brain",
color: .blue,
disabled: false
) {
if enhancementService.isEnhancementEnabled {
showEnhancementPromptPopover.toggle()
} else {
enhancementService.isEnhancementEnabled = true
}
}
.frame(width: 24)
.padding(.trailing, 8)
.popover(isPresented: $showEnhancementPromptPopover, arrowEdge: .bottom) {
EnhancementPromptPopover()
.environmentObject(enhancementService)
}
}
}
}
var body: some View {
Group {
@ -85,23 +48,13 @@ struct MiniRecorderView: View {
}
.overlay {
HStack(spacing: 0) {
let isRecording = whisperState.recordingState == .recording
let isProcessing = whisperState.recordingState == .transcribing || whisperState.recordingState == .enhancing
RecorderRecordButton(
isRecording: isRecording,
isProcessing: isProcessing
) {
Task { await whisperState.toggleRecord() }
}
.frame(width: 24)
.padding(.leading, 8)
RecorderPromptButton(showPopover: $showEnhancementPromptPopover)
statusView
.frame(maxWidth: .infinity)
.padding(.horizontal, 8)
rightButton
RecorderPowerModeButton(showPopover: $showPowerModePopover)
}
.padding(.vertical, 8)
}

View File

@ -33,62 +33,24 @@ struct NotchRecorderView: View {
private var leftSection: some View {
HStack(spacing: 8) {
let isRecording = whisperState.recordingState == .recording
let isProcessing = whisperState.recordingState == .transcribing || whisperState.recordingState == .enhancing
RecorderPromptButton(
showPopover: $showEnhancementPromptPopover,
buttonSize: 22,
padding: EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
)
RecorderRecordButton(
isRecording: isRecording,
isProcessing: isProcessing
) {
Task { await whisperState.toggleRecord() }
}
.frame(width: 22)
rightToggleButton
RecorderPowerModeButton(
showPopover: $showPowerModePopover,
buttonSize: 22,
padding: EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
)
Spacer()
}
.frame(width: 64)
.frame(width: 84)
.padding(.leading, 16)
}
private var rightToggleButton: some View {
HStack(spacing: 4) {
if !powerModeManager.enabledConfigurations.isEmpty && false {
RecorderToggleButton(
isEnabled: !powerModeManager.enabledConfigurations.isEmpty,
icon: powerModeManager.currentActiveConfiguration?.emoji ?? "⚙️",
color: .orange,
disabled: false
) {
showPowerModePopover.toggle()
}
.frame(width: 22)
.popover(isPresented: $showPowerModePopover, arrowEdge: .bottom) {
PowerModePopover()
}
} else {
RecorderToggleButton(
isEnabled: enhancementService.isEnhancementEnabled,
icon: enhancementService.activePrompt?.icon.rawValue ?? "brain",
color: .blue,
disabled: false
) {
if enhancementService.isEnhancementEnabled {
showEnhancementPromptPopover.toggle()
} else {
enhancementService.isEnhancementEnabled = true
}
}
.frame(width: 22)
.popover(isPresented: $showEnhancementPromptPopover, arrowEdge: .bottom) {
EnhancementPromptPopover()
.environmentObject(enhancementService)
}
}
}
}
private var centerSection: some View {
Rectangle()
.fill(Color.clear)
@ -97,7 +59,7 @@ struct NotchRecorderView: View {
}
private var rightSection: some View {
HStack(spacing: 0) {
HStack(spacing: 8) {
Spacer()
statusDisplay
}

View File

@ -99,6 +99,71 @@ struct ProcessingIndicator: View {
}
}
// MARK: - Prompt Button Component
struct RecorderPromptButton: View {
@EnvironmentObject private var enhancementService: AIEnhancementService
@Binding var showPopover: Bool
let buttonSize: CGFloat
let padding: EdgeInsets
init(showPopover: Binding<Bool>, buttonSize: CGFloat = 24, padding: EdgeInsets = EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 0)) {
self._showPopover = showPopover
self.buttonSize = buttonSize
self.padding = padding
}
var body: some View {
RecorderToggleButton(
isEnabled: enhancementService.isEnhancementEnabled,
icon: enhancementService.activePrompt?.icon.rawValue ?? "brain",
color: .blue,
disabled: false
) {
if enhancementService.isEnhancementEnabled {
showPopover.toggle()
} else {
enhancementService.isEnhancementEnabled = true
}
}
.frame(width: buttonSize)
.padding(padding)
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
EnhancementPromptPopover()
.environmentObject(enhancementService)
}
}
}
// MARK: - Power Mode Button Component
struct RecorderPowerModeButton: View {
@ObservedObject private var powerModeManager = PowerModeManager.shared
@Binding var showPopover: Bool
let buttonSize: CGFloat
let padding: EdgeInsets
init(showPopover: Binding<Bool>, buttonSize: CGFloat = 24, padding: EdgeInsets = EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8)) {
self._showPopover = showPopover
self.buttonSize = buttonSize
self.padding = padding
}
var body: some View {
RecorderToggleButton(
isEnabled: !powerModeManager.enabledConfigurations.isEmpty,
icon: powerModeManager.currentActiveConfiguration?.emoji ?? "⚙️",
color: .orange,
disabled: powerModeManager.enabledConfigurations.isEmpty
) {
showPopover.toggle()
}
.frame(width: buttonSize)
.padding(padding)
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
PowerModePopover()
}
}
}
// MARK: - Status Display Component
struct RecorderStatusDisplay: View {
let currentState: RecordingState