|
|
@@ -45,6 +45,10 @@ struct ActiveRecordingView: View {
|
|
|
// Dynamic clean background
|
|
|
Color.spaceBlack
|
|
|
.ignoresSafeArea()
|
|
|
+ .contentShape(Rectangle())
|
|
|
+ .onTapGesture(count: 2) {
|
|
|
+ endRecording()
|
|
|
+ }
|
|
|
|
|
|
VStack(spacing: 0) {
|
|
|
recordNameSection
|
|
|
@@ -76,8 +80,8 @@ struct ActiveRecordingView: View {
|
|
|
.padding(.horizontal, 48)
|
|
|
.padding(.bottom, 32)
|
|
|
|
|
|
- // End Recording
|
|
|
- endRecordingButton
|
|
|
+ // Recording Controls
|
|
|
+ recordingControlButtons
|
|
|
.padding(.bottom, 24)
|
|
|
}
|
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
|
|
@@ -238,16 +242,16 @@ struct ActiveRecordingView: View {
|
|
|
TimelineView(.periodic(from: .now, by: 1.0)) { context in
|
|
|
let isEven = Int(context.date.timeIntervalSince1970) % 2 == 0
|
|
|
Circle()
|
|
|
- .fill(recordingVM.isRecording ? Color.recordingRed : Color.secondary)
|
|
|
+ .fill(recordingVM.isRecording && !recordingVM.isPaused ? Color.recordingRed : Color.secondary)
|
|
|
.frame(width: 8, height: 8)
|
|
|
- .opacity(recordingVM.isRecording ? (isEven ? 1.0 : 0.3) : 0.6)
|
|
|
+ .opacity(recordingVM.isRecording && !recordingVM.isPaused ? (isEven ? 1.0 : 0.3) : 0.6)
|
|
|
.animation(.easeInOut(duration: 0.5), value: isEven)
|
|
|
}
|
|
|
.frame(width: 10, height: 10)
|
|
|
|
|
|
Text(recordingVM.isPaused ? "已暂停" : recordingVM.statusMessage)
|
|
|
.font(.system(size: 11, weight: .semibold, design: .monospaced))
|
|
|
- .foregroundStyle(recordingVM.isRecording ? Color.recordingRed : Color.secondary)
|
|
|
+ .foregroundStyle(recordingVM.isRecording && !recordingVM.isPaused ? Color.recordingRed : Color.secondary)
|
|
|
.tracking(1.2)
|
|
|
}
|
|
|
|
|
|
@@ -387,33 +391,64 @@ struct ActiveRecordingView: View {
|
|
|
.buttonStyle(.plain)
|
|
|
}
|
|
|
|
|
|
- // MARK: - End Recording Button
|
|
|
+ // MARK: - Recording Controls
|
|
|
|
|
|
- private var endRecordingButton: some View {
|
|
|
- Button {
|
|
|
- endRecording()
|
|
|
- } label: {
|
|
|
- VStack(spacing: 6) {
|
|
|
- Text("双击结束录制")
|
|
|
- .font(.system(size: 13, weight: .medium))
|
|
|
- .foregroundStyle(Color.recordingRed)
|
|
|
- .padding(.horizontal, 24)
|
|
|
- .padding(.vertical, 10)
|
|
|
- .businessBorder(cornerRadius: 8)
|
|
|
-
|
|
|
- Text("双击即可完成本次现场录音")
|
|
|
- .font(.system(size: 8, weight: .medium, design: .monospaced))
|
|
|
- .foregroundStyle(Color.secondary.opacity(0.5))
|
|
|
- .tracking(1.5)
|
|
|
+ private var recordingControlButtons: some View {
|
|
|
+ HStack(spacing: 52) {
|
|
|
+ recordingControlButton(
|
|
|
+ icon: recordingVM.isPaused ? "play.fill" : "pause.fill",
|
|
|
+ label: recordingVM.isPaused ? "继续记录" : "暂停",
|
|
|
+ tint: .primary
|
|
|
+ ) {
|
|
|
+ toggleRecordingPause()
|
|
|
}
|
|
|
- }
|
|
|
- .highPriorityGesture(
|
|
|
- TapGesture(count: 2).onEnded {
|
|
|
+
|
|
|
+ recordingControlButton(
|
|
|
+ icon: "stop.fill",
|
|
|
+ label: isEndingRecording ? "正在结束" : "结束记录",
|
|
|
+ tint: .recordingRed,
|
|
|
+ isProminent: true
|
|
|
+ ) {
|
|
|
endRecording()
|
|
|
}
|
|
|
- )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func recordingControlButton(
|
|
|
+ icon: String,
|
|
|
+ label: String,
|
|
|
+ tint: Color,
|
|
|
+ isProminent: Bool = false,
|
|
|
+ action: @escaping () -> Void
|
|
|
+ ) -> some View {
|
|
|
+ Button(action: action) {
|
|
|
+ VStack(spacing: 9) {
|
|
|
+ ZStack {
|
|
|
+ Circle()
|
|
|
+ .fill(isProminent ? tint : Color.primary.opacity(0.02))
|
|
|
+ .frame(width: 64, height: 64)
|
|
|
+
|
|
|
+ if !isProminent {
|
|
|
+ Circle()
|
|
|
+ .stroke(Color.primary.opacity(0.18), lineWidth: 1)
|
|
|
+ .frame(width: 64, height: 64)
|
|
|
+ }
|
|
|
+
|
|
|
+ Image(systemName: icon)
|
|
|
+ .font(.system(size: 21, weight: .semibold))
|
|
|
+ .foregroundStyle(isProminent ? Color.white : tint)
|
|
|
+ }
|
|
|
+
|
|
|
+ Text(label)
|
|
|
+ .font(.system(size: 11, weight: .medium))
|
|
|
+ .foregroundStyle(tint)
|
|
|
+ }
|
|
|
+ .frame(width: 88)
|
|
|
+ }
|
|
|
.buttonStyle(.plain)
|
|
|
.disabled(isEndingRecording)
|
|
|
+ .opacity(isEndingRecording && !isProminent ? 0.4 : 1)
|
|
|
+ .accessibilityLabel(label)
|
|
|
}
|
|
|
|
|
|
// MARK: - Note Input Sheet
|
|
|
@@ -501,6 +536,17 @@ struct ActiveRecordingView: View {
|
|
|
showNoteSheet = false
|
|
|
}
|
|
|
|
|
|
+ private func toggleRecordingPause() {
|
|
|
+ guard !isEndingRecording else { return }
|
|
|
+ HapticManager.trigger(.tapFeedback)
|
|
|
+
|
|
|
+ if recordingVM.isPaused {
|
|
|
+ recordingVM.resumeRecording()
|
|
|
+ } else {
|
|
|
+ recordingVM.pauseRecording()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private func endRecording() {
|
|
|
guard !isEndingRecording else { return }
|
|
|
commitRecordName()
|