Redesign recorder views with reusable components
This commit is contained in:
parent
36f33e5a83
commit
f7987cd4bd
@ -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;
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user