import Foundation import Display import TelegramCore import Postbox import SwiftSignalKit import LegacyComponents final class InstantVideoControllerRecordingStatus { let micLevel: Signal init(micLevel: Signal) { self.micLevel = micLevel } } final class InstantVideoController: LegacyController { private var captureController: TGVideoMessageCaptureController? var onDismiss: (() -> Void)? var onStop: (() -> Void)? private let micLevelValue = ValuePromise(0.0) let audioStatus: InstantVideoControllerRecordingStatus private var dismissedVideo = false override init(presentation: LegacyControllerPresentation, theme: PresentationTheme?, presentationData: PresentationData? = nil, initialLayout: ContainerViewLayout? = nil) { self.audioStatus = InstantVideoControllerRecordingStatus(micLevel: self.micLevelValue.get()) super.init(presentation: presentation, theme: theme, initialLayout: initialLayout) } required public init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func bindCaptureController(_ captureController: TGVideoMessageCaptureController?) { self.captureController = captureController if let captureController = captureController { captureController.micLevel = { [weak self] (level: CGFloat) -> Void in self?.micLevelValue.set(Float(level)) } captureController.onDismiss = { [weak self] _ in self?.onDismiss?() } captureController.onStop = { [weak self] in self?.onStop?() } } } func dismissVideo() { if let captureController = self.captureController, !self.dismissedVideo { self.dismissedVideo = true captureController.dismiss() } } func completeVideo() { if let captureController = self.captureController, !self.dismissedVideo { self.dismissedVideo = true captureController.complete() } } func stopVideo() -> Bool { if let captureController = self.captureController { return captureController.stop() } return false } func lockVideo() { if let captureController = self.captureController { return captureController.setLocked() } } func updateRecordButtonInteraction(_ value: CGFloat) { if let captureController = self.captureController { captureController.buttonInteractionUpdate(CGPoint(x: value, y: 0.0)) } } } func legacyInstantVideoController(theme: PresentationTheme, panelFrame: CGRect, account: Account, peerId: PeerId, send: @escaping (EnqueueMessage) -> Void) -> InstantVideoController { let legacyController = InstantVideoController(presentation: .custom, theme: theme) legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait) legacyController.statusBar.statusBarStyle = .Hide let baseController = TGViewController(context: legacyController.context)! legacyController.bind(controller: baseController) legacyController.presentationCompleted = { [weak legacyController, weak baseController] in if let legacyController = legacyController, let baseController = baseController { let inputPanelTheme = theme.chat.inputPanel var uploadInterface: LegacyLiveUploadInterface? if peerId.namespace != Namespaces.Peer.SecretChat { uploadInterface = LegacyLiveUploadInterface(account: account) } let controller = TGVideoMessageCaptureController(context: legacyController.context, assets: TGVideoMessageCaptureControllerAssets(send: PresentationResourcesChat.chatInputPanelSendButtonImage(theme)!, slideToCancel: PresentationResourcesChat.chatInputPanelMediaRecordingCancelArrowImage(theme)!, actionDelete: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionThrash"), color: theme.chat.inputPanel.panelControlAccentColor))!, transitionInView: { return nil }, parentController: baseController, controlsFrame: panelFrame, isAlreadyLocked: { return false }, liveUploadInterface: uploadInterface, pallete: TGModernConversationInputMicPallete(dark: theme.overallDarkAppearance, buttonColor: inputPanelTheme.actionControlFillColor, iconColor: inputPanelTheme.actionControlForegroundColor, backgroundColor: inputPanelTheme.panelBackgroundColor, borderColor: inputPanelTheme.panelStrokeColor, lock: inputPanelTheme.panelControlAccentColor, textColor: inputPanelTheme.primaryTextColor, secondaryTextColor: inputPanelTheme.secondaryTextColor, recording: inputPanelTheme.mediaRecordingDotColor))! controller.finishedWithVideo = { videoUrl, previewImage, _, duration, dimensions, liveUploadData, adjustments in guard let videoUrl = videoUrl else { return } var finalDimensions: CGSize = dimensions var finalDuration: Double = duration var previewRepresentations: [TelegramMediaImageRepresentation] = [] if let previewImage = previewImage { let resource = LocalFileMediaResource(fileId: arc4random64()) let thumbnailSize = finalDimensions.aspectFitted(CGSize(width: 90.0, height: 90.0)) let thumbnailImage = TGScaleImageToPixelSize(previewImage, thumbnailSize)! if let thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 0.4) { account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnailData) previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: thumbnailSize, resource: resource)) } } finalDimensions = TGMediaVideoConverter.dimensions(for: finalDimensions, adjustments: adjustments, preset: TGMediaVideoConversionPresetVideoMessage) var resourceAdjustments: VideoMediaResourceAdjustments? if let adjustments = adjustments { if adjustments.trimApplied() { finalDuration = adjustments.trimEndValue - adjustments.trimStartValue } let adjustmentsData = MemoryBuffer(data: NSKeyedArchiver.archivedData(withRootObject: adjustments.dictionary())) let digest = MemoryBuffer(data: adjustmentsData.md5Digest()) resourceAdjustments = VideoMediaResourceAdjustments(data: adjustmentsData, digest: digest) } if finalDuration.isZero || finalDuration.isNaN { return } let resource: TelegramMediaResource if let liveUploadData = liveUploadData as? LegacyLiveUploadInterfaceResult, resourceAdjustments == nil, let data = try? Data(contentsOf: videoUrl) { resource = LocalFileMediaResource(fileId: liveUploadData.id) account.postbox.mediaBox.storeResourceData(resource.id, data: data) } else { resource = LocalFileVideoMediaResource(randomId: arc4random64(), path: videoUrl.path, adjustments: resourceAdjustments) } if let previewImage = previewImage { if let data = compressImageToJPEG(previewImage, quality: 0.7) { account.postbox.mediaBox.storeCachedResourceRepresentation(resource, representation: CachedVideoFirstFrameRepresentation(), data: data) } } let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, mimeType: "video/mp4", size: nil, attributes: [.FileName(fileName: "video.mp4"), .Video(duration: Int(finalDuration), size: finalDimensions, flags: [.instantRoundVideo])]) let attributes: [MessageAttribute] = [] send(.message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)) } controller.didDismiss = { [weak legacyController] in if let legacyController = legacyController { legacyController.dismiss() } } legacyController.bindCaptureController(controller) } } return legacyController }