diff --git a/submodules/Camera/Sources/Camera.swift b/submodules/Camera/Sources/Camera.swift index 58afcb938e..341740e7ac 100644 --- a/submodules/Camera/Sources/Camera.swift +++ b/submodules/Camera/Sources/Camera.swift @@ -223,6 +223,10 @@ private final class CameraContext { self.device.setZoomLevel(zoomLevel) } + func setZoomDelta(_ zoomDelta: CGFloat) { + self.device.setZoomDelta(zoomDelta) + } + func takePhoto() -> Signal { return self.output.takePhoto(orientation: self.videoOrientation ?? .portrait, flashMode: self._flashMode) } @@ -414,6 +418,15 @@ public final class Camera { } } + + public func setZoomDelta(_ zoomDelta: CGFloat) { + self.queue.async { + if let context = self.contextRef?.takeUnretainedValue() { + context.setZoomDelta(zoomDelta) + } + } + } + public func setTorchActive(_ active: Bool) { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { diff --git a/submodules/Camera/Sources/CameraDevice.swift b/submodules/Camera/Sources/CameraDevice.swift index 880e4f35b4..3df0b04f8a 100644 --- a/submodules/Camera/Sources/CameraDevice.swift +++ b/submodules/Camera/Sources/CameraDevice.swift @@ -220,4 +220,13 @@ final class CameraDevice { device.videoZoomFactor = max(1.0, min(10.0, zoomLevel)) } } + + func setZoomDelta(_ zoomDelta: CGFloat) { + guard let device = self.videoDevice else { + return + } + self.transaction(device) { device in + device.videoZoomFactor = max(1.0, min(10.0, device.videoZoomFactor * zoomDelta)) + } + } } diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift index 6ee4c1108c..4153994c1e 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift @@ -873,11 +873,10 @@ public class CameraScreen: ViewController { @objc private func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) { switch gestureRecognizer.state { - case .began: - gestureRecognizer.scale = 1.0 case .changed: let scale = gestureRecognizer.scale - self.camera.setZoomLevel(scale) + self.camera.setZoomDelta(scale) + gestureRecognizer.scale = 1.0 default: break } diff --git a/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift b/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift index fe68a87bf1..e6629b7a8f 100644 --- a/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift +++ b/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift @@ -387,6 +387,7 @@ public final class MediaEditor { self.setGradientColors([topColor, bottomColor]) if player == nil { + self.updateRenderChain() self.maybeGeneratePersonSegmentation(image) } @@ -425,10 +426,20 @@ public final class MediaEditor { } private var skipRendering = false + private func updateValues(skipRendering: Bool = false, _ f: (MediaEditorValues) -> MediaEditorValues) { + if skipRendering { + self.skipRendering = true + } + self.values = f(self.values) + if skipRendering { + self.skipRendering = false + } + } + public func setCrop(offset: CGPoint, scale: CGFloat, rotation: CGFloat, mirroring: Bool) { - self.skipRendering = true - self.values = self.values.withUpdatedCrop(offset: offset, scale: scale, rotation: rotation, mirroring: mirroring) - self.skipRendering = false + self.updateValues(skipRendering: true) { values in + return values.withUpdatedCrop(offset: offset, scale: scale, rotation: rotation, mirroring: mirroring) + } } public func getToolValue(_ key: EditorToolKey) -> Any? { @@ -436,19 +447,24 @@ public final class MediaEditor { } public func setToolValue(_ key: EditorToolKey, value: Any) { - var updatedToolValues = self.values.toolValues - updatedToolValues[key] = value - self.values = self.values.withUpdatedToolValues(updatedToolValues) - self.updateRenderChain() + self.updateValues { values in + var updatedToolValues = values.toolValues + updatedToolValues[key] = value + return values.withUpdatedToolValues(updatedToolValues) + } } public func setVideoIsMuted(_ videoIsMuted: Bool) { self.player?.isMuted = videoIsMuted - self.values = self.values.withUpdatedVideoIsMuted(videoIsMuted) + self.updateValues(skipRendering: true) { values in + return values.withUpdatedVideoIsMuted(videoIsMuted) + } } public func setVideoIsFullHd(_ videoIsFullHd: Bool) { - self.values = self.values.withUpdatedVideoIsFullHd(videoIsFullHd) + self.updateValues(skipRendering: true) { values in + return values.withUpdatedVideoIsFullHd(videoIsFullHd) + } } private var targetTimePosition: (CMTime, Bool)? @@ -494,23 +510,29 @@ public final class MediaEditor { }) } - public func setVideoTrimRange(_ trimRange: Range) { - self.skipRendering = true - self.values = self.values.withUpdatedVideoTrimRange(trimRange) - self.skipRendering = false + public func setVideoTrimRange(_ trimRange: Range, apply: Bool) { + self.updateValues(skipRendering: true) { values in + return values.withUpdatedVideoTrimRange(trimRange) + } - self.player?.currentItem?.forwardPlaybackEndTime = CMTime(seconds: trimRange.upperBound, preferredTimescale: CMTimeScale(1000)) + if apply { + self.player?.currentItem?.forwardPlaybackEndTime = CMTime(seconds: trimRange.upperBound, preferredTimescale: CMTimeScale(1000)) + } } public func setDrawingAndEntities(data: Data?, image: UIImage?, entities: [CodableDrawingEntity]) { - self.values = self.values.withUpdatedDrawingAndEntities(drawing: image, entities: entities) + self.updateValues(skipRendering: true) { values in + return values.withUpdatedDrawingAndEntities(drawing: image, entities: entities) + } } public func setGradientColors(_ gradientColors: [UIColor]) { - self.values = self.values.withUpdatedGradientColors(gradientColors: gradientColors) + self.updateValues(skipRendering: true) { values in + return values.withUpdatedGradientColors(gradientColors: gradientColors) + } } - private var previousUpdateTime = CACurrentMediaTime() + private var previousUpdateTime: Double? private var scheduledUpdate = false private func updateRenderChain() { self.renderChain.update(values: self.values) @@ -519,10 +541,9 @@ public final class MediaEditor { let currentTime = CACurrentMediaTime() if !self.scheduledUpdate { let delay = 0.03333 - let delta = currentTime - self.previousUpdateTime - if delta < delay { + if let previousUpdateTime = self.previousUpdateTime, currentTime - previousUpdateTime < delay { self.scheduledUpdate = true - Queue.mainQueue().after(delay - delta) { + Queue.mainQueue().after(delay - (currentTime - previousUpdateTime)) { self.scheduledUpdate = false self.previousUpdateTime = CACurrentMediaTime() self.renderer.willRenderFrame() diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index c3e9ab4b59..186ad786c2 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -200,6 +200,8 @@ final class MediaEditorScreenComponent: Component { private let textDoneButton = ComponentView() private let textSize = ComponentView() + private var isDismissed = false + private var component: MediaEditorScreenComponent? private weak var state: State? private var environment: ViewControllerComponentContainer.Environment? @@ -274,6 +276,7 @@ final class MediaEditorScreenComponent: Component { } func animateOut(to source: TransitionAnimationSource) { + self.isDismissed = true let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut)) if let view = self.cancelButton.view { transition.setAlpha(view: view, alpha: 0.0) @@ -398,6 +401,9 @@ final class MediaEditorScreenComponent: Component { } func update(component: MediaEditorScreenComponent, availableSize: CGSize, state: State, environment: Environment, transition: Transition) -> CGSize { + guard !self.isDismissed else { + return availableSize + } let environment = environment[ViewControllerComponentContainer.Environment.self].value self.environment = environment @@ -612,10 +618,9 @@ final class MediaEditorScreenComponent: Component { framesUpdateTimestamp: playerState.framesUpdateTimestamp, trimUpdated: { [weak mediaEditor] start, end, updatedEnd, done in if let mediaEditor { + mediaEditor.setVideoTrimRange(start.. 10.0 && !self.isEnhacing { + if abs(translation.y) > 10.0 && !self.isEnhacing && hasSwipeToDismiss { if !self.isDismissing { self.isDismissing = true controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut)) @@ -1449,7 +1454,7 @@ public final class MediaEditorScreen: ViewController { } else if self.isEnhacing { if let mediaEditor = self.mediaEditor { let value = mediaEditor.getToolValue(.enhance) as? Float ?? 0.0 - let delta = Float((translation.x / self.frame.width) * 2.0) + let delta = Float((translation.x / self.frame.width) * 1.5) let updatedValue = max(0.0, min(1.0, value + delta)) mediaEditor.setToolValue(.enhance, value: updatedValue) } @@ -1573,6 +1578,7 @@ public final class MediaEditorScreen: ViewController { guard let controller = self.controller else { return } + self.isDismissed = true controller.statusBar.statusBarStyle = .Ignore let previousDimAlpha = self.backgroundDimView.alpha @@ -1825,7 +1831,7 @@ public final class MediaEditorScreen: ViewController { private var drawingScreen: DrawingScreen? func containerLayoutUpdated(layout: ContainerViewLayout, forceUpdate: Bool = false, animateOut: Bool = false, transition: Transition) { - guard let controller = self.controller else { + guard let controller = self.controller, !self.isDismissed else { return } let isFirstTime = self.validLayout == nil @@ -2800,6 +2806,8 @@ private final class ToolValueComponent: Component { private let title = ComponentView() private let value = ComponentView() + private let hapticFeedback = HapticFeedback() + private var component: ToolValueComponent? private weak var state: EmptyComponentState? @@ -2814,6 +2822,8 @@ private final class ToolValueComponent: Component { } func update(component: ToolValueComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { + + let previousValue = self.component?.value self.component = component self.state = state @@ -2860,6 +2870,10 @@ private final class ToolValueComponent: Component { transition.setPosition(view: valueView, position: valueFrame.center) transition.setBounds(view: valueView, bounds: CGRect(origin: .zero, size: valueFrame.size)) } + + if let previousValue, component.value != previousValue, self.alpha > 0.0 { + self.hapticFeedback.impact(.click05) + } return availableSize }