diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift index cfde14f38c..84d3d5b021 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift @@ -151,6 +151,7 @@ private final class StoryContainerScreenComponent: Component { } } + final class View: UIView, UIScrollViewDelegate, UIGestureRecognizerDelegate { private var component: StoryContainerScreenComponent? private weak var state: EmptyComponentState? @@ -165,6 +166,7 @@ private final class StoryContainerScreenComponent: Component { private let storyItemSharedState = StoryContentItem.SharedState() private var visibleItemSetViews: [EnginePeer.Id: ItemSetView] = [:] + private var itemSetPinchState: StoryItemSetContainerComponent.PinchState? private var itemSetPanState: ItemSetPanState? private var verticalPanState: ItemSetPanState? private var isHoldingTouch: Bool = false @@ -226,6 +228,9 @@ private final class StoryContainerScreenComponent: Component { } self.addGestureRecognizer(longPressRecognizer) + let pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(self.pinchGesture(_:))) + self.addGestureRecognizer(pinchRecognizer) + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))) self.backgroundEffectView.addGestureRecognizer(tapGestureRecognizer) } @@ -435,6 +440,26 @@ private final class StoryContainerScreenComponent: Component { } } + @objc private func pinchGesture(_ recognizer: UIPinchGestureRecognizer) { + switch recognizer.state { + case .began, .changed: + let location = recognizer.location(in: self) + let scale = recognizer.scale + if let itemSetPinchState = self.itemSetPinchState { + let offset = CGPoint(x: location.x - itemSetPinchState.location.x , y: location.y - itemSetPinchState.location.y) + self.itemSetPinchState = StoryItemSetContainerComponent.PinchState(scale: scale, location: itemSetPinchState.location, offset: offset) + } else { + self.itemSetPinchState = StoryItemSetContainerComponent.PinchState(scale: scale, location: location, offset: .zero) + } + self.state?.updated(transition: .immediate) + case .cancelled, .ended: + self.itemSetPinchState = nil + self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring))) + default: + break + } + } + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { for subview in self.subviews.reversed() { if !subview.isUserInteractionEnabled || subview.isHidden || subview.alpha == 0.0 { @@ -703,7 +728,7 @@ private final class StoryContainerScreenComponent: Component { itemSetContainerInsets.bottom = floorToScreenPixels((availableSize.height - itemSetContainerSize.height) / 2.0) itemSetContainerSafeInsets.bottom = 0.0 } - + let _ = itemSetView.view.update( transition: itemSetTransition, component: AnyComponent(StoryItemSetContainerComponent( @@ -718,10 +743,11 @@ private final class StoryContainerScreenComponent: Component { inputHeight: environment.inputHeight, metrics: environment.metrics, isProgressPaused: isProgressPaused || i != focusedIndex, - hideUI: i == focusedIndex && self.itemSetPanState?.didBegin == false, + hideUI: (i == focusedIndex && (self.itemSetPanState?.didBegin == false || self.itemSetPinchState != nil)), visibilityFraction: 1.0 - abs(panFraction + cubeAdditionalRotationFraction), isPanning: self.itemSetPanState?.didBegin == true, verticalPanFraction: verticalPanFraction, + pinchState: self.itemSetPinchState, presentController: { [weak self] c in guard let self, let environment = self.environment else { return diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index dbbf4a205e..4e42b52af1 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -36,6 +36,18 @@ public final class StoryItemSetContainerComponent: Component { case next } + public struct PinchState: Equatable { + var scale: CGFloat + var location: CGPoint + var offset: CGPoint + + init(scale: CGFloat, location: CGPoint, offset: CGPoint) { + self.scale = scale + self.location = location + self.offset = offset + } + } + public let context: AccountContext public let externalState: ExternalState public let storyItemSharedState: StoryContentItem.SharedState @@ -51,6 +63,7 @@ public final class StoryItemSetContainerComponent: Component { public let visibilityFraction: CGFloat public let isPanning: Bool public let verticalPanFraction: CGFloat + public let pinchState: PinchState? public let presentController: (ViewController) -> Void public let close: () -> Void public let navigate: (NavigationDirection) -> Void @@ -74,6 +87,7 @@ public final class StoryItemSetContainerComponent: Component { visibilityFraction: CGFloat, isPanning: Bool, verticalPanFraction: CGFloat, + pinchState: PinchState?, presentController: @escaping (ViewController) -> Void, close: @escaping () -> Void, navigate: @escaping (NavigationDirection) -> Void, @@ -96,6 +110,7 @@ public final class StoryItemSetContainerComponent: Component { self.visibilityFraction = visibilityFraction self.isPanning = isPanning self.verticalPanFraction = verticalPanFraction + self.pinchState = pinchState self.presentController = presentController self.close = close self.navigate = navigate @@ -144,6 +159,9 @@ public final class StoryItemSetContainerComponent: Component { if lhs.verticalPanFraction != rhs.verticalPanFraction { return false } + if lhs.pinchState != rhs.pinchState { + return false + } return true } @@ -492,6 +510,9 @@ public final class StoryItemSetContainerComponent: Component { guard let component = self.component else { return false } + if component.pinchState != nil { + return true + } if self.inputPanelExternalState.isEditing || component.isProgressPaused || self.actionSheet != nil || self.contextController != nil || self.sendMessageContext.audioRecorderValue != nil || self.sendMessageContext.videoRecorderValue != nil || self.displayViewList { return true } @@ -1359,7 +1380,7 @@ public final class StoryItemSetContainerComponent: Component { actionSheet.setItemGroups([ ActionSheetItemGroup(items: [ - ActionSheetButtonItem(title: "Delete", color: .destructive, action: { [weak self, weak actionSheet] in + ActionSheetButtonItem(title: "Delete Story", color: .destructive, action: { [weak self, weak actionSheet] in actionSheet?.dismissAnimated() guard let self, let component = self.component else { @@ -1607,7 +1628,24 @@ public final class StoryItemSetContainerComponent: Component { transition.setPosition(view: self.contentContainerView, position: contentFrame.center) transition.setBounds(view: self.contentContainerView, bounds: CGRect(origin: CGPoint(), size: contentFrame.size)) - transition.setScale(view: self.contentContainerView, scale: contentVisualScale) + + var transform = CATransform3DMakeScale(contentVisualScale, contentVisualScale, 1.0) + if let pinchState = component.pinchState { + let pinchOffset = CGPoint( + x: pinchState.location.x - contentFrame.width / 2.0, + y: pinchState.location.y - contentFrame.height / 2.0 + ) + transform = CATransform3DTranslate( + transform, + pinchState.offset.x - pinchOffset.x * (pinchState.scale - 1.0), + pinchState.offset.y - pinchOffset.y * (pinchState.scale - 1.0), + 0.0 + ) + transform = CATransform3DScale(transform, pinchState.scale, pinchState.scale, 0.0) + } + transition.setTransform(view: self.contentContainerView, transform: transform) + + //transition.setScale(view: self.contentContainerView, scale: contentVisualScale) transition.setCornerRadius(layer: self.contentContainerView.layer, cornerRadius: 12.0 * (1.0 / contentVisualScale)) if self.closeButtonIconView.image == nil { @@ -1731,7 +1769,7 @@ public final class StoryItemSetContainerComponent: Component { self.itemLayout = itemLayout let inputPanelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - inputPanelSize.width) / 2.0), y: availableSize.height - inputPanelBottomInset - inputPanelSize.height), size: inputPanelSize) - var inputPanelAlpha: CGFloat = focusedItem?.isMy == true ? 0.0 : 1.0 + var inputPanelAlpha: CGFloat = focusedItem?.isMy == true || component.hideUI ? 0.0 : 1.0 if case .regular = component.metrics.widthClass { inputPanelAlpha *= component.visibilityFraction } diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index 5734f97694..c2d7015314 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -255,7 +255,6 @@ public final class TelegramRootController: NavigationController, TelegramRootCon controller.view.endEditing(true) let context = self.context - let presentationData = context.sharedContext.currentPresentationData.with { $0 } var presentImpl: ((ViewController) -> Void)? var returnToCameraImpl: (() -> Void)?