mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Stories
This commit is contained in:
parent
e6ebc89b85
commit
a1e59a8bff
@ -2490,10 +2490,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
|
||||
let localRect = transitionView.convert(transitionView.bounds, to: self.view)
|
||||
|
||||
Queue.mainQueue().after(0.2 * UIView.animationDurationFactor, { [weak self] in
|
||||
HapticFeedback().impact()
|
||||
self?.animateRipple(centerLocation: localRect.center)
|
||||
})
|
||||
|
||||
return StoryContainerScreen.TransitionOut(
|
||||
destinationView: transitionView,
|
||||
destinationRect: transitionView.bounds,
|
||||
destinationCornerRadius: transitionView.bounds.height * 0.5
|
||||
destinationCornerRadius: transitionView.bounds.height * 0.5,
|
||||
completed: { [weak self] in
|
||||
let _ = self
|
||||
//self?.animateRipple(centerLocation: localRect.center)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import Display
|
||||
@_silgen_name("UIAnimationDragCoefficient") func UIAnimationDragCoefficient() -> Float
|
||||
#endif
|
||||
|
||||
private extension UIView {
|
||||
public extension UIView {
|
||||
static var animationDurationFactor: Double {
|
||||
#if targetEnvironment(simulator)
|
||||
return Double(UIAnimationDragCoefficient())
|
||||
|
@ -579,6 +579,24 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
self.maskAsSeenDisposables.set(signal.start(), forKey: opaqueId)
|
||||
}
|
||||
|
||||
func markAction(opaqueId: Data) {
|
||||
let account = self.account
|
||||
let signal: Signal<Never, NoError> = account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
return transaction.getPeer(self.peerId).flatMap(apiInputChannel)
|
||||
}
|
||||
|> mapToSignal { inputChannel -> Signal<Never, NoError> in
|
||||
guard let inputChannel = inputChannel else {
|
||||
return .complete()
|
||||
}
|
||||
return account.network.request(Api.functions.channels.clickSponsoredMessage(channel: inputChannel, randomId: Buffer(data: opaqueId)))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
let _ = signal.start()
|
||||
}
|
||||
}
|
||||
|
||||
public class AdMessagesHistoryContext {
|
||||
@ -612,4 +630,10 @@ public class AdMessagesHistoryContext {
|
||||
impl.markAsSeen(opaqueId: opaqueId)
|
||||
}
|
||||
}
|
||||
|
||||
public func markAction(opaqueId: Data) {
|
||||
self.impl.with { impl in
|
||||
impl.markAction(opaqueId: opaqueId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ swift_library(
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/ComponentFlow",
|
||||
],
|
||||
data = [
|
||||
":FullScreenEffectViewBundle",
|
||||
|
@ -2,6 +2,7 @@ import Foundation
|
||||
import Metal
|
||||
import MetalKit
|
||||
import simd
|
||||
import ComponentFlow
|
||||
|
||||
public final class RippleEffectView: MTKView {
|
||||
private let centerLocation: CGPoint
|
||||
@ -154,7 +155,7 @@ public final class RippleEffectView: MTKView {
|
||||
let relativeTime: Double
|
||||
let timestamp = CACurrentMediaTime()
|
||||
if let startTime = self.startTime {
|
||||
relativeTime = timestamp - startTime
|
||||
relativeTime = (timestamp - startTime) * (1.0 / UIView.animationDurationFactor)
|
||||
} else {
|
||||
self.startTime = timestamp
|
||||
relativeTime = 0.0
|
||||
|
@ -115,6 +115,8 @@ private final class StoryContainerScreenComponent: Component {
|
||||
private weak var state: EmptyComponentState?
|
||||
private var environment: ViewControllerComponentContainer.Environment?
|
||||
|
||||
private let backgroundLayer: SimpleLayer
|
||||
|
||||
private var focusedItemSet: AnyHashable?
|
||||
private var itemSets: [StoryContentItemSlice] = []
|
||||
private var visibleItemSetViews: [AnyHashable: ItemSetView] = [:]
|
||||
@ -122,10 +124,14 @@ private final class StoryContainerScreenComponent: Component {
|
||||
private var itemSetPanState: ItemSetPanState?
|
||||
private var dismissPanState: ItemSetPanState?
|
||||
|
||||
private var isAnimatingOut: Bool = false
|
||||
private var didAnimateOut: Bool = false
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.backgroundLayer = SimpleLayer()
|
||||
self.backgroundLayer.backgroundColor = UIColor.black.cgColor
|
||||
|
||||
self.backgroundColor = .black
|
||||
super.init(frame: frame)
|
||||
|
||||
let horizontalPanRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] point in
|
||||
guard let self, let focusedItemSet = self.focusedItemSet, let itemSetView = self.visibleItemSetViews[focusedItemSet], let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View else {
|
||||
@ -320,7 +326,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
|
||||
func animateIn() {
|
||||
if let transitionIn = self.component?.transitionIn, transitionIn.sourceView != nil {
|
||||
self.layer.animate(from: UIColor.black.withAlphaComponent(0.0).cgColor, to: self.layer.backgroundColor ?? UIColor.black.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.28)
|
||||
self.backgroundLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.28, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||
|
||||
if let transitionIn = self.component?.transitionIn, let focusedItemSet = self.focusedItemSet, let itemSetView = self.visibleItemSetViews[focusedItemSet] {
|
||||
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||
@ -336,17 +342,26 @@ private final class StoryContainerScreenComponent: Component {
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
self.isAnimatingOut = true
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
if let component = self.component, let focusedItemSet = self.focusedItemSet, let peerId = focusedItemSet.base as? EnginePeer.Id, let itemSetView = self.visibleItemSetViews[focusedItemSet], let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View, let transitionOut = component.transitionOut(peerId) {
|
||||
let currentBackgroundColor = self.layer.presentation()?.backgroundColor ?? self.layer.backgroundColor
|
||||
self.layer.animate(from: currentBackgroundColor ?? UIColor.black.cgColor, to: UIColor.black.withAlphaComponent(0.0).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.25, removeOnCompletion: false)
|
||||
let transition = Transition(animation: .curve(duration: 0.25, curve: .easeInOut))
|
||||
transition.setAlpha(layer: self.backgroundLayer, alpha: 0.0)
|
||||
|
||||
itemSetComponentView.animateOut(transitionOut: transitionOut, completion: completion)
|
||||
let transitionOutCompleted = transitionOut.completed
|
||||
itemSetComponentView.animateOut(transitionOut: transitionOut, completion: {
|
||||
completion()
|
||||
transitionOutCompleted()
|
||||
})
|
||||
} else {
|
||||
self.layer.allowsGroupOpacity = true
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
self.didAnimateOut = true
|
||||
}
|
||||
|
||||
private func updatePreloads() {
|
||||
@ -381,6 +396,10 @@ private final class StoryContainerScreenComponent: Component {
|
||||
}
|
||||
|
||||
func update(component: StoryContainerScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: Transition) -> CGSize {
|
||||
if self.didAnimateOut {
|
||||
return availableSize
|
||||
}
|
||||
|
||||
let isFirstTime = self.component == nil
|
||||
|
||||
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
||||
@ -405,6 +424,9 @@ private final class StoryContainerScreenComponent: Component {
|
||||
if self.dismissPanState != nil {
|
||||
isProgressPaused = true
|
||||
}
|
||||
if self.isAnimatingOut {
|
||||
isProgressPaused = true
|
||||
}
|
||||
|
||||
var dismissPanOffset: CGFloat = 0.0
|
||||
var dismissPanScale: CGFloat = 1.0
|
||||
@ -415,7 +437,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
dismissAlphaScale = 1.0 * (1.0 - dismissPanState.fraction) + 0.2 * dismissPanState.fraction
|
||||
}
|
||||
|
||||
transition.setBackgroundColor(view: self, color: UIColor.black.withAlphaComponent(max(0.5, dismissAlphaScale)))
|
||||
transition.setAlpha(layer: self.backgroundLayer, alpha: max(0.5, dismissAlphaScale))
|
||||
|
||||
var contentDerivedBottomInset: CGFloat = environment.safeInsets.bottom
|
||||
|
||||
@ -727,15 +749,18 @@ public class StoryContainerScreen: ViewControllerComponentContainer {
|
||||
public weak var destinationView: UIView?
|
||||
public let destinationRect: CGRect
|
||||
public let destinationCornerRadius: CGFloat
|
||||
public let completed: () -> Void
|
||||
|
||||
public init(
|
||||
destinationView: UIView,
|
||||
destinationRect: CGRect,
|
||||
destinationCornerRadius: CGFloat
|
||||
destinationCornerRadius: CGFloat,
|
||||
completed: @escaping () -> Void
|
||||
) {
|
||||
self.destinationView = destinationView
|
||||
self.destinationRect = destinationRect
|
||||
self.destinationCornerRadius = destinationCornerRadius
|
||||
self.completed = completed
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4329,6 +4329,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId)
|
||||
|
||||
switch adAttribute.target {
|
||||
case let .peer(id, messageId, startParam):
|
||||
if case let .peer(currentPeerId) = self.chatLocation, currentPeerId == id {
|
||||
|
@ -636,7 +636,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
var openNextChannelToRead: ((EnginePeer, TelegramEngine.NextUnreadChannelLocation) -> Void)?
|
||||
private var contentInsetAnimator: DisplayLinkAnimator?
|
||||
|
||||
private let adMessagesContext: AdMessagesHistoryContext?
|
||||
let adMessagesContext: AdMessagesHistoryContext?
|
||||
private var adMessagesDisposable: Disposable?
|
||||
private var preloadAdPeerId: PeerId?
|
||||
private let preloadAdPeerDisposable = MetaDisposable()
|
||||
|
Loading…
x
Reference in New Issue
Block a user