feat: 拍照使用头像
This commit is contained in:
parent
e539bb37d2
commit
534c38cd8b
Binary file not shown.
@ -20,6 +20,10 @@
|
||||
</array>
|
||||
<key>NSAppleIDUsageDescription</key>
|
||||
<string>Sign in with Apple is used to authenticate your account</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>We need access to your camera to take photos</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>We need access to your photo library to select photos</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>Inter.ttf</string>
|
||||
|
||||
70
wake/View/Components/Upload/ImageCaptureView.swift
Normal file
70
wake/View/Components/Upload/ImageCaptureView.swift
Normal file
@ -0,0 +1,70 @@
|
||||
import AVFoundation
|
||||
import UIKit
|
||||
|
||||
class ImageCaptureManager: NSObject {
|
||||
static let shared = ImageCaptureManager()
|
||||
private var completion: ((UIImage?) -> Void)?
|
||||
private weak var presentingViewController: UIViewController?
|
||||
|
||||
func captureImage(from viewController: UIViewController, completion: @escaping (UIImage?) -> Void) {
|
||||
self.completion = completion
|
||||
self.presentingViewController = viewController
|
||||
|
||||
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
|
||||
switch status {
|
||||
case .authorized:
|
||||
presentImagePicker()
|
||||
case .notDetermined:
|
||||
AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
|
||||
DispatchQueue.main.async {
|
||||
if granted {
|
||||
self?.presentImagePicker()
|
||||
} else {
|
||||
self?.completion?(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentImagePicker() {
|
||||
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
|
||||
completion?(nil)
|
||||
return
|
||||
}
|
||||
|
||||
let picker = UIImagePickerController()
|
||||
picker.sourceType = .camera
|
||||
picker.allowsEditing = true
|
||||
picker.delegate = self
|
||||
|
||||
// Present from the topmost view controller
|
||||
var topController = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.rootViewController
|
||||
while let presentedVC = topController?.presentedViewController {
|
||||
topController = presentedVC
|
||||
}
|
||||
|
||||
topController?.present(picker, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension ImageCaptureManager: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
|
||||
func imagePickerController(_ picker: UIImagePickerController,
|
||||
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
|
||||
let image = info[.editedImage] as? UIImage ?? info[.originalImage] as? UIImage
|
||||
picker.dismiss(animated: true) { [weak self] in
|
||||
self?.completion?(image)
|
||||
self?.completion = nil
|
||||
}
|
||||
}
|
||||
|
||||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
picker.dismiss(animated: true) { [weak self] in
|
||||
self?.completion?(nil)
|
||||
self?.completion = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ import SwiftUI
|
||||
public struct AvatarPicker: View {
|
||||
@StateObject private var uploadManager = MediaUploadManager()
|
||||
@State private var showMediaPicker = false
|
||||
@State private var showImageCapture = false
|
||||
@State private var isUploading = false
|
||||
@Binding var selectedImage: UIImage?
|
||||
@Binding var showUsername: Bool
|
||||
@ -12,7 +13,10 @@ public struct AvatarPicker: View {
|
||||
// Animation state
|
||||
@State private var isAnimating = false
|
||||
|
||||
public init(selectedImage: Binding<UIImage?>, showUsername: Binding<Bool>, isKeyboardVisible: Binding<Bool>, uploadedFileId: Binding<String?>) {
|
||||
public init(selectedImage: Binding<UIImage?>,
|
||||
showUsername: Binding<Bool>,
|
||||
isKeyboardVisible: Binding<Bool>,
|
||||
uploadedFileId: Binding<String?>) {
|
||||
self._selectedImage = selectedImage
|
||||
self._showUsername = showUsername
|
||||
self._isKeyboardVisible = isKeyboardVisible
|
||||
@ -139,6 +143,35 @@ public struct AvatarPicker: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
if !showUsername {
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
showImageCapture = true
|
||||
}
|
||||
}) {
|
||||
Text("Take a Photo")
|
||||
.font(Typography.font(for: .subtitle, family: .inter))
|
||||
.fontWeight(.regular)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.foregroundColor(.black)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(Color.themePrimaryLight)
|
||||
)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.sheet(isPresented: $showImageCapture) {
|
||||
CameraView(isPresented: $showImageCapture) { image in
|
||||
selectedImage = image
|
||||
uploadManager.selectedMedia = [.image(image)]
|
||||
withAnimation {
|
||||
isUploading = true
|
||||
}
|
||||
uploadManager.startUpload()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
30
wake/View/Owner/UserInfo/CameraView.swift
Normal file
30
wake/View/Owner/UserInfo/CameraView.swift
Normal file
@ -0,0 +1,30 @@
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
struct CameraView: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
let onImageSelected: (UIImage) -> Void
|
||||
@Environment(\.presentationMode) private var presentationMode
|
||||
|
||||
func makeUIViewController(context: Context) -> UIViewController {
|
||||
let viewController = UIViewController()
|
||||
viewController.view.backgroundColor = .clear
|
||||
return viewController
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
|
||||
if isPresented {
|
||||
DispatchQueue.main.async {
|
||||
if let rootVC = UIApplication.shared.windows.first?.rootViewController {
|
||||
ImageCaptureManager.shared.captureImage(from: rootVC) { image in
|
||||
if let image = image {
|
||||
onImageSelected(image)
|
||||
}
|
||||
isPresented = false
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,23 +109,6 @@ struct UserInfo: View {
|
||||
)
|
||||
.padding(.top, isKeyboardVisible ? 0 : 20)
|
||||
|
||||
if !showUsername {
|
||||
Button(action: {
|
||||
// Action for second button
|
||||
}) {
|
||||
Text("Take a Photo")
|
||||
.font(Typography.font(for: .subtitle, family: .inter))
|
||||
.fontWeight(.regular)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.foregroundColor(.black)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(Color.themePrimaryLight)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if showUsername {
|
||||
TextField("Username", text: $userName)
|
||||
.font(Typography.font(for: .subtitle, family: .inter))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user