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.

262 lines
8.6 KiB

import SwiftUI
import CoreData
import Photos
struct QRCodeSavedView: View {
@EnvironmentObject var languageManager: LanguageManager
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("qr_code_saved_title".localized)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("return_home".localized) {
// ContentView
shouldPopToRoot = true
}
}
}
.sheet(isPresented: $showingShareSheet) {
ShareSheet(activityItems: [qrCodeImage])
}
.alert("tip".localized, isPresented: $showingAlert) {
Button("confirm".localized) { }
} 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("scan_this_qr_code".localized)
.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("share".localized)
.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 ? "saving".localized : "save".localized)
.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("add_to_picture".localized)
.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 = "qr_code_saved_to_photos".localized
} else {
self.alertMessage = String(format: "save_failed".localized, error?.localizedDescription ?? "unknown_error".localized)
}
self.showingAlert = true
}
}
}
private func showPermissionAlert() {
alertMessage = "photo_permission_required".localized
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())
.environmentObject(LanguageManager.shared)
}