[WIP] Stories

This commit is contained in:
Ali 2023-05-16 22:16:22 +04:00
parent e6ebc89b85
commit a1e59a8bff
8 changed files with 76 additions and 12 deletions

View File

@ -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)
}
)
}
}

View File

@ -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())

View File

@ -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)
}
}
}

View File

@ -58,6 +58,7 @@ swift_library(
"-warnings-as-errors",
],
deps = [
"//submodules/ComponentFlow",
],
data = [
":FullScreenEffectViewBundle",

View File

@ -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

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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()