mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Add story pinch-to-zoom
This commit is contained in:
@@ -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 {
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)?
|
||||
|
||||
Reference in New Issue
Block a user