mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Camera and editor improvements
This commit is contained in:
parent
b7e25ec8e7
commit
340001788e
@ -2533,6 +2533,15 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
}
|
||||
|
||||
public func transitionViewForOwnStoryItem() -> UIView? {
|
||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||
return transitionView
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func animateStoryUploadRipple() {
|
||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||
|
@ -602,6 +602,9 @@ public extension MediaEditorValues {
|
||||
}
|
||||
|
||||
var requiresComposing: Bool {
|
||||
if self.originalDimensions.width > self.originalDimensions.height {
|
||||
return true
|
||||
}
|
||||
if abs(1.0 - self.cropScale) > 0.0 {
|
||||
return true
|
||||
}
|
||||
|
@ -519,21 +519,7 @@ public final class MediaEditorVideoExport {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// let progress = (CMSampleBufferGetPresentationTimeStamp(buffer) - self.configuration.timeRange.start).seconds/self.duration.seconds
|
||||
// if self.videoOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateVideoEncodingProgress(fractionCompleted: progress) }
|
||||
// }
|
||||
// if self.audioOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateAudioEncodingProgress(fractionCompleted: progress) }
|
||||
// }
|
||||
|
||||
} else {
|
||||
// if self.videoOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateVideoEncodingProgress(fractionCompleted: 1) }
|
||||
// }
|
||||
// if self.audioOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateAudioEncodingProgress(fractionCompleted: 1) }
|
||||
// }
|
||||
writer.markVideoAsFinished()
|
||||
return false
|
||||
}
|
||||
@ -553,24 +539,11 @@ public final class MediaEditorVideoExport {
|
||||
}
|
||||
self.pauseDispatchGroup.wait()
|
||||
if let buffer = output.copyNextSampleBuffer() {
|
||||
// let progress = (CMSampleBufferGetPresentationTimeStamp(buffer) - self.configuration.timeRange.start).seconds/self.duration.seconds
|
||||
// if self.videoOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateVideoEncodingProgress(fractionCompleted: progress) }
|
||||
// }
|
||||
// if self.audioOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateAudioEncodingProgress(fractionCompleted: progress) }
|
||||
// }
|
||||
if !writer.appendVideoBuffer(buffer) {
|
||||
if !writer.appendAudioBuffer(buffer) {
|
||||
writer.markAudioAsFinished()
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// if self.videoOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateVideoEncodingProgress(fractionCompleted: 1) }
|
||||
// }
|
||||
// if self.audioOutput === output {
|
||||
// self.dispatchProgressCallback { $0.updateAudioEncodingProgress(fractionCompleted: 1) }
|
||||
// }
|
||||
writer.markAudioAsFinished()
|
||||
return false
|
||||
}
|
||||
|
@ -385,11 +385,20 @@ final class MediaEditorScreenComponent: Component {
|
||||
image: state.image(.done),
|
||||
size: CGSize(width: 33.0, height: 33.0)
|
||||
)),
|
||||
action: {
|
||||
guard let controller = environment.controller() as? MediaEditorScreen else {
|
||||
action: { [weak self] in
|
||||
guard let self, let controller = environment.controller() as? MediaEditorScreen else {
|
||||
return
|
||||
}
|
||||
controller.requestCompletion(animated: true)
|
||||
guard let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View else {
|
||||
return
|
||||
}
|
||||
var inputText = NSAttributedString(string: "")
|
||||
switch inputPanelView.getSendMessageInput() {
|
||||
case let .text(text):
|
||||
inputText = NSAttributedString(string: text)
|
||||
}
|
||||
|
||||
controller.requestCompletion(caption: inputText, animated: true)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
@ -687,6 +696,38 @@ final class MediaEditorScreenComponent: Component {
|
||||
private let storyDimensions = CGSize(width: 1080.0, height: 1920.0)
|
||||
|
||||
public final class MediaEditorScreen: ViewController {
|
||||
public final class TransitionIn {
|
||||
public weak var sourceView: UIView?
|
||||
public let sourceRect: CGRect
|
||||
public let sourceCornerRadius: CGFloat
|
||||
|
||||
public init(
|
||||
sourceView: UIView,
|
||||
sourceRect: CGRect,
|
||||
sourceCornerRadius: CGFloat
|
||||
) {
|
||||
self.sourceView = sourceView
|
||||
self.sourceRect = sourceRect
|
||||
self.sourceCornerRadius = sourceCornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
public final class TransitionOut {
|
||||
public weak var destinationView: UIView?
|
||||
public let destinationRect: CGRect
|
||||
public let destinationCornerRadius: CGFloat
|
||||
|
||||
public init(
|
||||
destinationView: UIView,
|
||||
destinationRect: CGRect,
|
||||
destinationCornerRadius: CGFloat
|
||||
) {
|
||||
self.destinationView = destinationView
|
||||
self.destinationRect = destinationRect
|
||||
self.destinationCornerRadius = destinationCornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
|
||||
private weak var controller: MediaEditorScreen?
|
||||
private let context: AccountContext
|
||||
@ -935,11 +976,44 @@ public final class MediaEditorScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
func animateOut(finished: Bool, completion: @escaping () -> Void) {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
if let sourceHint = controller.sourceHint {
|
||||
if let transitionOut = controller.transitionOut(finished), let destinationView = transitionOut.destinationView {
|
||||
let destinationLocalFrame = destinationView.convert(transitionOut.destinationRect, to: self.view)
|
||||
|
||||
let targetScale = destinationLocalFrame.width / self.previewContainerView.frame.width
|
||||
self.previewContainerView.layer.animatePosition(from: self.previewContainerView.center, to: destinationLocalFrame.center, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
self.previewContainerView.layer.animateScale(from: 1.0, to: targetScale, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
self.previewContainerView.layer.animateBounds(from: self.previewContainerView.bounds, to: CGRect(origin: CGPoint(x: 0.0, y: (self.previewContainerView.frame.height - self.previewContainerView.frame.width) / 2.0), size: CGSize(width: self.previewContainerView.bounds.width, height: self.previewContainerView.bounds.width)), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
self.previewContainerView.layer.animate(
|
||||
from: self.previewContainerView.layer.cornerRadius as NSNumber,
|
||||
to: self.previewContainerView.bounds.width / 2.0 as NSNumber,
|
||||
keyPath: "cornerRadius",
|
||||
timingFunction: kCAMediaTimingFunctionSpring,
|
||||
duration: 0.4,
|
||||
removeOnCompletion: false
|
||||
)
|
||||
|
||||
if let componentView = self.componentHost.view {
|
||||
componentView.clipsToBounds = true
|
||||
componentView.layer.animatePosition(from: componentView.center, to: destinationLocalFrame.center, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
componentView.layer.animateScale(from: 1.0, to: targetScale, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
componentView.layer.animateBounds(from: componentView.bounds, to: CGRect(origin: CGPoint(x: 0.0, y: (componentView.frame.height - componentView.frame.width) / 2.0), size: CGSize(width: componentView.bounds.width, height: componentView.bounds.width)), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
componentView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
componentView.layer.animate(
|
||||
from: componentView.layer.cornerRadius as NSNumber,
|
||||
to: componentView.bounds.width / 2.0 as NSNumber,
|
||||
keyPath: "cornerRadius",
|
||||
timingFunction: kCAMediaTimingFunctionSpring,
|
||||
duration: 0.4,
|
||||
removeOnCompletion: false
|
||||
)
|
||||
}
|
||||
} else if let sourceHint = controller.sourceHint {
|
||||
switch sourceHint {
|
||||
case .camera:
|
||||
if let view = self.componentHost.view as? MediaEditorScreenComponent.View {
|
||||
@ -1175,6 +1249,8 @@ public final class MediaEditorScreen: ViewController {
|
||||
|
||||
fileprivate let context: AccountContext
|
||||
fileprivate let subject: Signal<Subject?, NoError>
|
||||
fileprivate let transitionIn: TransitionIn?
|
||||
fileprivate let transitionOut: (Bool) -> TransitionOut?
|
||||
|
||||
public enum SourceHint {
|
||||
case camera
|
||||
@ -1184,9 +1260,17 @@ public final class MediaEditorScreen: ViewController {
|
||||
public var cancelled: () -> Void = {}
|
||||
public var completion: (MediaEditorScreen.Result, @escaping () -> Void) -> Void = { _, _ in }
|
||||
|
||||
public init(context: AccountContext, subject: Signal<Subject?, NoError>, completion: @escaping (MediaEditorScreen.Result, @escaping () -> Void) -> Void) {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
subject: Signal<Subject?, NoError>,
|
||||
transitionIn: TransitionIn?,
|
||||
transitionOut: @escaping (Bool) -> TransitionOut?,
|
||||
completion: @escaping (MediaEditorScreen.Result, @escaping () -> Void) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
self.transitionIn = transitionIn
|
||||
self.transitionOut = transitionOut
|
||||
self.completion = completion
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
@ -1210,12 +1294,12 @@ public final class MediaEditorScreen: ViewController {
|
||||
func requestDismiss(animated: Bool) {
|
||||
self.cancelled()
|
||||
|
||||
self.node.animateOut(completion: { [weak self] in
|
||||
self.node.animateOut(finished: false, completion: { [weak self] in
|
||||
self?.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
func requestCompletion(animated: Bool) {
|
||||
func requestCompletion(caption: NSAttributedString, animated: Bool) {
|
||||
guard let mediaEditor = self.node.mediaEditor, let subject = self.node.subject else {
|
||||
return
|
||||
}
|
||||
@ -1250,8 +1334,8 @@ public final class MediaEditorScreen: ViewController {
|
||||
duration = 5.0
|
||||
}
|
||||
}
|
||||
self.completion(.video(video: videoResult, coverImage: nil, values: mediaEditor.values, duration: duration, dimensions: PixelDimensions(width: 1080, height: 1920), caption: nil), { [weak self] in
|
||||
self?.node.animateOut(completion: { [weak self] in
|
||||
self.completion(.video(video: videoResult, coverImage: nil, values: mediaEditor.values, duration: duration, dimensions: PixelDimensions(width: 1080, height: 1920), caption: caption), { [weak self] in
|
||||
self?.node.animateOut(finished: true, completion: { [weak self] in
|
||||
self?.dismiss()
|
||||
})
|
||||
})
|
||||
@ -1259,8 +1343,8 @@ public final class MediaEditorScreen: ViewController {
|
||||
if let image = mediaEditor.resultImage {
|
||||
makeEditorImageComposition(account: self.context.account, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, completion: { resultImage in
|
||||
if let resultImage {
|
||||
self.completion(.image(image: resultImage, dimensions: PixelDimensions(resultImage.size), caption: nil), { [weak self] in
|
||||
self?.node.animateOut(completion: { [weak self] in
|
||||
self.completion(.image(image: resultImage, dimensions: PixelDimensions(resultImage.size), caption: caption), { [weak self] in
|
||||
self?.node.animateOut(finished: true, completion: { [weak self] in
|
||||
self?.dismiss()
|
||||
})
|
||||
})
|
||||
|
@ -210,7 +210,13 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
return nil
|
||||
}
|
||||
if finished {
|
||||
|
||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let transitionView = chatListController.transitionViewForOwnStoryItem() {
|
||||
return StoryCameraTransitionOut(
|
||||
destinationView: transitionView,
|
||||
destinationRect: transitionView.bounds,
|
||||
destinationCornerRadius: transitionView.bounds.height / 2.0
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if let cameraItemView = self.rootTabController?.viewForCameraItem() {
|
||||
return StoryCameraTransitionOut(
|
||||
@ -221,18 +227,6 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
}
|
||||
}
|
||||
return nil
|
||||
// if finished {
|
||||
// return nil
|
||||
// } else {
|
||||
// if let self, let cameraItemView = self.rootTabController?.viewForCameraItem() {
|
||||
// return StoryCameraTransitionOut(
|
||||
// destinationView: cameraItemView,
|
||||
// destinationRect: cameraItemView.bounds,
|
||||
// destinationCornerRadius: cameraItemView.bound.height / 2.0
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -344,114 +338,68 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
return .asset(asset)
|
||||
}
|
||||
}
|
||||
let controller = MediaEditorScreen(context: context, subject: subject, completion: { mediaResult, commit in
|
||||
enum AdditionalCategoryId: Int {
|
||||
case everyone
|
||||
case contacts
|
||||
case closeFriends
|
||||
}
|
||||
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
|
||||
let additionalCategories: [ChatListNodeAdditionalCategory] = [
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.everyone.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Channel"), color: .white), cornerRadius: nil, color: .blue),
|
||||
smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Channel"), color: .white), iconScale: 0.6, cornerRadius: 6.0, circleCorners: true, color: .blue),
|
||||
title: "Everyone",
|
||||
appearance: .option(sectionTitle: "WHO CAN VIEW FOR 24 HOURS")
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.contacts.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Tabs/IconContacts"), color: .white), iconScale: 1.0 * 0.8, cornerRadius: nil, color: .yellow),
|
||||
smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Tabs/IconContacts"), color: .white), iconScale: 0.6 * 0.8, cornerRadius: 6.0, circleCorners: true, color: .yellow),
|
||||
title: presentationData.strings.ChatListFolder_CategoryContacts,
|
||||
appearance: .option(sectionTitle: "WHO CAN VIEW FOR 24 HOURS")
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.closeFriends.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Call/StarHighlighted"), color: .white), iconScale: 1.0 * 0.6, cornerRadius: nil, color: .green),
|
||||
smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Call/StarHighlighted"), color: .white), iconScale: 0.6 * 0.6, cornerRadius: 6.0, circleCorners: true, color: .green),
|
||||
title: "Close Friends",
|
||||
appearance: .option(sectionTitle: "WHO CAN VIEW FOR 24 HOURS")
|
||||
let controller = MediaEditorScreen(context: context, subject: subject, transitionIn: nil, transitionOut: { finished in
|
||||
if finished, let transitionOut = transitionOut(true), let destinationView = transitionOut.destinationView {
|
||||
return MediaEditorScreen.TransitionOut(
|
||||
destinationView: destinationView,
|
||||
destinationRect: transitionOut.destinationRect,
|
||||
destinationCornerRadius: transitionOut.destinationCornerRadius
|
||||
)
|
||||
]
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, completion: { mediaResult, commit in
|
||||
let privacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
|
||||
// if additionalCategoryIds.contains(AdditionalCategoryId.everyone.rawValue) {
|
||||
// privacy.base = .everyone
|
||||
// } else if additionalCategoryIds.contains(AdditionalCategoryId.contacts.rawValue) {
|
||||
// privacy.base = .contacts
|
||||
// } else if additionalCategoryIds.contains(AdditionalCategoryId.closeFriends.rawValue) {
|
||||
// privacy.base = .closeFriends
|
||||
// }
|
||||
// privacy.additionallyIncludePeers = peerIds.compactMap { id -> EnginePeer.Id? in
|
||||
// switch id {
|
||||
// case let .peer(peerId):
|
||||
// return peerId
|
||||
// default:
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
|
||||
let selectionController = self.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: self.context, mode: .chatSelection(ContactMultiselectionControllerMode.ChatSelection(
|
||||
title: "Share Story",
|
||||
searchPlaceholder: "Search contacts",
|
||||
selectedChats: Set(),
|
||||
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: Set([AdditionalCategoryId.everyone.rawValue])),
|
||||
chatListFilters: nil,
|
||||
displayPresence: true
|
||||
)), options: [], filters: [.excludeSelf], alwaysEnabled: true, limit: 1000, reachedLimit: { _ in
|
||||
}))
|
||||
selectionController.navigationPresentation = .modal
|
||||
self.pushViewController(selectionController)
|
||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let storyListContext = chatListController.storyListContext {
|
||||
switch mediaResult {
|
||||
case let .image(image, dimensions, caption):
|
||||
if let data = image.jpegData(compressionQuality: 0.8) {
|
||||
storyListContext.upload(media: .image(dimensions: dimensions, data: data), text: caption?.string ?? "", entities: [], privacy: privacy)
|
||||
Queue.mainQueue().after(0.3, { [weak chatListController] in
|
||||
chatListController?.animateStoryUploadRipple()
|
||||
})
|
||||
}
|
||||
case let .video(content, _, values, duration, dimensions, caption):
|
||||
let adjustments: VideoMediaResourceAdjustments
|
||||
if let valuesData = try? JSONEncoder().encode(values) {
|
||||
let data = MemoryBuffer(data: valuesData)
|
||||
let digest = MemoryBuffer(data: data.md5Digest())
|
||||
adjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: true)
|
||||
|
||||
let _ = (selectionController.result
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak selectionController] result in
|
||||
guard case let .result(peerIds, additionalCategoryIds) = result else {
|
||||
selectionController?.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
var privacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
|
||||
if additionalCategoryIds.contains(AdditionalCategoryId.everyone.rawValue) {
|
||||
privacy.base = .everyone
|
||||
} else if additionalCategoryIds.contains(AdditionalCategoryId.contacts.rawValue) {
|
||||
privacy.base = .contacts
|
||||
} else if additionalCategoryIds.contains(AdditionalCategoryId.closeFriends.rawValue) {
|
||||
privacy.base = .closeFriends
|
||||
}
|
||||
privacy.additionallyIncludePeers = peerIds.compactMap { id -> EnginePeer.Id? in
|
||||
switch id {
|
||||
case let .peer(peerId):
|
||||
return peerId
|
||||
default:
|
||||
return nil
|
||||
let resource: TelegramMediaResource
|
||||
switch content {
|
||||
case let .imageFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .videoFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .asset(localIdentifier):
|
||||
resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments))
|
||||
}
|
||||
storyListContext.upload(media: .video(dimensions: dimensions, duration: Int(duration), resource: resource), text: caption?.string ?? "", entities: [], privacy: privacy)
|
||||
Queue.mainQueue().after(0.3, { [weak chatListController] in
|
||||
chatListController?.animateStoryUploadRipple()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
selectionController?.displayProgress = true
|
||||
|
||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let storyListContext = chatListController.storyListContext {
|
||||
switch mediaResult {
|
||||
case let .image(image, dimensions, _):
|
||||
if let data = image.jpegData(compressionQuality: 0.8) {
|
||||
storyListContext.upload(media: .image(dimensions: dimensions, data: data), text: "", entities: [], privacy: privacy)
|
||||
Queue.mainQueue().after(0.3, { [weak chatListController] in
|
||||
chatListController?.animateStoryUploadRipple()
|
||||
})
|
||||
}
|
||||
case let .video(content, _, values, duration, dimensions, _):
|
||||
let adjustments: VideoMediaResourceAdjustments
|
||||
if let valuesData = try? JSONEncoder().encode(values) {
|
||||
let data = MemoryBuffer(data: valuesData)
|
||||
let digest = MemoryBuffer(data: data.md5Digest())
|
||||
adjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: true)
|
||||
|
||||
let resource: TelegramMediaResource
|
||||
switch content {
|
||||
case let .imageFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .videoFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .asset(localIdentifier):
|
||||
resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments))
|
||||
}
|
||||
storyListContext.upload(media: .video(dimensions: dimensions, duration: Int(duration), resource: resource), text: "", entities: [], privacy: privacy)
|
||||
Queue.mainQueue().after(0.3, { [weak chatListController] in
|
||||
chatListController?.animateStoryUploadRipple()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
dismissCameraImpl?()
|
||||
commit()
|
||||
selectionController?.dismiss()
|
||||
})
|
||||
}
|
||||
dismissCameraImpl?()
|
||||
commit()
|
||||
})
|
||||
controller.sourceHint = .camera
|
||||
controller.cancelled = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user