feat: 拍照使用头像
This commit is contained in:
parent
e539bb37d2
commit
534c38cd8b
Binary file not shown.
@ -20,6 +20,10 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>NSAppleIDUsageDescription</key>
|
<key>NSAppleIDUsageDescription</key>
|
||||||
<string>Sign in with Apple is used to authenticate your account</string>
|
<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>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Inter.ttf</string>
|
<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 {
|
public struct AvatarPicker: View {
|
||||||
@StateObject private var uploadManager = MediaUploadManager()
|
@StateObject private var uploadManager = MediaUploadManager()
|
||||||
@State private var showMediaPicker = false
|
@State private var showMediaPicker = false
|
||||||
|
@State private var showImageCapture = false
|
||||||
@State private var isUploading = false
|
@State private var isUploading = false
|
||||||
@Binding var selectedImage: UIImage?
|
@Binding var selectedImage: UIImage?
|
||||||
@Binding var showUsername: Bool
|
@Binding var showUsername: Bool
|
||||||
@ -12,7 +13,10 @@ public struct AvatarPicker: View {
|
|||||||
// Animation state
|
// Animation state
|
||||||
@State private var isAnimating = false
|
@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._selectedImage = selectedImage
|
||||||
self._showUsername = showUsername
|
self._showUsername = showUsername
|
||||||
self._isKeyboardVisible = isKeyboardVisible
|
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)
|
.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 {
|
if showUsername {
|
||||||
TextField("Username", text: $userName)
|
TextField("Username", text: $userName)
|
||||||
.font(Typography.font(for: .subtitle, family: .inter))
|
.font(Typography.font(for: .subtitle, family: .inter))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user