You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
8.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import SwiftUI
import CoreData
import Photos
struct QRCodeSavedView: View {
let qrCodeImage: UIImage
let qrCodeContent: String
let qrCodeType: QRCodeType
let styleData: QRCodeStyleData?
let historyItem: HistoryItem?
@Environment(\.dismiss) private var dismiss
@EnvironmentObject var coreDataManager: CoreDataManager
@Environment(\.presentationMode) private var presentationMode
@State private var shouldReturnToRoot = false
@State private var shouldPopToRoot = false
@State private var showingShareSheet = false
@State private var showingAlert = false
@State private var alertMessage = ""
@State private var isSavingToPhotos = false
@State private var showingImageComposer = false
@State private var showingBackgroundImagePicker = false
@State private var selectedBackgroundImage: UIImage?
//
private let photoSaver = PhotoSaver()
var body: some View {
VStack(spacing: 30) {
//
qrCodeImageView
//
actionButtonsSection
Spacer()
}
.padding()
.navigationTitle("二维码已保存")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("返回主页") {
// ContentView
shouldPopToRoot = true
}
}
}
.sheet(isPresented: $showingShareSheet) {
ShareSheet(activityItems: [qrCodeImage])
}
.alert("提示", isPresented: $showingAlert) {
Button("确定") { }
} message: {
Text(alertMessage)
}
.background(
NavigationLink(
destination: ContentView()
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true),
isActive: $shouldPopToRoot
) {
EmptyView()
}
)
.sheet(isPresented: $showingBackgroundImagePicker) {
ImagePicker(
onImageSelected: { image in
selectedBackgroundImage = image
showingImageComposer = true
},
shouldProcessImage: false
)
}
.sheet(isPresented: $showingImageComposer) {
if let backgroundImage = selectedBackgroundImage {
ImageComposerView(qrCodeImage: qrCodeImage, backgroundImage: backgroundImage)
}
}
}
// MARK: -
private var qrCodeImageView: some View {
VStack(spacing: 16) {
Image(uiImage: qrCodeImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300, height: 300)
.cornerRadius(16)
.shadow(radius: 10)
Text("扫描此二维码")
.font(.headline)
.foregroundColor(.secondary)
}
}
// MARK: -
private var actionButtonsSection: some View {
HStack(spacing: 12) {
//
Button(action: {
showingShareSheet = true
}) {
VStack(spacing: 8) {
Image(systemName: "square.and.arrow.up")
.font(.title2)
Text("分享")
.font(.caption)
.fontWeight(.medium)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(12)
}
//
Button(action: saveToPhotos) {
VStack(spacing: 8) {
if isSavingToPhotos {
ProgressView()
.scaleEffect(0.8)
.foregroundColor(.white)
} else {
Image(systemName: "photo")
.font(.title2)
}
Text(isSavingToPhotos ? "保存中..." : "保存")
.font(.caption)
.fontWeight(.medium)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(12)
}
.disabled(isSavingToPhotos)
//
Button(action: addToPhotos) {
VStack(spacing: 8) {
Image(systemName: "plus.rectangle.on.folder")
.font(.title2)
Text("添加到图片")
.font(.caption)
.fontWeight(.medium)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(Color.orange)
.foregroundColor(.white)
.cornerRadius(12)
}
}
}
// MARK: -
private func saveToPhotos() {
isSavingToPhotos = true
//
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized, .limited:
saveImageToPhotos()
case .notDetermined:
PHPhotoLibrary.requestAuthorization { newStatus in
DispatchQueue.main.async {
if newStatus == .authorized || newStatus == .limited {
self.saveImageToPhotos()
} else {
self.showPermissionAlert()
}
self.isSavingToPhotos = false
}
}
case .denied, .restricted:
DispatchQueue.main.async {
self.showPermissionAlert()
self.isSavingToPhotos = false
}
@unknown default:
DispatchQueue.main.async {
self.showPermissionAlert()
self.isSavingToPhotos = false
}
}
}
private func saveImageToPhotos() {
photoSaver.saveImage(qrCodeImage) { success, error in
DispatchQueue.main.async {
self.isSavingToPhotos = false
if success {
self.alertMessage = "二维码已保存到相册"
} else {
self.alertMessage = "保存失败:\(error?.localizedDescription ?? "未知错误")"
}
self.showingAlert = true
}
}
}
private func showPermissionAlert() {
alertMessage = "需要相册权限才能保存图片,请在设置中开启"
showingAlert = true
}
// MARK: -
private func addToPhotos() {
//
showingBackgroundImagePicker = true
}
}
// MARK: -
class PhotoSaver: NSObject {
func saveImage(_ image: UIImage, completion: @escaping (Bool, Error?) -> Void) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
self.completion = completion
}
private var completion: ((Bool, Error?) -> Void)?
@objc private func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
completion?(error == nil, error)
}
}
#Preview {
let sampleImage = UIImage(systemName: "qrcode") ?? UIImage()
let sampleStyleData = QRCodeStyleData(
foregroundColor: "black",
backgroundColor: "white",
dotType: "square",
eyeType: "square",
logo: nil,
hasCustomLogo: false,
customLogoFileName: nil
)
return QRCodeSavedView(
qrCodeImage: sampleImage,
qrCodeContent: "https://example.com",
qrCodeType: .url,
styleData: sampleStyleData,
historyItem: nil
)
.environmentObject(CoreDataManager())
}