- Implement three-pane Xcode-style layout with toggleable sidebars - Refactor into modular components for better maintainability - Replace tabbed interface with iMessage-style message bubbles - Redesign audio player for 70% height reduction with horizontal layout - Update to native macOS colors and remove custom backgrounds - Increase minimum window size to 1000x700 for better usability
101 lines
3.4 KiB
Swift
101 lines
3.4 KiB
Swift
import SwiftUI
|
|
|
|
struct TranscriptionDetailView: View {
|
|
let transcription: Transcription
|
|
|
|
private var hasAudioFile: Bool {
|
|
if let urlString = transcription.audioFileURL,
|
|
let url = URL(string: urlString),
|
|
FileManager.default.fileExists(atPath: url.path) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(spacing: 12) {
|
|
ScrollView {
|
|
VStack(spacing: 16) {
|
|
MessageBubble(
|
|
label: "Original",
|
|
text: transcription.text,
|
|
isEnhanced: false
|
|
)
|
|
|
|
if let enhancedText = transcription.enhancedText {
|
|
MessageBubble(
|
|
label: "Enhanced",
|
|
text: enhancedText,
|
|
isEnhanced: true
|
|
)
|
|
}
|
|
}
|
|
.padding(16)
|
|
}
|
|
|
|
if hasAudioFile, let urlString = transcription.audioFileURL,
|
|
let url = URL(string: urlString) {
|
|
VStack(spacing: 0) {
|
|
Divider()
|
|
|
|
AudioPlayerView(url: url)
|
|
.padding(.horizontal, 10)
|
|
.padding(.vertical, 6)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
|
.fill(Color(NSColor.controlBackgroundColor).opacity(0.5))
|
|
)
|
|
.padding(.horizontal, 12)
|
|
.padding(.top, 6)
|
|
}
|
|
}
|
|
}
|
|
.padding(.vertical, 12)
|
|
.background(Color(NSColor.controlBackgroundColor))
|
|
}
|
|
}
|
|
|
|
private struct MessageBubble: View {
|
|
let label: String
|
|
let text: String
|
|
let isEnhanced: Bool
|
|
|
|
var body: some View {
|
|
HStack(alignment: .bottom) {
|
|
if isEnhanced { Spacer(minLength: 60) }
|
|
|
|
VStack(alignment: isEnhanced ? .leading : .trailing, spacing: 4) {
|
|
Text(label)
|
|
.font(.system(size: 9, weight: .medium))
|
|
.foregroundColor(.secondary.opacity(0.7))
|
|
.padding(.horizontal, 12)
|
|
|
|
ScrollView {
|
|
Text(text)
|
|
.font(.system(size: 14, weight: .regular))
|
|
.lineSpacing(2)
|
|
.textSelection(.enabled)
|
|
.padding(.horizontal, 12)
|
|
.padding(.vertical, 10)
|
|
}
|
|
.frame(maxHeight: 350)
|
|
.background {
|
|
if isEnhanced {
|
|
RoundedRectangle(cornerRadius: 18, style: .continuous)
|
|
.fill(Color.accentColor.opacity(0.2))
|
|
} else {
|
|
RoundedRectangle(cornerRadius: 18, style: .continuous)
|
|
.fill(.thinMaterial)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 18, style: .continuous)
|
|
.strokeBorder(Color.primary.opacity(0.06), lineWidth: 0.5)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
if !isEnhanced { Spacer(minLength: 60) }
|
|
}
|
|
}
|
|
}
|