import SwiftUI // MARK: - 扫描界面覆盖层 struct ScanningOverlayView: View { let showPreviewPause: Bool let detectedCodesCount: Int let onImageDecode: () -> Void var body: some View { VStack { Spacer() // 扫描线组件 if !showPreviewPause { ScanningLineView(style: .modern) } // 提示文本 ScanningInstructionView( showPreviewPause: showPreviewPause, detectedCodesCount: detectedCodesCount ) Spacer() // 底部按钮区域 ScanningBottomButtonsView( showPreviewPause: showPreviewPause, onImageDecode: onImageDecode ) } } } // MARK: - 扫描指令视图 struct ScanningInstructionView: View { @EnvironmentObject var languageManager: LanguageManager let showPreviewPause: Bool let detectedCodesCount: Int var body: some View { if showPreviewPause { VStack(spacing: 8) { Text("detected_codes".localized) .foregroundColor(.white) .font(.headline) .id(languageManager.refreshTrigger) if detectedCodesCount == 1 { Text("auto_result_1s".localized) .foregroundColor(.green) .font(.subheadline) .id(languageManager.refreshTrigger) } else { Text("select_code_instruction".localized) .foregroundColor(.white.opacity(0.8)) .font(.subheadline) .id(languageManager.refreshTrigger) } } .padding(.top, 20) } else { Text("scan_instruction".localized) .foregroundColor(.white) .font(.headline) .padding(.top, 20) .id(languageManager.refreshTrigger) } } } // MARK: - 扫描底部按钮视图 struct ScanningBottomButtonsView: View { let showPreviewPause: Bool let onImageDecode: () -> Void var body: some View { VStack(spacing: 15) { // 图片解码按钮 if !showPreviewPause { Button(action: { onImageDecode() }) { HStack(spacing: 8) { Image(systemName: "photo.on.rectangle.angled") .font(.system(size: 16, weight: .semibold)) Text("image_decode".localized) .font(.subheadline) .fontWeight(.medium) } .foregroundColor(.white) .padding(.horizontal, 16) .padding(.vertical, 10) .background( RoundedRectangle(cornerRadius: 12) .fill(Color.blue.opacity(0.3)) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(Color.blue.opacity(0.6), lineWidth: 1) ) ) } .buttonStyle(PlainButtonStyle()) } // 移除关闭按钮,因为现在使用导航返回 } .padding(.bottom, 50) } } // MARK: - 扫描线样式选择器 struct ScanningStyleSelectorView: View { @EnvironmentObject var languageManager: LanguageManager @Binding var selectedStyle: ScanningLineStyle var body: some View { VStack(spacing: 12) { // 标题 Text("scanning_line_style".localized) .font(.caption) .foregroundColor(.white.opacity(0.8)) .padding(.bottom, 4) // 样式选择器 HStack(spacing: 8) { ForEach(ScanningLineStyle.allCases, id: \.self) { style in Button(action: { withAnimation(.easeInOut(duration: 0.2)) { selectedStyle = style } // 添加触觉反馈 let impactFeedback = UIImpactFeedbackGenerator(style: .light) impactFeedback.impactOccurred() }) { VStack(spacing: 4) { // 样式预览 stylePreview(style) .frame(width: 24, height: 24) // 样式名称 Text(style.getLocalizedName(languageManager: languageManager)) .font(.caption2) .foregroundColor(.white) .id(languageManager.refreshTrigger) } .frame(width: 60, height: 50) .background( RoundedRectangle(cornerRadius: 12) .fill(selectedStyle == style ? Color.green.opacity(0.8) : Color.black.opacity(0.6)) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(selectedStyle == style ? Color.green : Color.white.opacity(0.3), lineWidth: selectedStyle == style ? 2 : 1) ) ) } .buttonStyle(PlainButtonStyle()) } } } .padding(.horizontal, 16) .padding(.vertical, 12) .background( RoundedRectangle(cornerRadius: 16) .fill(Color.black.opacity(0.7)) .overlay( RoundedRectangle(cornerRadius: 16) .stroke(Color.white.opacity(0.2), lineWidth: 1) ) ) .padding(.bottom, 10) } // 样式预览 @ViewBuilder private func stylePreview(_ style: ScanningLineStyle) -> some View { switch style { case .modern: Rectangle() .fill( LinearGradient( colors: [.blue, .cyan, .blue], startPoint: .leading, endPoint: .trailing ) ) .frame(width: 20, height: 2) .shadow(color: .blue, radius: 2, x: 0, y: 0) case .classic: Rectangle() .fill(Color.green) .frame(width: 16, height: 2) case .neon: Rectangle() .fill(Color.purple) .frame(width: 18, height: 3) .shadow(color: .purple, radius: 3, x: 0, y: 0) case .minimal: Rectangle() .fill(Color.white) .frame(width: 14, height: 1) case .retro: Rectangle() .fill(Color.orange) .frame(width: 20, height: 2) .overlay( Rectangle() .stroke(Color.yellow, lineWidth: 0.5) .frame(width: 18, height: 1.5) ) } } }