Various improvements

This commit is contained in:
Ilya Laktyushin 2023-07-12 18:45:25 +02:00
parent 148947a0e9
commit 7b15dbe31c
13 changed files with 264 additions and 132 deletions

View File

@ -366,17 +366,17 @@ private final class CameraContext {
|> map { first, second in
return first && second
}
|> filter { $0 }
|> take(1)
|> delay(0.1, queue: self.queue)
|> deliverOn(self.queue)).start(next: { [weak self] _ in
|> filter { $0 }
|> take(1)
|> delay(0.1, queue: self.queue)
|> deliverOn(self.queue)).start(next: { [weak self] _ in
self?.modeChange = .none
})
} else {
let _ = (previewView.isPreviewing
|> filter { $0 }
|> take(1)
|> deliverOn(self.queue)).start(next: { [weak self] _ in
|> filter { $0 }
|> take(1)
|> deliverOn(self.queue)).start(next: { [weak self] _ in
self?.modeChange = .none
})
}

View File

@ -75,7 +75,6 @@ final class CameraOutput: NSObject {
let videoOutput = AVCaptureVideoDataOutput()
let audioOutput = AVCaptureAudioDataOutput()
let metadataOutput = AVCaptureMetadataOutput()
private let faceLandmarksOutput = FaceLandmarksDataOutput()
let exclusive: Bool
@ -85,17 +84,12 @@ final class CameraOutput: NSObject {
private let queue = DispatchQueue(label: "")
private let metadataQueue = DispatchQueue(label: "")
private let faceLandmarksQueue = DispatchQueue(label: "")
private var photoCaptureRequests: [Int64: PhotoCaptureContext] = [:]
private var videoRecorder: VideoRecorder?
var activeFilter: CameraFilter?
var faceLandmarks: Bool = false
var processSampleBuffer: ((CMSampleBuffer, CVImageBuffer, AVCaptureConnection) -> Void)?
var processCodes: (([CameraCode]) -> Void)?
var processFaceLandmarks: (([VNFaceObservation]) -> Void)?
init(exclusive: Bool) {
self.exclusive = exclusive
@ -104,12 +98,6 @@ final class CameraOutput: NSObject {
self.videoOutput.alwaysDiscardsLateVideoFrames = false
self.videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] as [String : Any]
self.faceLandmarksOutput.outputFaceObservations = { [weak self] observations in
if let self {
self.processFaceLandmarks?(observations)
}
}
}
deinit {
@ -273,7 +261,7 @@ final class CameraOutput: NSObject {
}
let uniqueId = settings.uniqueID
let photoCapture = PhotoCaptureContext(settings: settings, filter: self.activeFilter, mirror: mirror)
let photoCapture = PhotoCaptureContext(settings: settings, filter: nil, mirror: mirror)
self.photoCaptureRequests[uniqueId] = photoCapture
self.photoOutput.capturePhoto(with: settings, delegate: photoCapture)
@ -361,32 +349,10 @@ extension CameraOutput: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureA
return
}
if self.faceLandmarks {
self.faceLandmarksQueue.async {
self.faceLandmarksOutput.process(sampleBuffer: sampleBuffer)
}
}
if let videoPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
self.processSampleBuffer?(sampleBuffer, videoPixelBuffer, connection)
}
// let finalSampleBuffer: CMSampleBuffer = sampleBuffer
// if let videoPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer), let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
// var finalVideoPixelBuffer = videoPixelBuffer
// if let filter = self.activeFilter {
// if !filter.isPrepared {
// filter.prepare(with: formatDescription, outputRetainedBufferCountHint: 3)
// }
//
// guard let filteredBuffer = filter.render(pixelBuffer: finalVideoPixelBuffer) else {
// return
// }
// finalVideoPixelBuffer = filteredBuffer
// }
// self.processSampleBuffer?(finalVideoPixelBuffer, connection)
// }
if let videoRecorder = self.videoRecorder, videoRecorder.isRecording {
videoRecorder.appendSampleBuffer(sampleBuffer)
}

View File

@ -2975,6 +2975,8 @@ public final class DrawingToolsInteraction {
private var isActive = false
private var validLayout: ContainerViewLayout?
private let startTimestamp = CACurrentMediaTime()
public init(
context: AccountContext,
drawingView: DrawingView,
@ -3126,6 +3128,10 @@ public final class DrawingToolsInteraction {
if let textEntityView = entityView as? DrawingTextEntityView {
textEntityView.beginEditing(accessoryView: self.textEditAccessoryView)
} else {
if self.isVideo {
entityView.seek(to: 0.0)
}
entityView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
entityView.layer.animateScale(from: 0.1, to: entity.scale, duration: 0.2)

View File

@ -43,7 +43,8 @@ swift_library(
"//submodules/MoreButtonNode:MoreButtonNode",
"//submodules/InvisibleInkDustNode:InvisibleInkDustNode",
"//submodules/TelegramUI/Components/CameraScreen",
"//submodules/TelegramUI/Components/MediaEditor",
"//submodules/TelegramUI/Components/MediaEditor",
"//submodules/RadialStatusNode",
],
visibility = [
"//visibility:public",

View File

@ -17,7 +17,7 @@ final class AssetDownloadManager {
let identifier: String
let updated: () -> Void
var status: AssetDownloadStatus = .progress(0.0)
var status: AssetDownloadStatus = .none
var disposable: Disposable?
init(identifier: String, updated: @escaping () -> Void) {
@ -40,9 +40,7 @@ final class AssetDownloadManager {
}
func download(asset: PHAsset) {
if let currentAssetContext = self.currentAssetContext {
currentAssetContext.disposable?.dispose()
}
self.cancelAllDownloads()
let queue = self.queue
let identifier = asset.localIdentifier
@ -59,6 +57,7 @@ final class AssetDownloadManager {
}
}
})
self.currentAssetContext = assetContext
assetContext.disposable = (downloadAssetMediaData(asset)
|> deliverOn(queue)).start(next: { [weak self] status in
guard let self else {
@ -69,13 +68,31 @@ final class AssetDownloadManager {
currentAssetContext.updated()
}
})
self.currentAssetContext = assetContext
}
func cancelAllDownloads() {
if let currentAssetContext = self.currentAssetContext {
currentAssetContext.status = .none
currentAssetContext.updated()
currentAssetContext.disposable?.dispose()
self.queue.justDispatch {
if self.currentAssetContext === currentAssetContext {
self.currentAssetContext = nil
}
}
}
}
func cancel(identifier: String) {
if let currentAssetContext = self.currentAssetContext, currentAssetContext.identifier == identifier {
currentAssetContext.status = .none
currentAssetContext.updated()
currentAssetContext.disposable?.dispose()
self.currentAssetContext = nil
self.queue.justDispatch {
if self.currentAssetContext === currentAssetContext {
self.currentAssetContext = nil
}
}
}
}
@ -93,7 +110,7 @@ final class AssetDownloadManager {
if let currentAssetContext = self.currentAssetContext, currentAssetContext.identifier == identifier {
next(currentAssetContext.status)
} else {
next(.progress(0.0))
next(.none)
}
let queue = self.queue
@ -129,27 +146,35 @@ final class AssetDownloadManager {
}
func checkIfAssetIsLocal(_ asset: PHAsset) -> Signal<Bool, NoError> {
if asset.isLocallyAvailable == true {
return .single(true)
}
return Signal { subscriber in
let options = PHImageRequestOptions()
options.isNetworkAccessAllowed = false
let requestId: PHImageRequestID
if #available(iOS 13, *) {
requestId = imageManager.requestImageDataAndOrientation(for: asset, options: options) { data, _, _, _ in
if data != nil {
subscriber.putNext(data != nil)
}
if case .video = asset.mediaType {
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = false
requestId = imageManager.requestAVAsset(forVideo: asset, options: options) { asset, _, _ in
subscriber.putNext(asset != nil)
subscriber.putCompletion()
}
} else {
requestId = imageManager.requestImageData(for: asset, options: options) { data, _, _, _ in
if data != nil {
let options = PHImageRequestOptions()
options.isNetworkAccessAllowed = false
if #available(iOS 13, *) {
requestId = imageManager.requestImageDataAndOrientation(for: asset, options: options) { data, _, _, _ in
subscriber.putNext(data != nil)
subscriber.putCompletion()
}
} else {
requestId = imageManager.requestImageData(for: asset, options: options) { data, _, _, _ in
subscriber.putNext(data != nil)
subscriber.putCompletion()
}
subscriber.putCompletion()
}
}
return ActionDisposable {
imageManager.cancelImageRequest(requestId)
}
@ -157,32 +182,57 @@ func checkIfAssetIsLocal(_ asset: PHAsset) -> Signal<Bool, NoError> {
}
enum AssetDownloadStatus {
case none
case progress(Float)
case completed
}
private func downloadAssetMediaData(_ asset: PHAsset) -> Signal<AssetDownloadStatus, NoError> {
return Signal { subscriber in
let options = PHImageRequestOptions()
options.isNetworkAccessAllowed = true
options.progressHandler = { progress, _, _, _ in
subscriber.putNext(.progress(Float(progress)))
}
let requestId: PHImageRequestID
if #available(iOS 13, *) {
requestId = imageManager.requestImageDataAndOrientation(for: asset, options: options) { data, _, _, _ in
if data != nil {
if case .video = asset.mediaType {
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true
options.progressHandler = { progress, _, _, _ in
subscriber.putNext(.progress(Float(progress)))
}
subscriber.putNext(.progress(0.0))
requestId = imageManager.requestAVAsset(forVideo: asset, options: options) { asset, _, _ in
if asset != nil {
subscriber.putNext(.completed)
} else {
subscriber.putNext(.none)
}
subscriber.putCompletion()
}
} else {
requestId = imageManager.requestImageData(for: asset, options: options) { data, _, _, _ in
if data != nil {
subscriber.putNext(.completed)
let options = PHImageRequestOptions()
options.isNetworkAccessAllowed = true
options.progressHandler = { progress, _, _, _ in
subscriber.putNext(.progress(Float(progress)))
}
subscriber.putNext(.progress(0.0))
if #available(iOS 13, *) {
requestId = imageManager.requestImageDataAndOrientation(for: asset, options: options) { data, _, _, _ in
if data != nil {
subscriber.putNext(.completed)
} else {
subscriber.putNext(.none)
}
subscriber.putCompletion()
}
} else {
requestId = imageManager.requestImageData(for: asset, options: options) { data, _, _, _ in
if data != nil {
subscriber.putNext(.completed)
} else {
subscriber.putNext(.none)
}
subscriber.putCompletion()
}
subscriber.putCompletion()
}
}

View File

@ -16,6 +16,7 @@ import InvisibleInkDustNode
import ImageBlur
import FastBlur
import MediaEditor
import RadialStatusNode
enum MediaPickerGridItemContent: Equatable {
case asset(PHFetchResult<PHAsset>, Int)
@ -90,7 +91,9 @@ private let maskImage = generateImage(CGSize(width: 1.0, height: 36.0), opaque:
final class MediaPickerGridItemNode: GridItemNode {
var currentMediaState: (TGMediaSelectableItem, Int)?
var currentState: (PHFetchResult<PHAsset>, Int)?
var currentAssetState: (PHFetchResult<PHAsset>, Int)?
var currentAsset: PHAsset?
var currentDraftState: (MediaEditorDraft, Int)?
var enableAnimations: Bool = true
var stories: Bool = false
@ -103,6 +106,7 @@ final class MediaPickerGridItemNode: GridItemNode {
private let typeIconNode: ASImageNode
private let durationNode: ImmediateTextNode
private let draftNode: ImmediateTextNode
private var statusNode: RadialStatusNode?
private let activateAreaNode: AccessibilityAreaNode
@ -112,6 +116,8 @@ final class MediaPickerGridItemNode: GridItemNode {
private let spoilerDisposable = MetaDisposable()
var spoilerNode: SpoilerOverlayNode?
private let progressDisposable = MetaDisposable()
private var currentIsPreviewing = false
var selected: (() -> Void)?
@ -140,7 +146,7 @@ final class MediaPickerGridItemNode: GridItemNode {
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.image]
super.init()
self.clipsToBounds = true
@ -168,7 +174,7 @@ final class MediaPickerGridItemNode: GridItemNode {
var selectableItem: TGMediaSelectableItem? {
if let (media, _) = self.currentMediaState {
return media
} else if let (fetchResult, index) = self.currentState {
} else if let (fetchResult, index) = self.currentAssetState {
return TGMediaAsset(phAsset: fetchResult[index])
} else {
return nil
@ -179,7 +185,7 @@ final class MediaPickerGridItemNode: GridItemNode {
var tag: Int32? {
if let tag = self._cachedTag {
return tag
} else if let (fetchResult, index) = self.currentState {
} else if let (fetchResult, index) = self.currentAssetState {
let asset = fetchResult.object(at: index)
if let localTimestamp = asset.creationDate?.timeIntervalSince1970 {
let tag = Month(localTimestamp: Int32(localTimestamp)).packedValue
@ -251,6 +257,32 @@ final class MediaPickerGridItemNode: GridItemNode {
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
}
func updateProgress(_ value: Float?, animated: Bool) {
if let value {
let statusNode: RadialStatusNode
if let current = self.statusNode {
statusNode = current
} else {
statusNode = RadialStatusNode(backgroundNodeColor: UIColor(rgb: 0x000000, alpha: 0.6))
statusNode.isUserInteractionEnabled = false
self.addSubnode(statusNode)
self.statusNode = statusNode
}
let adjustedProgress = max(0.027, CGFloat(value))
let state: RadialStatusNodeState = .progress(color: .white, lineWidth: nil, value: adjustedProgress, cancelEnabled: true, animateRotation: true)
statusNode.transitionToState(state)
} else if let statusNode = self.statusNode {
self.statusNode = nil
if animated {
statusNode.transitionToState(.none, animated: true, completion: { [weak statusNode] in
statusNode?.removeFromSupernode()
})
} else {
statusNode.removeFromSupernode()
}
}
}
func setup(interaction: MediaPickerInteraction, draft: MediaEditorDraft, index: Int, theme: PresentationTheme, selectable: Bool, enableAnimations: Bool, stories: Bool) {
self.interaction = interaction
self.theme = theme
@ -259,14 +291,18 @@ final class MediaPickerGridItemNode: GridItemNode {
self.backgroundColor = theme.list.mediaPlaceholderColor
if self.currentDraftState == nil || self.currentDraftState?.0.path != draft.path || self.currentDraftState!.1 != index || self.currentState != nil {
if self.currentDraftState == nil || self.currentDraftState?.0.path != draft.path || self.currentDraftState!.1 != index || self.currentAssetState != nil {
let imageSignal: Signal<UIImage?, NoError> = .single(draft.thumbnail)
self.imageNode.setSignal(imageSignal)
self.currentDraftState = (draft, index)
if self.currentState != nil {
self.currentState = nil
if self.currentAssetState != nil {
self.currentAsset = nil
self.currentAssetState = nil
self.typeIconNode.removeFromSupernode()
self.progressDisposable.set(nil)
self.updateProgress(nil, animated: false)
}
if self.draftNode.supernode == nil {
@ -354,11 +390,30 @@ final class MediaPickerGridItemNode: GridItemNode {
self.draftNode.removeFromSupernode()
}
if self.currentState == nil || self.currentState!.0 !== fetchResult || self.currentState!.1 != index || self.currentDraftState != nil {
self.backgroundNode.image = nil
if self.currentAssetState == nil || self.currentAssetState!.0 !== fetchResult || self.currentAssetState!.1 != index || self.currentDraftState != nil {
let editingContext = interaction.editingState
let asset = fetchResult.object(at: index)
if asset.localIdentifier == self.currentAsset?.localIdentifier {
return
}
self.progressDisposable.set(
(interaction.downloadManager.downloadProgress(identifier: asset.localIdentifier)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let self {
switch status {
case .none, .completed:
self.updateProgress(nil, animated: true)
case let .progress(progress):
self.updateProgress(progress, animated: true)
}
}
})
)
self.backgroundNode.image = nil
if #available(iOS 15.0, *) {
self.activateAreaNode.accessibilityLabel = "Photo \(asset.creationDate?.formatted(date: .abbreviated, time: .standard) ?? "")"
}
@ -489,7 +544,8 @@ final class MediaPickerGridItemNode: GridItemNode {
}
}
self.currentState = (fetchResult, index)
self.currentAssetState = (fetchResult, index)
self.currentAsset = asset
self.setNeedsLayout()
}
@ -554,6 +610,11 @@ final class MediaPickerGridItemNode: GridItemNode {
spoilerNode.frame = self.bounds
spoilerNode.update(size: self.bounds.size, transition: .immediate)
}
let statusSize = CGSize(width: 40.0, height: 40.0)
if let statusNode = self.statusNode {
statusNode.view.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.bounds.width - statusSize.width) / 2.0), y: floorToScreenPixels((self.bounds.height - statusSize.height) / 2.0)), size: statusSize)
}
}
func transitionView(snapshot: Bool) -> UIView {
@ -589,10 +650,16 @@ final class MediaPickerGridItemNode: GridItemNode {
self.interaction?.openDraft(draft, self.imageNode.image)
return
}
guard let (fetchResult, index) = self.currentState else {
guard let (fetchResult, index) = self.currentAssetState else {
return
}
self.interaction?.openMedia(fetchResult, index, self.imageNode.image)
if self.statusNode != nil {
if let asset = self.currentAsset {
self.interaction?.downloadManager.cancel(identifier: asset.localIdentifier)
}
} else {
self.interaction?.openMedia(fetchResult, index, self.imageNode.image)
}
}
}

View File

@ -25,6 +25,7 @@ import CameraScreen
import MediaEditor
final class MediaPickerInteraction {
let downloadManager: AssetDownloadManager
let openMedia: (PHFetchResult<PHAsset>, Int, UIImage?) -> Void
let openSelectedMedia: (TGMediaSelectableItem, UIImage?) -> Void
let openDraft: (MediaEditorDraft, UIImage?) -> Void
@ -36,7 +37,8 @@ final class MediaPickerInteraction {
let editingState: TGMediaEditingContext
var hiddenMediaId: String?
init(openMedia: @escaping (PHFetchResult<PHAsset>, Int, UIImage?) -> Void, openSelectedMedia: @escaping (TGMediaSelectableItem, UIImage?) -> Void, openDraft: @escaping (MediaEditorDraft, UIImage?) -> Void, toggleSelection: @escaping (TGMediaSelectableItem, Bool, Bool) -> Bool, sendSelected: @escaping (TGMediaSelectableItem?, Bool, Int32?, Bool, @escaping () -> Void) -> Void, schedule: @escaping () -> Void, dismissInput: @escaping () -> Void, selectionState: TGMediaSelectionContext?, editingState: TGMediaEditingContext) {
init(downloadManager: AssetDownloadManager, openMedia: @escaping (PHFetchResult<PHAsset>, Int, UIImage?) -> Void, openSelectedMedia: @escaping (TGMediaSelectableItem, UIImage?) -> Void, openDraft: @escaping (MediaEditorDraft, UIImage?) -> Void, toggleSelection: @escaping (TGMediaSelectableItem, Bool, Bool) -> Bool, sendSelected: @escaping (TGMediaSelectableItem?, Bool, Int32?, Bool, @escaping () -> Void) -> Void, schedule: @escaping () -> Void, dismissInput: @escaping () -> Void, selectionState: TGMediaSelectionContext?, editingState: TGMediaEditingContext) {
self.downloadManager = downloadManager
self.openMedia = openMedia
self.openSelectedMedia = openSelectedMedia
self.openDraft = openDraft
@ -393,6 +395,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.selectionChangedDisposable?.dispose()
self.itemsDimensionsUpdatedDisposable?.dispose()
self.fastScrollDisposable?.dispose()
self.currentAssetDownloadDisposable.dispose()
}
override func didLoad() {
@ -777,8 +780,29 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
private weak var currentGalleryController: TGModernGalleryController?
private func requestAssetDownload(_ asset: PHAsset) {
fileprivate var currentAssetDownloadDisposable = MetaDisposable()
fileprivate func cancelAssetDownloads() {
guard let downloadManager = self.controller?.downloadManager else {
return
}
self.currentAssetDownloadDisposable.set(nil)
downloadManager.cancelAllDownloads()
}
fileprivate func requestAssetDownload(asset: PHAsset) {
guard let downloadManager = self.controller?.downloadManager else {
return
}
downloadManager.download(asset: asset)
self.currentAssetDownloadDisposable.set(
(downloadManager.downloadProgress(identifier: asset.localIdentifier)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let self, case .completed = status, let controller = self.controller, let customSelection = self.controller?.customSelection {
customSelection(controller, asset)
}
})
)
}
private var openingMedia = false
@ -794,26 +818,19 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.openingMedia = true
let asset = fetchResult[index]
customSelection(controller, asset)
// let isLocallyAvailable = asset.isLocallyAvailable
//
// if let isLocallyAvailable {
// if isLocallyAvailable {
// customSelection(controller, asset)
// } else {
// self.requestAssetDownload(asset)
// }
// } else {
// let _ = (checkIfAssetIsLocal(asset)
// |> deliverOnMainQueue).start(next: { [weak self] isLocallyAvailable in
// if isLocallyAvailable {
// customSelection(controller, asset)
// } else {
// self?.requestAssetDownload(asset)
// }
// })
// }
let _ = (checkIfAssetIsLocal(asset)
|> deliverOnMainQueue).start(next: { [weak self] isLocallyAvailable in
guard let self else {
return
}
if isLocallyAvailable {
self.cancelAssetDownloads()
customSelection(controller, asset)
} else {
self.requestAssetDownload(asset: asset)
}
})
Queue.mainQueue().after(0.3) {
self.openingMedia = false
@ -1365,6 +1382,8 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
private let groupedPromise = ValuePromise<Bool>(true)
private let downloadManager = AssetDownloadManager()
private var isDismissing = false
fileprivate let mainButtonState: AttachmentMainButtonState?
@ -1538,13 +1557,17 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
}
self.interaction = MediaPickerInteraction(openMedia: { [weak self] fetchResult, index, immediateThumbnail in
self.interaction = MediaPickerInteraction(downloadManager: self.downloadManager,
openMedia: { [weak self] fetchResult, index, immediateThumbnail in
self?.controllerNode.openMedia(fetchResult: fetchResult, index: index, immediateThumbnail: immediateThumbnail)
}, openSelectedMedia: { [weak self] item, immediateThumbnail in
},
openSelectedMedia: { [weak self] item, immediateThumbnail in
self?.controllerNode.openSelectedMedia(item: item, immediateThumbnail: immediateThumbnail)
}, openDraft: { [weak self] draft, immediateThumbnail in
},
openDraft: { [weak self] draft, immediateThumbnail in
self?.controllerNode.openDraft(draft: draft, immediateThumbnail: immediateThumbnail)
}, toggleSelection: { [weak self] item, value, suggestUndo in
},
toggleSelection: { [weak self] item, value, suggestUndo in
if let self = self, let selectionState = self.interaction?.selectionState {
if let _ = item as? TGMediaPickerGalleryPhotoItem {
if self.bannedSendPhotos != nil {
@ -1798,7 +1821,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.undoOverlayController?.dismissWithCommitAction()
}
public func requestDismiss(completion: @escaping () -> Void) {
public func requestDismiss(completion: @escaping () -> Void) {
if let selectionState = self.interaction?.selectionState, selectionState.count() > 0 {
self.isDismissing = true
@ -1837,6 +1860,12 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.dismiss()
}
public override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
self.controllerNode.cancelAssetDownloads()
super.dismiss(animated: flag, completion: completion)
}
@objc private func rightButtonPressed() {
self.moreButtonNode.buttonPressed()
}

View File

@ -284,6 +284,7 @@ final class PendingStoryManager {
self.currentPendingItemContext = pendingItemContext
let stableId = firstItem.stableId
Logger.shared.log("PendingStoryManager", "setting up item context for: \(firstItem.stableId) randomId: \(firstItem.randomId)")
pendingItemContext.disposable = (_internal_uploadStoryImpl(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, stateManager: self.stateManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.revalidationContext, auxiliaryMethods: self.auxiliaryMethods, stableId: stableId, media: firstItem.media, text: firstItem.text, entities: firstItem.entities, embeddedStickers: firstItem.embeddedStickers, pin: firstItem.pin, privacy: firstItem.privacy, isForwardingDisabled: firstItem.isForwardingDisabled, period: Int(firstItem.period), randomId: firstItem.randomId)
|> deliverOn(self.queue)).start(next: { [weak self] event in
guard let `self` = self else {

View File

@ -746,6 +746,7 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text:
period: Int32(period),
randomId: randomId
))
Logger.shared.log("UploadStory", "Appended new pending item stableId: \(stableId) randomId: \(randomId)")
transaction.setLocalStoryState(state: CodableEntry(currentState))
}).start()
}
@ -789,6 +790,7 @@ private func _internal_putPendingStoryIdMapping(accountPeerId: PeerId, stableId:
}
func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, auxiliaryMethods: AccountAuxiliaryMethods, stableId: Int32, media: Media, text: String, entities: [MessageTextEntity], embeddedStickers: [TelegramMediaFile], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64) -> Signal<StoryUploadResult, NoError> {
Logger.shared.log("UploadStory", "uploadStoryImpl for stableId: \(stableId) randomId: \(randomId)")
let passFetchProgress = media is TelegramMediaFile
let (contentSignal, originalMedia) = uploadedStoryContent(postbox: postbox, network: network, media: media, embeddedStickers: embeddedStickers, accountPeerId: accountPeerId, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, auxiliaryMethods: auxiliaryMethods, passFetchProgress: passFetchProgress)
return contentSignal

View File

@ -303,6 +303,8 @@ private final class CameraScreenComponent: CombinedComponent {
self.isPressingButton = true
}
self.buttonPressTimestamp = nil
self.buttonPressTimer?.invalidate()
self.buttonPressTimer = nil
}
}, queue: Queue.mainQueue())
self.buttonPressTimer?.start()
@ -641,11 +643,15 @@ private final class CameraScreenComponent: CombinedComponent {
}
controller.presentGallery()
},
swipeHintUpdated: { hint in
state.updateSwipeHint(hint)
swipeHintUpdated: { [weak state] hint in
if let state {
state.updateSwipeHint(hint)
}
},
zoomUpdated: { fraction in
state.updateZoom(fraction: fraction)
zoomUpdated: { [weak state] fraction in
if let state {
state.updateZoom(fraction: fraction)
}
},
flipAnimationAction: animateFlipAction
),
@ -737,10 +743,9 @@ private final class CameraScreenComponent: CombinedComponent {
component: CameraButton(
content: flashContentComponent,
action: { [weak state] in
guard let state else {
return
if let state {
state.toggleFlashMode()
}
state.toggleFlashMode()
}
).tagged(flashButtonTag),
availableSize: CGSize(width: 40.0, height: 40.0),
@ -762,10 +767,9 @@ private final class CameraScreenComponent: CombinedComponent {
)
),
action: { [weak state] in
guard let state else {
return
if let state {
state.toggleDualCamera()
}
state.toggleDualCamera()
}
).tagged(dualButtonTag),
availableSize: CGSize(width: 40.0, height: 40.0),

View File

@ -507,7 +507,9 @@ public final class MediaEditor {
self.onPlaybackAction(.seek(start))
self.player?.play()
self.additionalPlayer?.play()
self.onPlaybackAction(.play)
Queue.mainQueue().justDispatch {
self.onPlaybackAction(.play)
}
}
})
Queue.mainQueue().justDispatch {

View File

@ -3615,6 +3615,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
let fittedSize = resultImage.size.aspectFitted(CGSize(width: 128.0, height: 128.0))
let context = self.context
let saveImageDraft: (UIImage, PixelDimensions) -> Void = { image, dimensions in
if let thumbnailImage = generateScaledImage(image: resultImage, size: fittedSize) {
let path = "\(Int64.random(in: .min ... .max)).jpg"
@ -3622,9 +3623,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let draft = MediaEditorDraft(path: path, isVideo: false, thumbnail: thumbnailImage, dimensions: dimensions, duration: nil, values: values, caption: caption, privacy: privacy, timestamp: timestamp)
try? data.write(to: URL(fileURLWithPath: draft.fullPath()))
if let id {
saveStorySource(engine: self.context.engine, item: draft, id: id)
saveStorySource(engine: context.engine, item: draft, id: id)
} else {
addStoryDraft(engine: self.context.engine, item: draft)
addStoryDraft(engine: context.engine, item: draft)
}
}
}
@ -3636,9 +3637,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let draft = MediaEditorDraft(path: path, isVideo: true, thumbnail: thumbnailImage, dimensions: dimensions, duration: duration, values: values, caption: caption, privacy: privacy, timestamp: timestamp)
try? FileManager.default.moveItem(atPath: videoPath, toPath: draft.fullPath())
if let id {
saveStorySource(engine: self.context.engine, item: draft, id: id)
saveStorySource(engine: context.engine, item: draft, id: id)
} else {
addStoryDraft(engine: self.context.engine, item: draft)
addStoryDraft(engine: context.engine, item: draft)
}
}
}
@ -3861,6 +3862,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if let self {
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: image ?? UIImage(), dimensions: storyDimensions, values: mediaEditor.values, time: .zero, completion: { [weak self] coverImage in
if let self {
Logger.shared.log("Media Editor", "completed with video \(videoResult)")
self.completion(randomId, .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), caption, self.state.privacy, stickers, { [weak self] finished in
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
self?.dismiss()
@ -3883,6 +3885,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, completion: { [weak self] resultImage in
if let self, let resultImage {
Logger.shared.log("Media Editor", "completed with image \(resultImage)")
self.completion(randomId, .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), caption, self.state.privacy, stickers, { [weak self] finished in
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
self?.dismiss()

View File

@ -374,6 +374,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
case let .image(image, dimensions):
if let imageData = compressImageToJPEG(image, quality: 0.7) {
let entities = generateChatInputTextEntities(caption)
Logger.shared.log("MediaEditor", "Calling uploadStory for image, randomId \(randomId)")
self.context.engine.messages.uploadStory(media: .image(dimensions: dimensions, data: imageData, stickers: stickers), text: caption.string, entities: entities, pin: privacy.pin, privacy: privacy.privacy, isForwardingDisabled: privacy.isForwardingDisabled, period: privacy.timeout, randomId: randomId)
Queue.mainQueue().justDispatch {
commit({})
@ -404,7 +405,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
return nil
}
}
Logger.shared.log("MediaEditor", "Calling uploadStory for video, randomId \(randomId)")
let entities = generateChatInputTextEntities(caption)
self.context.engine.messages.uploadStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameFile: firstFrameFile, stickers: stickers), text: caption.string, entities: entities, pin: privacy.pin, privacy: privacy.privacy, isForwardingDisabled: privacy.isForwardingDisabled, period: privacy.timeout, randomId: randomId)
Queue.mainQueue().justDispatch {