Story animation transitions

This commit is contained in:
Ali 2023-06-09 11:11:57 +04:00
parent 69e49f9196
commit 3a2f75ab82
17 changed files with 205 additions and 46 deletions

View File

@ -2277,7 +2277,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
fileprivate func openStoryCamera() { fileprivate func openStoryCamera() {
var cameraTransitionIn: StoryCameraTransitionIn? var cameraTransitionIn: StoryCameraTransitionIn?
if let componentView = self.chatListHeaderView() { if let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
cameraTransitionIn = StoryCameraTransitionIn( cameraTransitionIn = StoryCameraTransitionIn(
sourceView: transitionView, sourceView: transitionView,
sourceRect: transitionView.bounds, sourceRect: transitionView.bounds,
@ -2292,7 +2292,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return nil return nil
} }
if let componentView = self.chatListHeaderView() { if let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
return StoryCameraTransitionOut( return StoryCameraTransitionOut(
destinationView: transitionView, destinationView: transitionView,
destinationRect: transitionView.bounds, destinationRect: transitionView.bounds,
@ -2340,7 +2340,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
var transitionIn: StoryContainerScreen.TransitionIn? var transitionIn: StoryContainerScreen.TransitionIn?
if let peer, let componentView = self.chatListHeaderView() { if let peer, let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) {
transitionIn = StoryContainerScreen.TransitionIn( transitionIn = StoryContainerScreen.TransitionIn(
sourceView: transitionView, sourceView: transitionView,
sourceRect: transitionView.bounds, sourceRect: transitionView.bounds,
@ -2359,10 +2359,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
if let componentView = self.chatListHeaderView() { if let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) { if let (transitionView, transitionContentView) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
return StoryContainerScreen.TransitionOut( return StoryContainerScreen.TransitionOut(
destinationView: transitionView, destinationView: transitionView,
transitionView: nil, transitionView: transitionContentView,
destinationRect: transitionView.bounds, destinationRect: transitionView.bounds,
destinationCornerRadius: transitionView.bounds.height * 0.5, destinationCornerRadius: transitionView.bounds.height * 0.5,
destinationIsAvatar: true, destinationIsAvatar: true,
@ -2374,6 +2374,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return nil return nil
} }
) )
if let componentView = self.chatListHeaderView() {
componentView.storyPeerListView()?.setPreviewedItem(signal: storyContainerScreen.focusedItem)
}
self.push(storyContainerScreen) self.push(storyContainerScreen)
}) })
} }
@ -2446,7 +2449,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
public func transitionViewForOwnStoryItem() -> UIView? { public func transitionViewForOwnStoryItem() -> UIView? {
if let componentView = self.chatListHeaderView() { if let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
return transitionView return transitionView
} }
} }
@ -2455,7 +2458,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
public func animateStoryUploadRipple() { public func animateStoryUploadRipple() {
if let componentView = self.chatListHeaderView() { if let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
let localRect = transitionView.convert(transitionView.bounds, to: self.view) let localRect = transitionView.convert(transitionView.bounds, to: self.view)
self.animateRipple(centerLocation: localRect.center) self.animateRipple(centerLocation: localRect.center)
} }
@ -4778,7 +4781,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return nil return nil
} }
if finished, let componentView = self.chatListHeaderView() { if finished, let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
return StoryCameraTransitionOut( return StoryCameraTransitionOut(
destinationView: transitionView, destinationView: transitionView,
destinationRect: transitionView.bounds, destinationRect: transitionView.bounds,

View File

@ -41,6 +41,7 @@ swift_library(
"//submodules/TelegramUI/Components/Stories/StoryContentComponent", "//submodules/TelegramUI/Components/Stories/StoryContentComponent",
"//submodules/TelegramUI/Components/Stories/StoryPeerListComponent", "//submodules/TelegramUI/Components/Stories/StoryPeerListComponent",
"//submodules/TelegramUI/Components/ChatListTitleView", "//submodules/TelegramUI/Components/ChatListTitleView",
"//submodules/TelegramUI/Components/ChatListHeaderComponent",
"//submodules/ComponentFlow", "//submodules/ComponentFlow",
], ],
visibility = [ visibility = [

View File

@ -529,7 +529,7 @@ public class ContactsController: ViewController {
var transitionIn: StoryContainerScreen.TransitionIn? var transitionIn: StoryContainerScreen.TransitionIn?
if let peer, let componentView = self.chatListHeaderView() { if let peer, let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) { if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) {
transitionIn = StoryContainerScreen.TransitionIn( transitionIn = StoryContainerScreen.TransitionIn(
sourceView: transitionView, sourceView: transitionView,
sourceRect: transitionView.bounds, sourceRect: transitionView.bounds,
@ -548,10 +548,10 @@ public class ContactsController: ViewController {
} }
if let componentView = self.chatListHeaderView() { if let componentView = self.chatListHeaderView() {
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) { if let (transitionView, transitionContentView) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
return StoryContainerScreen.TransitionOut( return StoryContainerScreen.TransitionOut(
destinationView: transitionView, destinationView: transitionView,
transitionView: nil, transitionView: transitionContentView,
destinationRect: transitionView.bounds, destinationRect: transitionView.bounds,
destinationCornerRadius: transitionView.bounds.height * 0.5, destinationCornerRadius: transitionView.bounds.height * 0.5,
destinationIsAvatar: true, destinationIsAvatar: true,

View File

@ -372,6 +372,7 @@ swift_library(
"//submodules/TelegramUI/Components/ShareWithPeersScreen", "//submodules/TelegramUI/Components/ShareWithPeersScreen",
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode", "//submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode",
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen", "//submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen",
"//submodules/TelegramUI/Components/MoreHeaderButton",
] + select({ ] + select({
"@build_bazel_rules_apple//apple:ios_armv7": [], "@build_bazel_rules_apple//apple:ios_armv7": [],
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,

View File

@ -23,6 +23,7 @@ swift_library(
"//submodules/TelegramUI/Components/Stories/StoryPeerListComponent", "//submodules/TelegramUI/Components/Stories/StoryPeerListComponent",
"//submodules/Components/ComponentDisplayAdapters", "//submodules/Components/ComponentDisplayAdapters",
"//submodules/SearchUI", "//submodules/SearchUI",
"//submodules/TelegramUI/Components/MoreHeaderButton",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -8,6 +8,7 @@ import ChatListTitleView
import AppBundle import AppBundle
import StoryPeerListComponent import StoryPeerListComponent
import TelegramCore import TelegramCore
import MoreHeaderButton
public final class HeaderNetworkStatusComponent: Component { public final class HeaderNetworkStatusComponent: Component {
public enum Content: Equatable { public enum Content: Equatable {

View File

@ -0,0 +1,20 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "MoreHeaderButton",
module_name = "MoreHeaderButton",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/AsyncDisplayKit",
"//submodules/AnimationUI",
],
visibility = [
"//visibility:public",
],
)

View File

@ -25,6 +25,7 @@ swift_library(
"//submodules/ContextUI", "//submodules/ContextUI",
"//submodules/UndoUI", "//submodules/UndoUI",
"//submodules/TelegramUI/Components/BottomButtonPanelComponent", "//submodules/TelegramUI/Components/BottomButtonPanelComponent",
"//submodules/TelegramUI/Components/MoreHeaderButton",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -13,6 +13,7 @@ import ContextUI
import ChatTitleView import ChatTitleView
import BottomButtonPanelComponent import BottomButtonPanelComponent
import UndoUI import UndoUI
import MoreHeaderButton
final class PeerInfoStoryGridScreenComponent: Component { final class PeerInfoStoryGridScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment typealias EnvironmentType = ViewControllerComponentContainer.Environment

View File

@ -696,6 +696,42 @@ public final class StoryItemSetContainerComponent: Component {
if let rightInfoView = self.rightInfoItem?.view.view { if let rightInfoView = self.rightInfoItem?.view.view {
if transitionOut.destinationIsAvatar { if transitionOut.destinationIsAvatar {
let transitionView = transitionOut.transitionView
let transitionViewImpl = transitionView?.makeView()
if let transitionViewImpl {
self.insertSubview(transitionViewImpl, aboveSubview: self.contentContainerView)
let rightInfoSourceFrame = rightInfoView.convert(rightInfoView.bounds, to: self)
let positionKeyframes: [CGPoint] = generateParabollicMotionKeyframes(from: sourceLocalFrame.center, to: rightInfoSourceFrame.center, elevation: 0.0, duration: 0.3, curve: .spring, reverse: true)
transitionViewImpl.frame = rightInfoSourceFrame
transitionViewImpl.alpha = 0.0
transitionView?.updateView(transitionViewImpl, StoryContainerScreen.TransitionState(
sourceSize: rightInfoSourceFrame.size,
destinationSize: sourceLocalFrame.size,
progress: 0.0
), .immediate)
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
transitionViewImpl.alpha = 1.0
transitionViewImpl.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
rightInfoView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
transition.setFrame(view: transitionViewImpl, frame: sourceLocalFrame)
transitionViewImpl.layer.position = positionKeyframes[positionKeyframes.count - 1]
transitionViewImpl.layer.animateKeyframes(values: positionKeyframes.map { NSValue(cgPoint: $0) }, duration: 0.3, keyPath: "position", removeOnCompletion: false, additive: false)
transitionViewImpl.layer.animateBounds(from: CGRect(origin: CGPoint(), size: rightInfoSourceFrame.size), to: CGRect(origin: CGPoint(), size: sourceLocalFrame.size), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
transitionView?.updateView(transitionViewImpl, StoryContainerScreen.TransitionState(
sourceSize: rightInfoSourceFrame.size,
destinationSize: sourceLocalFrame.size,
progress: 1.0
), transition)
}
let positionKeyframes: [CGPoint] = generateParabollicMotionKeyframes(from: innerSourceLocalFrame.center, to: rightInfoView.layer.position, elevation: 0.0, duration: 0.3, curve: .spring, reverse: true) let positionKeyframes: [CGPoint] = generateParabollicMotionKeyframes(from: innerSourceLocalFrame.center, to: rightInfoView.layer.position, elevation: 0.0, duration: 0.3, curve: .spring, reverse: true)
rightInfoView.layer.position = positionKeyframes[positionKeyframes.count - 1] rightInfoView.layer.position = positionKeyframes[positionKeyframes.count - 1]
rightInfoView.layer.animateKeyframes(values: positionKeyframes.map { NSValue(cgPoint: $0) }, duration: 0.3, keyPath: "position", removeOnCompletion: false, additive: false) rightInfoView.layer.animateKeyframes(values: positionKeyframes.map { NSValue(cgPoint: $0) }, duration: 0.3, keyPath: "position", removeOnCompletion: false, additive: false)
@ -715,33 +751,33 @@ public final class StoryItemSetContainerComponent: Component {
removeOnCompletion: false removeOnCompletion: false
) )
let transitionView = transitionOut.transitionView if !transitionOut.destinationIsAvatar {
let transitionViewImpl = transitionView?.makeView() let transitionView = transitionOut.transitionView
if let transitionViewImpl { let transitionViewImpl = transitionView?.makeView()
self.insertSubview(transitionViewImpl, belowSubview: self.contentContainerView) if let transitionViewImpl {
self.insertSubview(transitionViewImpl, belowSubview: self.contentContainerView)
transitionViewImpl.frame = contentSourceFrame transitionViewImpl.frame = contentSourceFrame
transitionViewImpl.alpha = 0.0 transitionViewImpl.alpha = 0.0
transitionView?.updateView(transitionViewImpl, StoryContainerScreen.TransitionState( transitionView?.updateView(transitionViewImpl, StoryContainerScreen.TransitionState(
sourceSize: contentSourceFrame.size, sourceSize: contentSourceFrame.size,
destinationSize: sourceLocalFrame.size, destinationSize: sourceLocalFrame.size,
progress: 0.0 progress: 0.0
), .immediate) ), .immediate)
}
if let transitionViewImpl { let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
transitionViewImpl.alpha = 1.0 transitionViewImpl.alpha = 1.0
transitionViewImpl.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) transitionViewImpl.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.contentContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) self.contentContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
transition.setFrame(view: transitionViewImpl, frame: sourceLocalFrame) transition.setFrame(view: transitionViewImpl, frame: sourceLocalFrame)
transitionView?.updateView(transitionViewImpl, StoryContainerScreen.TransitionState( transitionView?.updateView(transitionViewImpl, StoryContainerScreen.TransitionState(
sourceSize: contentSourceFrame.size, sourceSize: contentSourceFrame.size,
destinationSize: sourceLocalFrame.size, destinationSize: sourceLocalFrame.size,
progress: 1.0 progress: 1.0
), transition) ), transition)
}
} }
if let component = self.component, let visibleItemView = self.visibleItems[component.slice.item.id]?.view.view { if let component = self.component, let visibleItemView = self.visibleItems[component.slice.item.id]?.view.view {

View File

@ -14,10 +14,10 @@ swift_library(
"//submodules/ComponentFlow", "//submodules/ComponentFlow",
"//submodules/AppBundle", "//submodules/AppBundle",
"//submodules/Components/BundleIconComponent", "//submodules/Components/BundleIconComponent",
"//submodules/TelegramUI/Components/ChatListHeaderComponent",
"//submodules/AnimatedAvatarSetNode", "//submodules/AnimatedAvatarSetNode",
"//submodules/AccountContext", "//submodules/AccountContext",
"//submodules/TelegramCore", "//submodules/TelegramCore",
"//submodules/TelegramUI/Components/MoreHeaderButton",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -4,10 +4,10 @@ import Display
import ComponentFlow import ComponentFlow
import AppBundle import AppBundle
import BundleIconComponent import BundleIconComponent
import ChatListHeaderComponent
import AnimatedAvatarSetNode import AnimatedAvatarSetNode
import AccountContext import AccountContext
import TelegramCore import TelegramCore
import MoreHeaderButton
public final class StoryFooterPanelComponent: Component { public final class StoryFooterPanelComponent: Component {
public let context: AccountContext public let context: AccountContext

View File

@ -20,6 +20,7 @@ swift_library(
"//submodules/TelegramPresentationData", "//submodules/TelegramPresentationData",
"//submodules/AvatarNode", "//submodules/AvatarNode",
"//submodules/ContextUI", "//submodules/ContextUI",
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -6,8 +6,10 @@ import AppBundle
import BundleIconComponent import BundleIconComponent
import AccountContext import AccountContext
import TelegramCore import TelegramCore
import Postbox
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import StoryContainerScreen
public final class StoryPeerListComponent: Component { public final class StoryPeerListComponent: Component {
public final class ExternalState { public final class ExternalState {
@ -142,6 +144,9 @@ public final class StoryPeerListComponent: Component {
private var requestedLoadMoreToken: String? private var requestedLoadMoreToken: String?
private let loadMoreDisposable = MetaDisposable() private let loadMoreDisposable = MetaDisposable()
private var previewedItemDisposable: Disposable?
private var previewedItemId: EnginePeer.Id?
public override init(frame: CGRect) { public override init(frame: CGRect) {
self.collapsedButton = HighlightableButton() self.collapsedButton = HighlightableButton()
@ -187,6 +192,7 @@ public final class StoryPeerListComponent: Component {
deinit { deinit {
self.loadMoreDisposable.dispose() self.loadMoreDisposable.dispose()
self.previewedItemDisposable?.dispose()
} }
@objc private func collapsedButtonPressed() { @objc private func collapsedButtonPressed() {
@ -196,12 +202,41 @@ public final class StoryPeerListComponent: Component {
component.peerAction(nil) component.peerAction(nil)
} }
public func transitionViewForItem(peerId: EnginePeer.Id) -> UIView? { public func setPreviewedItem(signal: Signal<StoryId?, NoError>) {
self.previewedItemDisposable?.dispose()
self.previewedItemDisposable = (signal |> map(\.?.peerId) |> distinctUntilChanged |> deliverOnMainQueue).start(next: { [weak self] itemId in
guard let self else {
return
}
self.previewedItemId = itemId
for (peerId, visibleItem) in self.visibleItems {
if let itemView = visibleItem.view.view as? StoryPeerListItemComponent.View {
itemView.updateIsPreviewing(isPreviewing: peerId == itemId)
}
}
})
}
public func transitionViewForItem(peerId: EnginePeer.Id) -> (UIView, StoryContainerScreen.TransitionView)? {
if self.collapsedButton.isUserInteractionEnabled { if self.collapsedButton.isUserInteractionEnabled {
return nil return nil
} }
if let visibleItem = self.visibleItems[peerId], let itemView = visibleItem.view.view as? StoryPeerListItemComponent.View { if let visibleItem = self.visibleItems[peerId], let itemView = visibleItem.view.view as? StoryPeerListItemComponent.View {
return itemView.transitionView() if !self.scrollView.bounds.intersects(itemView.frame) {
return nil
}
return itemView.transitionView().flatMap { transitionView in
return (transitionView, StoryContainerScreen.TransitionView(
makeView: { [weak itemView] in
return StoryPeerListItemComponent.TransitionView(itemView: itemView)
},
updateView: { view, state, transition in
(view as? StoryPeerListItemComponent.TransitionView)?.update(state: state, transition: transition)
}
))
}
} }
return nil return nil
} }
@ -394,6 +429,8 @@ public final class StoryPeerListComponent: Component {
itemTransition.setFrame(view: itemView.backgroundContainer, frame: itemFrame) itemTransition.setFrame(view: itemView.backgroundContainer, frame: itemFrame)
itemTransition.setAlpha(view: itemView.backgroundContainer, alpha: itemAlpha) itemTransition.setAlpha(view: itemView.backgroundContainer, alpha: itemAlpha)
itemTransition.setScale(view: itemView.backgroundContainer, scale: itemScale) itemTransition.setScale(view: itemView.backgroundContainer, scale: itemScale)
itemView.updateIsPreviewing(isPreviewing: self.previewedItemId == itemSet.peer.id)
} }
} }

View File

@ -11,6 +11,7 @@ import TelegramPresentationData
import AvatarNode import AvatarNode
import ContextUI import ContextUI
import AsyncDisplayKit import AsyncDisplayKit
import StoryContainerScreen
private func calculateCircleIntersection(center: CGPoint, otherCenter: CGPoint, radius: CGFloat) -> (point1Angle: CGFloat, point2Angle: CGFloat)? { private func calculateCircleIntersection(center: CGPoint, otherCenter: CGPoint, radius: CGFloat) -> (point1Angle: CGFloat, point2Angle: CGFloat)? {
let distanceVector = CGPoint(x: otherCenter.x - center.x, y: otherCenter.y - center.y) let distanceVector = CGPoint(x: otherCenter.x - center.x, y: otherCenter.y - center.y)
@ -144,6 +145,47 @@ private final class StoryProgressLayer: SimpleShapeLayer {
private var sharedAvatarBackgroundImage: UIImage? private var sharedAvatarBackgroundImage: UIImage?
public final class StoryPeerListItemComponent: Component { public final class StoryPeerListItemComponent: Component {
public final class TransitionView: UIView {
private weak var itemView: StoryPeerListItemComponent.View?
private var snapshotView: UIView?
private var portalView: PortalView?
init(itemView: StoryPeerListItemComponent.View?) {
self.itemView = itemView
super.init(frame: CGRect())
if let itemView {
if let portalView = PortalView(matchPosition: false) {
itemView.avatarContent.addPortal(view: portalView)
self.portalView = portalView
self.addSubview(portalView.view)
}
/*if let snapshotView = itemView.avatarContent.snapshotView(afterScreenUpdates: false) {
self.addSubview(snapshotView)
self.snapshotView = snapshotView
}*/
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(state: StoryContainerScreen.TransitionState, transition: Transition) {
let size = state.sourceSize.interpolate(to: state.destinationSize, amount: state.progress)
if let snapshotView = self.snapshotView {
transition.setPosition(view: snapshotView, position: CGPoint(x: size.width * 0.5, y: size.height * 0.5))
transition.setScale(view: snapshotView, scale: size.width / state.destinationSize.width)
}
if let portalView = self.portalView {
transition.setPosition(view: portalView.view, position: CGPoint(x: size.width * 0.5, y: size.height * 0.5))
transition.setScale(view: portalView.view, scale: size.width / state.destinationSize.width)
}
}
}
public let context: AccountContext public let context: AccountContext
public let theme: PresentationTheme public let theme: PresentationTheme
public let strings: PresentationStrings public let strings: PresentationStrings
@ -240,6 +282,7 @@ public final class StoryPeerListItemComponent: Component {
private let button: HighlightTrackingButton private let button: HighlightTrackingButton
fileprivate let avatarContent: PortalSourceView
private let avatarContainer: UIView private let avatarContainer: UIView
private let avatarBackgroundContainer: UIView private let avatarBackgroundContainer: UIView
private let avatarBackgroundView: UIImageView private let avatarBackgroundView: UIImageView
@ -266,6 +309,9 @@ public final class StoryPeerListItemComponent: Component {
self.extractedBackgroundView = UIImageView() self.extractedBackgroundView = UIImageView()
self.extractedBackgroundView.alpha = 0.0 self.extractedBackgroundView.alpha = 0.0
self.avatarContent = PortalSourceView()
self.avatarContent.isUserInteractionEnabled = false
self.avatarContainer = UIView() self.avatarContainer = UIView()
self.avatarContainer.isUserInteractionEnabled = false self.avatarContainer.isUserInteractionEnabled = false
@ -294,9 +340,10 @@ public final class StoryPeerListItemComponent: Component {
self.avatarBackgroundContainer.addSubview(self.avatarBackgroundView) self.avatarBackgroundContainer.addSubview(self.avatarBackgroundView)
self.extractedContainerNode.contentNode.view.addSubview(self.button) self.extractedContainerNode.contentNode.view.addSubview(self.button)
self.button.addSubview(self.avatarContainer) self.avatarContent.addSubview(self.avatarContainer)
self.button.addSubview(self.avatarContent)
self.button.layer.addSublayer(self.indicatorColorLayer) self.avatarContent.layer.addSublayer(self.indicatorColorLayer)
self.indicatorMaskLayer.addSublayer(self.indicatorShapeLayer) self.indicatorMaskLayer.addSublayer(self.indicatorShapeLayer)
self.indicatorColorLayer.mask = self.indicatorMaskLayer self.indicatorColorLayer.mask = self.indicatorMaskLayer
@ -366,6 +413,10 @@ public final class StoryPeerListItemComponent: Component {
return self.avatarNode?.view return self.avatarNode?.view
} }
func updateIsPreviewing(isPreviewing: Bool) {
self.avatarContent.alpha = isPreviewing ? 0.0 : 1.0
}
func update(component: StoryPeerListItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize { func update(component: StoryPeerListItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let size = availableSize let size = availableSize
@ -439,7 +490,11 @@ public final class StoryPeerListItemComponent: Component {
peer: component.peer peer: component.peer
) )
avatarNode.updateSize(size: avatarSize) avatarNode.updateSize(size: avatarSize)
transition.setPosition(view: self.avatarContainer, position: avatarFrame.center)
transition.setPosition(view: self.avatarContent, position: CGPoint(x: avatarFrame.midX, y: avatarFrame.midY))
transition.setBounds(view: self.avatarContent, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size))
transition.setPosition(view: self.avatarContainer, position: CGPoint(x: avatarFrame.width * 0.5, y: avatarFrame.height * 0.5))
transition.setBounds(view: self.avatarContainer, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size)) transition.setBounds(view: self.avatarContainer, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size))
transition.setPosition(view: self.avatarBackgroundContainer, position: avatarFrame.center) transition.setPosition(view: self.avatarBackgroundContainer, position: avatarFrame.center)
@ -517,7 +572,7 @@ public final class StoryPeerListItemComponent: Component {
self.indicatorColorLayer.colors = colors self.indicatorColorLayer.colors = colors
} }
transition.setPosition(layer: self.indicatorColorLayer, position: indicatorFrame.center) transition.setPosition(layer: self.indicatorColorLayer, position: indicatorFrame.offsetBy(dx: -avatarFrame.minX, dy: -avatarFrame.minY).center)
transition.setBounds(layer: self.indicatorColorLayer, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size)) transition.setBounds(layer: self.indicatorColorLayer, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size))
transition.setPosition(layer: self.indicatorShapeLayer, position: CGPoint(x: indicatorFrame.width * 0.5, y: indicatorFrame.height * 0.5)) transition.setPosition(layer: self.indicatorShapeLayer, position: CGPoint(x: indicatorFrame.width * 0.5, y: indicatorFrame.height * 0.5))
transition.setBounds(layer: self.indicatorShapeLayer, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size)) transition.setBounds(layer: self.indicatorShapeLayer, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size))

View File

@ -96,6 +96,7 @@ import LegacyCamera
import LegacyInstantVideoController import LegacyInstantVideoController
import StoryContainerScreen import StoryContainerScreen
import StoryContentComponent import StoryContentComponent
import MoreHeaderButton
#if DEBUG #if DEBUG
import os.signpost import os.signpost