mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-25 09:32:46 +00:00
Merge branches 'master' and 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
81c5ce4af9
@ -785,10 +785,6 @@ private final class NotificationServiceHandler {
|
|||||||
var recordId: AccountRecordId?
|
var recordId: AccountRecordId?
|
||||||
var isCurrentAccount: Bool = false
|
var isCurrentAccount: Bool = false
|
||||||
|
|
||||||
let loggingSettings = sharedData.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings
|
|
||||||
Logger.shared.logToFile = loggingSettings.logToFile
|
|
||||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
|
||||||
|
|
||||||
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
|
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
|
||||||
automaticMediaDownloadSettings = value
|
automaticMediaDownloadSettings = value
|
||||||
|
|||||||
@ -2851,50 +2851,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
|
||||||
let isMuted = resolvedAreStoriesMuted(globalSettings: globalSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings._asNotificationSettings(), topSearchPeers: topSearchPeers)
|
|
||||||
items.append(.action(ContextMenuActionItem(text: isMuted ? self.presentationData.strings.StoryFeed_ContextNotifyOn : self.presentationData.strings.StoryFeed_ContextNotifyOff, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor)
|
|
||||||
}, action: { [weak self] _, f in
|
|
||||||
f(.default)
|
|
||||||
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let _ = self.context.engine.peers.togglePeerStoriesMuted(peerId: peer.id).start()
|
|
||||||
|
|
||||||
let iconColor = UIColor.white
|
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
if isMuted {
|
|
||||||
self.present(UndoOverlayController(
|
|
||||||
presentationData: presentationData,
|
|
||||||
content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
|
|
||||||
"Middle.Group 1.Fill 1": iconColor,
|
|
||||||
"Top.Group 1.Fill 1": iconColor,
|
|
||||||
"Bottom.Group 1.Fill 1": iconColor,
|
|
||||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
|
||||||
"Line.Group 1.Stroke 1": iconColor
|
|
||||||
], title: nil, text: presentationData.strings.StoryFeed_TooltipNotifyOn(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, customUndoText: nil, timeout: nil),
|
|
||||||
elevatedLayout: false,
|
|
||||||
animateInAsReplacement: false,
|
|
||||||
action: { _ in return false }
|
|
||||||
), in: .current)
|
|
||||||
} else {
|
|
||||||
self.present(UndoOverlayController(
|
|
||||||
presentationData: presentationData,
|
|
||||||
content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
|
||||||
"Middle.Group 1.Fill 1": iconColor,
|
|
||||||
"Top.Group 1.Fill 1": iconColor,
|
|
||||||
"Bottom.Group 1.Fill 1": iconColor,
|
|
||||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
|
||||||
"Line.Group 1.Stroke 1": iconColor
|
|
||||||
], title: nil, text: presentationData.strings.StoryFeed_TooltipNotifyOff(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, customUndoText: nil, timeout: nil),
|
|
||||||
elevatedLayout: false,
|
|
||||||
animateInAsReplacement: false,
|
|
||||||
action: { _ in return false }
|
|
||||||
), in: .current)
|
|
||||||
}
|
|
||||||
})))
|
|
||||||
|
|
||||||
let hideText: String
|
let hideText: String
|
||||||
if self.location == .chatList(groupId: .archive) {
|
if self.location == .chatList(groupId: .archive) {
|
||||||
hideText = self.presentationData.strings.StoryFeed_ContextUnarchive
|
hideText = self.presentationData.strings.StoryFeed_ContextUnarchive
|
||||||
|
|||||||
@ -545,6 +545,12 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
|||||||
public final class EmojiTextAttachmentView: UIView {
|
public final class EmojiTextAttachmentView: UIView {
|
||||||
private let contentLayer: InlineStickerItemLayer
|
private let contentLayer: InlineStickerItemLayer
|
||||||
|
|
||||||
|
public var isActive: Bool = true {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public convenience init(context: AccountContext, userLocation: MediaResourceUserLocation, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) {
|
public convenience init(context: AccountContext, userLocation: MediaResourceUserLocation, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) {
|
||||||
self.init(
|
self.init(
|
||||||
context: .account(context),
|
context: .account(context),
|
||||||
|
|||||||
@ -146,6 +146,26 @@ public final class LottieComponent: Component {
|
|||||||
|
|
||||||
private var currentTemplateFrameImage: UIImage?
|
private var currentTemplateFrameImage: UIImage?
|
||||||
|
|
||||||
|
public var externalShouldPlay: Bool? {
|
||||||
|
didSet {
|
||||||
|
if self.externalShouldPlay != oldValue {
|
||||||
|
self.visibilityUpdated()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isEffectivelyVisible: Bool {
|
||||||
|
if !self.isVisible {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if let externalShouldPlay = self.externalShouldPlay {
|
||||||
|
if !externalShouldPlay {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
public weak var output: UIImageView? {
|
public weak var output: UIImageView? {
|
||||||
didSet {
|
didSet {
|
||||||
if let output = self.output, let currentTemplateFrameImage = self.currentTemplateFrameImage {
|
if let output = self.output, let currentTemplateFrameImage = self.currentTemplateFrameImage {
|
||||||
@ -190,10 +210,14 @@ public final class LottieComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func visibilityUpdated() {
|
private func visibilityUpdated() {
|
||||||
if self.isVisible {
|
if self.isEffectivelyVisible {
|
||||||
if self.scheduledPlayOnce {
|
if self.scheduledPlayOnce {
|
||||||
self.playOnce()
|
self.playOnce()
|
||||||
|
} else {
|
||||||
|
self.displayLink?.isPaused = false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.displayLink?.isPaused = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +228,7 @@ public final class LottieComponent: Component {
|
|||||||
self.scheduledPlayOnce = true
|
self.scheduledPlayOnce = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !self.isVisible {
|
if !self.isEffectivelyVisible {
|
||||||
self.scheduledPlayOnce = true
|
self.scheduledPlayOnce = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -431,6 +431,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
let blurEffect = UIBlurEffect(style: style)
|
let blurEffect = UIBlurEffect(style: style)
|
||||||
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
|
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
|
||||||
let vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
|
let vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
|
||||||
|
vibrancyEffectView.alpha = 0.0
|
||||||
self.vibrancyEffectView = vibrancyEffectView
|
self.vibrancyEffectView = vibrancyEffectView
|
||||||
|
|
||||||
self.mediaRecordingVibrancyContainer = UIView()
|
self.mediaRecordingVibrancyContainer = UIView()
|
||||||
@ -791,6 +792,9 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
|
|
||||||
transition.setFrame(view: self.vibrancyEffectView, frame: CGRect(origin: CGPoint(), size: fieldBackgroundFrame.size))
|
transition.setFrame(view: self.vibrancyEffectView, frame: CGRect(origin: CGPoint(), size: fieldBackgroundFrame.size))
|
||||||
self.vibrancyEffectView.isHidden = component.style == .media
|
self.vibrancyEffectView.isHidden = component.style == .media
|
||||||
|
if isEditing {
|
||||||
|
self.vibrancyEffectView.alpha = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
transition.setFrame(view: self.fieldBackgroundView, frame: fieldBackgroundFrame)
|
transition.setFrame(view: self.fieldBackgroundView, frame: fieldBackgroundFrame)
|
||||||
self.fieldBackgroundView.update(size: fieldBackgroundFrame.size, cornerRadius: baseFieldHeight * 0.5, transition: transition.containedViewLayoutTransition)
|
self.fieldBackgroundView.update(size: fieldBackgroundFrame.size, cornerRadius: baseFieldHeight * 0.5, transition: transition.containedViewLayoutTransition)
|
||||||
|
|||||||
@ -919,6 +919,8 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
public var openCurrentDate: (() -> Void)?
|
public var openCurrentDate: (() -> Void)?
|
||||||
public var paneDidScroll: (() -> Void)?
|
public var paneDidScroll: (() -> Void)?
|
||||||
public var emptyAction: (() -> Void)?
|
public var emptyAction: (() -> Void)?
|
||||||
|
|
||||||
|
public var ensureRectVisible: ((UIView, CGRect) -> Void)?
|
||||||
|
|
||||||
private weak var currentGestureItem: SparseItemGridDisplayItem?
|
private weak var currentGestureItem: SparseItemGridDisplayItem?
|
||||||
|
|
||||||
@ -1116,6 +1118,21 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.itemInteraction.hiddenMedia = Set([itemId.id])
|
self.itemInteraction.hiddenMedia = Set([itemId.id])
|
||||||
if let items = self.items, let item = items.items.first(where: { $0.id == AnyHashable(itemId.id) }) {
|
if let items = self.items, let item = items.items.first(where: { $0.id == AnyHashable(itemId.id) }) {
|
||||||
self.itemGrid.ensureItemVisible(index: item.index, anyAmount: anyAmount)
|
self.itemGrid.ensureItemVisible(index: item.index, anyAmount: anyAmount)
|
||||||
|
|
||||||
|
if !anyAmount {
|
||||||
|
var foundItemLayer: SparseItemGridLayer?
|
||||||
|
self.itemGrid.forEachVisibleItem { item in
|
||||||
|
guard let itemLayer = item.layer as? ItemLayer else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let listItem = itemLayer.item, listItem.story.id == itemId.id {
|
||||||
|
foundItemLayer = itemLayer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let foundItemLayer {
|
||||||
|
self.ensureRectVisible?(self.view, self.itemGrid.frameForItem(layer: foundItemLayer))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.itemInteraction.hiddenMedia = Set()
|
self.itemInteraction.hiddenMedia = Set()
|
||||||
|
|||||||
@ -1550,7 +1550,8 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
closeFriends: self.closeFriendsPromise,
|
closeFriends: self.closeFriendsPromise,
|
||||||
blockedPeers: self.blockedPeers,
|
blockedPeers: self.blockedPeers,
|
||||||
sharedViewListsContext: self.sharedViewListsContext,
|
sharedViewListsContext: self.sharedViewListsContext,
|
||||||
stealthModeTimeout: stealthModeTimeout
|
stealthModeTimeout: stealthModeTimeout,
|
||||||
|
isDismissed: self.isDismissedExlusively
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: itemSetContainerSize
|
containerSize: itemSetContainerSize
|
||||||
@ -1697,6 +1698,7 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
itemSetView.removeFromSuperview()
|
itemSetView.removeFromSuperview()
|
||||||
|
|
||||||
if let view = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
if let view = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||||
|
view.saveDraft()
|
||||||
view.transitionCloneContainerView.removeFromSuperview()
|
view.transitionCloneContainerView.removeFromSuperview()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -280,6 +280,10 @@ final class StoryItemContentComponent: Component {
|
|||||||
if self.progressMode != progressMode {
|
if self.progressMode != progressMode {
|
||||||
self.progressMode = progressMode
|
self.progressMode = progressMode
|
||||||
self.updateProgressMode(update: true)
|
self.updateProgressMode(update: true)
|
||||||
|
|
||||||
|
if let component = self.component, !self.overlaysView.bounds.isEmpty {
|
||||||
|
self.updateOverlays(component: component, size: self.overlaysView.bounds.size, synchronousLoad: false, transition: .immediate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,6 +487,22 @@ final class StoryItemContentComponent: Component {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateOverlays(component: StoryItemContentComponent, size: CGSize, synchronousLoad: Bool, transition: Transition) {
|
||||||
|
self.overlaysView.update(
|
||||||
|
context: component.context,
|
||||||
|
strings: component.strings,
|
||||||
|
peer: component.peer,
|
||||||
|
story: component.item,
|
||||||
|
availableReactions: component.availableReactions,
|
||||||
|
entityFiles: component.entityFiles,
|
||||||
|
size: size,
|
||||||
|
isCaptureProtected: component.item.isForwardingDisabled,
|
||||||
|
attemptSynchronous: synchronousLoad,
|
||||||
|
isActive: self.progressMode == .play,
|
||||||
|
transition: transition
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func update(component: StoryItemContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<StoryContentItem.Environment>, transition: Transition) -> CGSize {
|
func update(component: StoryItemContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<StoryContentItem.Environment>, transition: Transition) -> CGSize {
|
||||||
let previousItem = self.component?.item
|
let previousItem = self.component?.item
|
||||||
|
|
||||||
@ -610,18 +630,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
attemptSynchronous: synchronousLoad,
|
attemptSynchronous: synchronousLoad,
|
||||||
transition: transition
|
transition: transition
|
||||||
)
|
)
|
||||||
self.overlaysView.update(
|
self.updateOverlays(component: component, size: availableSize, synchronousLoad: synchronousLoad, transition: transition)
|
||||||
context: component.context,
|
|
||||||
strings: component.strings,
|
|
||||||
peer: component.peer,
|
|
||||||
story: component.item,
|
|
||||||
availableReactions: component.availableReactions,
|
|
||||||
entityFiles: component.entityFiles,
|
|
||||||
size: availableSize,
|
|
||||||
isCaptureProtected: component.item.isForwardingDisabled,
|
|
||||||
attemptSynchronous: synchronousLoad,
|
|
||||||
transition: transition
|
|
||||||
)
|
|
||||||
applyState = true
|
applyState = true
|
||||||
if self.imageView.isContentLoaded {
|
if self.imageView.isContentLoaded {
|
||||||
self.contentLoaded = true
|
self.contentLoaded = true
|
||||||
|
|||||||
@ -19,6 +19,38 @@ import AnimatedCountLabelNode
|
|||||||
import LottieComponent
|
import LottieComponent
|
||||||
import LottieComponentResourceContent
|
import LottieComponentResourceContent
|
||||||
|
|
||||||
|
public final class StaticStoryItemOverlaysView: UIImageView {
|
||||||
|
override public init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update(
|
||||||
|
context: AccountContext,
|
||||||
|
peer: EnginePeer,
|
||||||
|
story: EngineStoryItem,
|
||||||
|
availableReactions: StoryAvailableReactions?,
|
||||||
|
entityFiles: [MediaId: TelegramMediaFile]
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func draw(_ rect: CGRect) {
|
||||||
|
guard let context = UIGraphicsGetCurrentContext() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class StoryItemOverlaysView: UIView {
|
final class StoryItemOverlaysView: UIView {
|
||||||
static let counterFont: UIFont = {
|
static let counterFont: UIFont = {
|
||||||
return Font.with(size: 17.0, design: .camera, weight: .semibold, traits: .monospacedNumbers)
|
return Font.with(size: 17.0, design: .camera, weight: .semibold, traits: .monospacedNumbers)
|
||||||
@ -105,7 +137,8 @@ final class StoryItemOverlaysView: UIView {
|
|||||||
availableReactions: StoryAvailableReactions?,
|
availableReactions: StoryAvailableReactions?,
|
||||||
entityFiles: [MediaId: TelegramMediaFile],
|
entityFiles: [MediaId: TelegramMediaFile],
|
||||||
synchronous: Bool,
|
synchronous: Bool,
|
||||||
size: CGSize
|
size: CGSize,
|
||||||
|
isActive: Bool
|
||||||
) {
|
) {
|
||||||
var transition = Transition(animation: .curve(duration: 0.18, curve: .easeInOut))
|
var transition = Transition(animation: .curve(duration: 0.18, curve: .easeInOut))
|
||||||
if self.reaction == nil {
|
if self.reaction == nil {
|
||||||
@ -291,9 +324,11 @@ final class StoryItemOverlaysView: UIView {
|
|||||||
stickerTransition.setPosition(view: customEmojiView, position: stickerFrame.center)
|
stickerTransition.setPosition(view: customEmojiView, position: stickerFrame.center)
|
||||||
stickerTransition.setBounds(view: customEmojiView, bounds: CGRect(origin: CGPoint(), size: stickerFrame.size))
|
stickerTransition.setBounds(view: customEmojiView, bounds: CGRect(origin: CGPoint(), size: stickerFrame.size))
|
||||||
stickerTransition.setScale(view: customEmojiView, scale: stickerScale)
|
stickerTransition.setScale(view: customEmojiView, scale: stickerScale)
|
||||||
|
|
||||||
|
customEmojiView.isActive = isActive
|
||||||
}
|
}
|
||||||
|
|
||||||
if let directStickerView = self.directStickerView?.view {
|
if let directStickerView = self.directStickerView?.view as? LottieComponent.View {
|
||||||
var stickerTransition = transition
|
var stickerTransition = transition
|
||||||
if directStickerView.superview == nil {
|
if directStickerView.superview == nil {
|
||||||
self.addSubview(directStickerView)
|
self.addSubview(directStickerView)
|
||||||
@ -314,6 +349,8 @@ final class StoryItemOverlaysView: UIView {
|
|||||||
stickerTransition.setPosition(view: directStickerView, position: stickerFrame.center)
|
stickerTransition.setPosition(view: directStickerView, position: stickerFrame.center)
|
||||||
stickerTransition.setBounds(view: directStickerView, bounds: CGRect(origin: CGPoint(), size: stickerFrame.size))
|
stickerTransition.setBounds(view: directStickerView, bounds: CGRect(origin: CGPoint(), size: stickerFrame.size))
|
||||||
stickerTransition.setScale(view: directStickerView, scale: stickerScale)
|
stickerTransition.setScale(view: directStickerView, scale: stickerScale)
|
||||||
|
|
||||||
|
directStickerView.externalShouldPlay = isActive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,6 +389,7 @@ final class StoryItemOverlaysView: UIView {
|
|||||||
size: CGSize,
|
size: CGSize,
|
||||||
isCaptureProtected: Bool,
|
isCaptureProtected: Bool,
|
||||||
attemptSynchronous: Bool,
|
attemptSynchronous: Bool,
|
||||||
|
isActive: Bool,
|
||||||
transition: Transition
|
transition: Transition
|
||||||
) {
|
) {
|
||||||
var nextId = 0
|
var nextId = 0
|
||||||
@ -400,7 +438,8 @@ final class StoryItemOverlaysView: UIView {
|
|||||||
availableReactions: availableReactions,
|
availableReactions: availableReactions,
|
||||||
entityFiles: entityFiles,
|
entityFiles: entityFiles,
|
||||||
synchronous: attemptSynchronous,
|
synchronous: attemptSynchronous,
|
||||||
size: targetFrame.size
|
size: targetFrame.size,
|
||||||
|
isActive: isActive
|
||||||
)
|
)
|
||||||
|
|
||||||
nextId += 1
|
nextId += 1
|
||||||
|
|||||||
@ -124,6 +124,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
public let blockedPeers: BlockedPeersContext?
|
public let blockedPeers: BlockedPeersContext?
|
||||||
let sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext
|
let sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext
|
||||||
let stealthModeTimeout: Int32?
|
let stealthModeTimeout: Int32?
|
||||||
|
public let isDismissed: Bool
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
@ -158,7 +159,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
closeFriends: Promise<[EnginePeer]>,
|
closeFriends: Promise<[EnginePeer]>,
|
||||||
blockedPeers: BlockedPeersContext?,
|
blockedPeers: BlockedPeersContext?,
|
||||||
sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext,
|
sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext,
|
||||||
stealthModeTimeout: Int32?
|
stealthModeTimeout: Int32?,
|
||||||
|
isDismissed: Bool
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.externalState = externalState
|
self.externalState = externalState
|
||||||
@ -193,6 +195,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
self.blockedPeers = blockedPeers
|
self.blockedPeers = blockedPeers
|
||||||
self.sharedViewListsContext = sharedViewListsContext
|
self.sharedViewListsContext = sharedViewListsContext
|
||||||
self.stealthModeTimeout = stealthModeTimeout
|
self.stealthModeTimeout = stealthModeTimeout
|
||||||
|
self.isDismissed = isDismissed
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: StoryItemSetContainerComponent, rhs: StoryItemSetContainerComponent) -> Bool {
|
public static func ==(lhs: StoryItemSetContainerComponent, rhs: StoryItemSetContainerComponent) -> Bool {
|
||||||
@ -253,6 +256,9 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
if lhs.stealthModeTimeout != rhs.stealthModeTimeout {
|
if lhs.stealthModeTimeout != rhs.stealthModeTimeout {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isDismissed != rhs.isDismissed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,10 +482,13 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
|
|
||||||
private var isAnimatingOut: Bool = false
|
private var isAnimatingOut: Bool = false
|
||||||
|
|
||||||
|
private var scheduledStoryUnpinnedUndoOverlay: ViewController?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.sendMessageContext = StoryItemSetContainerSendMessage()
|
self.sendMessageContext = StoryItemSetContainerSendMessage()
|
||||||
|
|
||||||
self.componentContainerView = UIView()
|
self.componentContainerView = UIView()
|
||||||
|
|
||||||
self.overlayContainerView = SparseContainerView()
|
self.overlayContainerView = SparseContainerView()
|
||||||
|
|
||||||
self.itemsContainerView = UIView()
|
self.itemsContainerView = UIView()
|
||||||
@ -2017,6 +2026,14 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateOut(transitionOut: StoryContainerScreen.TransitionOut, transitionCloneMasterView: UIView, completion: @escaping () -> Void) {
|
func animateOut(transitionOut: StoryContainerScreen.TransitionOut, transitionCloneMasterView: UIView, completion: @escaping () -> Void) {
|
||||||
|
func fixScale(layer: CALayer) {
|
||||||
|
layer.rasterizationScale = UIScreenScale
|
||||||
|
|
||||||
|
for sublayer in layer.sublayers ?? [] {
|
||||||
|
fixScale(layer: sublayer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cleanups: [() -> Void] = []
|
var cleanups: [() -> Void] = []
|
||||||
|
|
||||||
self.isAnimatingOut = true
|
self.isAnimatingOut = true
|
||||||
@ -2142,6 +2159,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
var transitionViewsImpl: [UIView] = []
|
var transitionViewsImpl: [UIView] = []
|
||||||
|
|
||||||
if let transitionViewImpl = transitionView?.makeView() {
|
if let transitionViewImpl = transitionView?.makeView() {
|
||||||
|
fixScale(layer: transitionViewImpl.layer)
|
||||||
transitionViewsImpl.append(transitionViewImpl)
|
transitionViewsImpl.append(transitionViewImpl)
|
||||||
|
|
||||||
let transitionSourceContainerView = UIView(frame: self.bounds)
|
let transitionSourceContainerView = UIView(frame: self.bounds)
|
||||||
@ -2152,6 +2170,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
|
|
||||||
if let insertCloneTransitionView = transitionView?.insertCloneTransitionView {
|
if let insertCloneTransitionView = transitionView?.insertCloneTransitionView {
|
||||||
if let transitionCloneViewImpl = transitionView?.makeView() {
|
if let transitionCloneViewImpl = transitionView?.makeView() {
|
||||||
|
fixScale(layer: transitionCloneViewImpl.layer)
|
||||||
transitionViewsImpl.append(transitionCloneViewImpl)
|
transitionViewsImpl.append(transitionCloneViewImpl)
|
||||||
|
|
||||||
transitionCloneMasterView.isUserInteractionEnabled = false
|
transitionCloneMasterView.isUserInteractionEnabled = false
|
||||||
@ -2262,6 +2281,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
var transitionViewsImpl: [UIView] = []
|
var transitionViewsImpl: [UIView] = []
|
||||||
|
|
||||||
if let transitionViewImpl = transitionView?.makeView() {
|
if let transitionViewImpl = transitionView?.makeView() {
|
||||||
|
fixScale(layer: transitionViewImpl.layer)
|
||||||
transitionViewsImpl.append(transitionViewImpl)
|
transitionViewsImpl.append(transitionViewImpl)
|
||||||
|
|
||||||
let transitionSourceContainerView = UIView(frame: self.bounds)
|
let transitionSourceContainerView = UIView(frame: self.bounds)
|
||||||
@ -2272,6 +2292,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
|
|
||||||
if let insertCloneTransitionView = transitionView?.insertCloneTransitionView {
|
if let insertCloneTransitionView = transitionView?.insertCloneTransitionView {
|
||||||
if let transitionCloneViewImpl = transitionView?.makeView() {
|
if let transitionCloneViewImpl = transitionView?.makeView() {
|
||||||
|
fixScale(layer: transitionCloneViewImpl.layer)
|
||||||
transitionViewsImpl.append(transitionCloneViewImpl)
|
transitionViewsImpl.append(transitionCloneViewImpl)
|
||||||
|
|
||||||
transitionCloneMasterView.isUserInteractionEnabled = false
|
transitionCloneMasterView.isUserInteractionEnabled = false
|
||||||
@ -2413,6 +2434,19 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
let _ = ApplicationSpecificNotice.setDisplayStoryReactionTooltip(accountManager: component.context.sharedContext.accountManager).start()
|
let _ = ApplicationSpecificNotice.setDisplayStoryReactionTooltip(accountManager: component.context.sharedContext.accountManager).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func saveDraft() {
|
||||||
|
guard let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||||
|
let previousInput = inputPanelView.getSendMessageInput()
|
||||||
|
switch previousInput {
|
||||||
|
case let .text(value):
|
||||||
|
component.storyItemSharedState.replyDrafts[StoryId(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id)] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func update(component: StoryItemSetContainerComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(component: StoryItemSetContainerComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
let isFirstTime = self.component == nil
|
let isFirstTime = self.component == nil
|
||||||
|
|
||||||
@ -2448,15 +2482,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
|
|
||||||
resetInputContents = .text(NSAttributedString())
|
resetInputContents = .text(NSAttributedString())
|
||||||
|
|
||||||
if let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View {
|
self.saveDraft()
|
||||||
if let previousComponent = self.component {
|
|
||||||
let previousInput = inputPanelView.getSendMessageInput()
|
|
||||||
switch previousInput {
|
|
||||||
case let .text(value):
|
|
||||||
component.storyItemSharedState.replyDrafts[StoryId(peerId: previousComponent.slice.peer.id, id: previousComponent.slice.item.storyItem.id)] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let draft = component.storyItemSharedState.replyDrafts[StoryId(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id)] {
|
if let draft = component.storyItemSharedState.replyDrafts[StoryId(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id)] {
|
||||||
resetInputContents = .text(draft)
|
resetInputContents = .text(draft)
|
||||||
}
|
}
|
||||||
@ -4590,6 +4616,13 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let scheduledStoryUnpinnedUndoOverlay = self.scheduledStoryUnpinnedUndoOverlay {
|
||||||
|
self.scheduledStoryUnpinnedUndoOverlay = nil
|
||||||
|
if !self.isAnimatingOut && !component.isDismissed {
|
||||||
|
component.presentController(scheduledStoryUnpinnedUndoOverlay, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return contentSize
|
return contentSize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5247,8 +5280,26 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
if component.slice.peer.id == component.context.account.peerId {
|
if component.slice.peer.id == component.context.account.peerId {
|
||||||
self.performMyMoreAction(sourceView: sourceView, gesture: gesture)
|
self.performMyMoreAction(sourceView: sourceView, gesture: gesture)
|
||||||
} else if case let .channel(channel) = component.slice.peer, channel.hasPermission(.sendSomething) {
|
} else if case let .channel(channel) = component.slice.peer {
|
||||||
self.performMyChannelMoreAction(sourceView: sourceView, gesture: gesture)
|
var canPerformStoryActions = false
|
||||||
|
|
||||||
|
if channel.hasPermission(.editStories) {
|
||||||
|
canPerformStoryActions = true
|
||||||
|
} else if component.slice.item.storyItem.isMy && channel.hasPermission(.postStories) {
|
||||||
|
canPerformStoryActions = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if channel.hasPermission(.deleteStories) {
|
||||||
|
canPerformStoryActions = true
|
||||||
|
} else if component.slice.item.storyItem.isMy && channel.hasPermission(.postStories) {
|
||||||
|
canPerformStoryActions = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if canPerformStoryActions {
|
||||||
|
self.performMyChannelMoreAction(sourceView: sourceView, gesture: gesture)
|
||||||
|
} else {
|
||||||
|
self.performOtherMoreAction(sourceView: sourceView, gesture: gesture)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.performOtherMoreAction(sourceView: sourceView, gesture: gesture)
|
self.performOtherMoreAction(sourceView: sourceView, gesture: gesture)
|
||||||
}
|
}
|
||||||
@ -5265,9 +5316,13 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var likeButtonView: UIView?
|
var likeButtonView: UIView?
|
||||||
|
var addTracingOffset: ((UIView) -> Void)?
|
||||||
|
|
||||||
if let visibleItem = self.visibleItems[component.slice.item.storyItem.id], let footerPanelView = visibleItem.footerPanel?.view as? StoryFooterPanelComponent.View {
|
if let visibleItem = self.visibleItems[component.slice.item.storyItem.id], let footerPanelView = visibleItem.footerPanel?.view as? StoryFooterPanelComponent.View {
|
||||||
likeButtonView = footerPanelView.likeButtonView
|
likeButtonView = footerPanelView.likeButtonView
|
||||||
|
addTracingOffset = { [weak footerPanelView] view in
|
||||||
|
footerPanelView?.setLikeButtonTracingOffset(view: view)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
guard let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View else {
|
guard let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View else {
|
||||||
return
|
return
|
||||||
@ -5338,6 +5393,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
standaloneReactionAnimation?.view.removeFromSuperview()
|
standaloneReactionAnimation?.view.removeFromSuperview()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addTracingOffset?(standaloneReactionAnimation.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
if component.slice.item.storyItem.myReaction != nil {
|
if component.slice.item.storyItem.myReaction != nil {
|
||||||
@ -5721,14 +5778,14 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme)
|
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme)
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
if component.slice.item.storyItem.isPinned {
|
if component.slice.item.storyItem.isPinned {
|
||||||
self.component?.presentController(UndoOverlayController(
|
self.scheduledStoryUnpinnedUndoOverlay = UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .info(title: nil, text: "Story removed from the channel's profile", timeout: nil),
|
content: .info(title: nil, text: "Story removed from the channel's profile", timeout: nil),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
animateInAsReplacement: false,
|
animateInAsReplacement: false,
|
||||||
blurred: true,
|
blurred: true,
|
||||||
action: { _ in return false }
|
action: { _ in return false }
|
||||||
), nil)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.component?.presentController(UndoOverlayController(
|
self.component?.presentController(UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
@ -6016,20 +6073,22 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_ContextStealthMode, icon: { theme in
|
if case .user = component.slice.peer {
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: accountUser.isPremium ? "Chat/Context Menu/Eye" : "Chat/Context Menu/EyeLocked"), color: theme.contextMenu.primaryColor)
|
items.append(.action(ContextMenuActionItem(text: component.strings.Story_ContextStealthMode, icon: { theme in
|
||||||
}, action: { [weak self] _, a in
|
return generateTintedImage(image: UIImage(bundleImageName: accountUser.isPremium ? "Chat/Context Menu/Eye" : "Chat/Context Menu/EyeLocked"), color: theme.contextMenu.primaryColor)
|
||||||
a(.default)
|
}, action: { [weak self] _, a in
|
||||||
|
a(.default)
|
||||||
guard let self else {
|
|
||||||
return
|
guard let self else {
|
||||||
}
|
return
|
||||||
if accountUser.isPremium {
|
}
|
||||||
self.sendMessageContext.requestStealthMode(view: self)
|
if accountUser.isPremium {
|
||||||
} else {
|
self.sendMessageContext.requestStealthMode(view: self)
|
||||||
self.presentStealthModeUpgradeScreen()
|
} else {
|
||||||
}
|
self.presentStealthModeUpgradeScreen()
|
||||||
})))
|
}
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
if !component.slice.peer.isService && component.slice.item.storyItem.isPublic && (component.slice.peer.addressName != nil || !component.slice.peer._asPeer().usernames.isEmpty) {
|
if !component.slice.peer.isService && component.slice.item.storyItem.isPublic && (component.slice.peer.addressName != nil || !component.slice.peer._asPeer().usernames.isEmpty) {
|
||||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_CopyLink, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_CopyLink, icon: { theme in
|
||||||
|
|||||||
@ -137,6 +137,8 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
|
|
||||||
public let externalContainerView: UIView
|
public let externalContainerView: UIView
|
||||||
|
|
||||||
|
private weak var likeButtonTracingOffsetView: UIView?
|
||||||
|
|
||||||
public var likeButtonView: UIView? {
|
public var likeButtonView: UIView? {
|
||||||
return self.likeButton?.view
|
return self.likeButton?.view
|
||||||
}
|
}
|
||||||
@ -197,6 +199,10 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
self.uploadProgressDisposable?.dispose()
|
self.uploadProgressDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func setLikeButtonTracingOffset(view: UIView) {
|
||||||
|
self.likeButtonTracingOffsetView = view
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func viewStatsPressed() {
|
@objc private func viewStatsPressed() {
|
||||||
guard let component = self.component else {
|
guard let component = self.component else {
|
||||||
return
|
return
|
||||||
@ -457,6 +463,13 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
var likeButtonFrame = CGRect(origin: CGPoint(x: rightContentOffset - likeButtonSize.width, y: floor((size.height - likeButtonSize.height) * 0.5)), size: likeButtonSize)
|
var likeButtonFrame = CGRect(origin: CGPoint(x: rightContentOffset - likeButtonSize.width, y: floor((size.height - likeButtonSize.height) * 0.5)), size: likeButtonSize)
|
||||||
likeButtonFrame.origin.y += component.expandFraction * 45.0
|
likeButtonFrame.origin.y += component.expandFraction * 45.0
|
||||||
|
|
||||||
|
if let likeButtonTracingOffsetView = self.likeButtonTracingOffsetView {
|
||||||
|
let difference = CGPoint(x: likeButtonFrame.midX - likeButtonView.layer.position.x, y: likeButtonFrame.midY - likeButtonView.layer.position.y)
|
||||||
|
if difference != CGPoint() {
|
||||||
|
likeStatsTransition.setPosition(view: likeButtonTracingOffsetView, position: likeButtonTracingOffsetView.layer.position.offsetBy(dx: difference.x, dy: difference.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
likeStatsTransition.setPosition(view: likeButtonView, position: likeButtonFrame.center)
|
likeStatsTransition.setPosition(view: likeButtonView, position: likeButtonFrame.center)
|
||||||
likeStatsTransition.setBounds(view: likeButtonView, bounds: CGRect(origin: CGPoint(), size: likeButtonFrame.size))
|
likeStatsTransition.setBounds(view: likeButtonView, bounds: CGRect(origin: CGPoint(), size: likeButtonFrame.size))
|
||||||
likeStatsTransition.setAlpha(view: likeButtonView, alpha: 1.0 - component.expandFraction)
|
likeStatsTransition.setAlpha(view: likeButtonView, alpha: 1.0 - component.expandFraction)
|
||||||
|
|||||||
@ -321,6 +321,7 @@ public final class StoryPeerListItemComponent: Component {
|
|||||||
|
|
||||||
if let itemView {
|
if let itemView {
|
||||||
if let portalView = PortalView(matchPosition: false) {
|
if let portalView = PortalView(matchPosition: false) {
|
||||||
|
portalView.view.layer.rasterizationScale = UIScreenScale
|
||||||
itemView.avatarContent.addPortal(view: portalView)
|
itemView.avatarContent.addPortal(view: portalView)
|
||||||
self.portalView = portalView
|
self.portalView = portalView
|
||||||
self.addSubview(portalView.view)
|
self.addSubview(portalView.view)
|
||||||
|
|||||||
@ -362,7 +362,8 @@ private final class PeerInfoPendingPane {
|
|||||||
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
|
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
|
||||||
parentController: ViewController?,
|
parentController: ViewController?,
|
||||||
openMediaCalendar: @escaping () -> Void,
|
openMediaCalendar: @escaping () -> Void,
|
||||||
paneDidScroll: @escaping () -> Void
|
paneDidScroll: @escaping () -> Void,
|
||||||
|
ensureRectVisible: @escaping (UIView, CGRect) -> Void
|
||||||
) {
|
) {
|
||||||
let captureProtected = data.peer?.isCopyProtectionEnabled ?? false
|
let captureProtected = data.peer?.isCopyProtectionEnabled ?? false
|
||||||
let paneNode: PeerInfoPaneNode
|
let paneNode: PeerInfoPaneNode
|
||||||
@ -376,6 +377,9 @@ private final class PeerInfoPendingPane {
|
|||||||
visualPaneNode.paneDidScroll = {
|
visualPaneNode.paneDidScroll = {
|
||||||
paneDidScroll()
|
paneDidScroll()
|
||||||
}
|
}
|
||||||
|
visualPaneNode.ensureRectVisible = { sourceView, rect in
|
||||||
|
ensureRectVisible(sourceView, rect)
|
||||||
|
}
|
||||||
case .media:
|
case .media:
|
||||||
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected)
|
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
@ -487,6 +491,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
var openMediaCalendar: (() -> Void)?
|
var openMediaCalendar: (() -> Void)?
|
||||||
var paneDidScroll: (() -> Void)?
|
var paneDidScroll: (() -> Void)?
|
||||||
|
|
||||||
|
var ensurePaneRectVisible: ((UIView, CGRect) -> Void)?
|
||||||
|
|
||||||
private var currentAvailablePanes: [PeerInfoPaneKey]?
|
private var currentAvailablePanes: [PeerInfoPaneKey]?
|
||||||
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||||
|
|
||||||
@ -698,6 +704,10 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
let previousCurrentPaneKey = self.currentPaneKey
|
let previousCurrentPaneKey = self.currentPaneKey
|
||||||
var updateCurrentPaneStatus = false
|
var updateCurrentPaneStatus = false
|
||||||
|
|
||||||
|
if let previousAvailablePanes, !previousAvailablePanes.contains(.stories), availablePanes.contains(.stories) {
|
||||||
|
self.pendingSwitchToPaneKey = .stories
|
||||||
|
}
|
||||||
|
|
||||||
if let currentPaneKey = self.currentPaneKey, !availablePanes.contains(currentPaneKey) {
|
if let currentPaneKey = self.currentPaneKey, !availablePanes.contains(currentPaneKey) {
|
||||||
var nextCandidatePaneKey: PeerInfoPaneKey?
|
var nextCandidatePaneKey: PeerInfoPaneKey?
|
||||||
if let previousAvailablePanes = previousAvailablePanes, let index = previousAvailablePanes.firstIndex(of: currentPaneKey), index != 0 {
|
if let previousAvailablePanes = previousAvailablePanes, let index = previousAvailablePanes.firstIndex(of: currentPaneKey), index != 0 {
|
||||||
@ -816,6 +826,12 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
},
|
},
|
||||||
paneDidScroll: { [weak self] in
|
paneDidScroll: { [weak self] in
|
||||||
self?.paneDidScroll?()
|
self?.paneDidScroll?()
|
||||||
|
},
|
||||||
|
ensureRectVisible: { [weak self] sourceView, rect in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.ensurePaneRectVisible?(self.view, sourceView.convert(rect, to: self.view))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.pendingPanes[key] = pane
|
self.pendingPanes[key] = pane
|
||||||
|
|||||||
@ -2982,6 +2982,35 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.paneContainerNode.ensurePaneRectVisible = { [weak self] sourceView, rect in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let localRect = sourceView.convert(rect, to: self.view)
|
||||||
|
if !self.view.bounds.insetBy(dx: -1000.0, dy: 0.0).contains(localRect) {
|
||||||
|
guard let (_, navigationHeight) = self.validLayout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.headerNode.isAvatarExpanded {
|
||||||
|
let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring)
|
||||||
|
|
||||||
|
self.headerNode.updateIsAvatarExpanded(false, transition: transition)
|
||||||
|
self.updateNavigationExpansionPresentation(isExpanded: false, animated: true)
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let contentOffset = self.scrollNode.view.contentOffset
|
||||||
|
let paneAreaExpansionFinalPoint: CGFloat = self.paneContainerNode.frame.minY - navigationHeight
|
||||||
|
if contentOffset.y < paneAreaExpansionFinalPoint - CGFloat.ulpOfOne {
|
||||||
|
self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: paneAreaExpansionFinalPoint), animated: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.paneContainerNode.openMediaCalendar = { [weak self] in
|
self.paneContainerNode.openMediaCalendar = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user