* ios: video support * made video experience prettier * line reordering * fix warning * remove playback speed * fullscreen player * removed unused code * fix conflict * setting playing status better * thumbnail dimensions and loading indicator * fill under video --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
205 lines
7.6 KiB
Swift
205 lines
7.6 KiB
Swift
//
|
|
// ImagePicker.swift
|
|
// SimpleX
|
|
//
|
|
// Created by Evgeny on 23/03/2022.
|
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
import PhotosUI
|
|
import SwiftyGif
|
|
import SimpleXChat
|
|
|
|
struct LibraryImagePicker: View {
|
|
@Binding var image: UIImage?
|
|
var didFinishPicking: (_ didSelectItems: Bool) -> Void
|
|
@State var images: [UploadContent] = []
|
|
|
|
var body: some View {
|
|
LibraryMediaListPicker(media: $images, selectionLimit: 1, didFinishPicking: didFinishPicking)
|
|
.onChange(of: images) { _ in
|
|
if let img = images.first {
|
|
image = img.uiImage
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct LibraryMediaListPicker: UIViewControllerRepresentable {
|
|
typealias UIViewControllerType = PHPickerViewController
|
|
@AppStorage(GROUP_DEFAULT_XFTP_SEND_ENABLED, store: groupDefaults) var xftpSendEnabled = false
|
|
@Binding var media: [UploadContent]
|
|
var selectionLimit: Int
|
|
var didFinishPicking: (_ didSelectItems: Bool) -> Void
|
|
|
|
class Coordinator: PHPickerViewControllerDelegate {
|
|
let parent: LibraryMediaListPicker
|
|
let dispatchQueue = DispatchQueue(label: "chat.simplex.app.LibraryMediaListPicker")
|
|
var media: [UploadContent] = []
|
|
var mediaCount: Int = 0
|
|
|
|
init(_ parent: LibraryMediaListPicker) {
|
|
self.parent = parent
|
|
}
|
|
|
|
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
|
parent.didFinishPicking(!results.isEmpty)
|
|
guard !results.isEmpty else {
|
|
return
|
|
}
|
|
|
|
parent.media = []
|
|
media = []
|
|
mediaCount = results.count
|
|
for result in results {
|
|
logger.log("LibraryMediaListPicker result")
|
|
let p = result.itemProvider
|
|
if p.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
|
|
p.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { url, error in
|
|
if let url = url {
|
|
let tempUrl = URL(fileURLWithPath: getTempFilesDirectory().path + "/" + generateNewFileName("video", url.pathExtension))
|
|
if ((try? FileManager.default.copyItem(at: url, to: tempUrl)) != nil) {
|
|
ChatModel.shared.filesToDelete.insert(tempUrl)
|
|
self.loadVideo(url: tempUrl, error: error)
|
|
}
|
|
}
|
|
}
|
|
} else if p.hasItemConformingToTypeIdentifier(UTType.data.identifier) {
|
|
p.loadFileRepresentation(forTypeIdentifier: UTType.data.identifier) { url, error in
|
|
self.loadImage(object: url, error: error)
|
|
}
|
|
} else if p.canLoadObject(ofClass: UIImage.self) {
|
|
p.loadObject(ofClass: UIImage.self) { image, error in
|
|
DispatchQueue.main.async {
|
|
self.loadImage(object: image, error: error)
|
|
}
|
|
}
|
|
} else {
|
|
dispatchQueue.sync { self.mediaCount -= 1}
|
|
}
|
|
}
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
|
|
self.dispatchQueue.sync {
|
|
if self.parent.media.count == 0 {
|
|
logger.log("LibraryMediaListPicker: added \(self.media.count) images out of \(results.count)")
|
|
self.parent.media = self.media
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func loadImage(object: Any?, error: Error? = nil) {
|
|
if let error = error {
|
|
logger.error("LibraryMediaListPicker: couldn't load image with error: \(error.localizedDescription)")
|
|
} else if let image = object as? UIImage {
|
|
media.append(.simpleImage(image: image))
|
|
logger.log("LibraryMediaListPicker: added image")
|
|
} else if let url = object as? URL, let image = UploadContent.loadFromURL(url: url) {
|
|
media.append(image)
|
|
}
|
|
dispatchQueue.sync {
|
|
self.mediaCount -= 1
|
|
if self.mediaCount == 0 && self.parent.media.count == 0 {
|
|
logger.log("LibraryMediaListPicker: added all media")
|
|
self.parent.media = self.media
|
|
self.media = []
|
|
}
|
|
}
|
|
}
|
|
|
|
func loadVideo(url: URL?, error: Error? = nil) {
|
|
if let error = error {
|
|
logger.error("LibraryMediaListPicker: couldn't load video with error: \(error.localizedDescription)")
|
|
} else if let url = url as URL?, let video = UploadContent.loadVideoFromURL(url: url) {
|
|
media.append(video)
|
|
}
|
|
dispatchQueue.sync {
|
|
self.mediaCount -= 1
|
|
if self.mediaCount == 0 && self.parent.media.count == 0 {
|
|
logger.log("LibraryMediaListPicker: added all media")
|
|
self.parent.media = self.media
|
|
self.media = []
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(self)
|
|
}
|
|
|
|
func makeUIViewController(context: Context) -> PHPickerViewController {
|
|
var config = PHPickerConfiguration()
|
|
let allowVideoAttachment = xftpSendEnabled
|
|
if allowVideoAttachment {
|
|
config.filter = .any(of: [.images, .videos])
|
|
} else {
|
|
config.filter = .images
|
|
}
|
|
config.selectionLimit = selectionLimit
|
|
config.selection = .ordered
|
|
//config.preferredAssetRepresentationMode = .current
|
|
let controller = PHPickerViewController(configuration: config)
|
|
controller.delegate = context.coordinator
|
|
return controller
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
|
|
|
|
}
|
|
}
|
|
|
|
struct CameraImageListPicker: View {
|
|
@Binding var images: [UploadContent]
|
|
@State var image: UIImage?
|
|
|
|
var body: some View {
|
|
CameraImagePicker(image: $image)
|
|
.onChange(of: image) { img in
|
|
if let img = img {
|
|
images = [UploadContent.simpleImage(image: img)]
|
|
} else {
|
|
images = []
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct CameraImagePicker: UIViewControllerRepresentable {
|
|
@Environment(\.presentationMode) var presentationMode
|
|
@Binding var image: UIImage?
|
|
|
|
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
|
|
let parent: CameraImagePicker
|
|
|
|
init(_ parent: CameraImagePicker) {
|
|
self.parent = parent
|
|
}
|
|
|
|
func imagePickerController(_ picker: UIImagePickerController,
|
|
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
|
|
if let uiImage = info[.originalImage] as? UIImage {
|
|
parent.image = uiImage
|
|
}
|
|
parent.presentationMode.wrappedValue.dismiss()
|
|
}
|
|
}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(self)
|
|
}
|
|
|
|
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraImagePicker>) -> UIImagePickerController {
|
|
let picker = UIImagePickerController()
|
|
picker.sourceType = .camera
|
|
picker.allowsEditing = false
|
|
picker.delegate = context.coordinator
|
|
return picker
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<CameraImagePicker>) {
|
|
|
|
}
|
|
}
|