mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-07 16:11:13 +00:00
Stories
This commit is contained in:
parent
f3c0a20a61
commit
a7ab23f97a
@ -19,6 +19,7 @@ import ComponentDisplayAdapters
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import ChatFolderLinkPreviewScreen
|
import ChatFolderLinkPreviewScreen
|
||||||
import ChatListHeaderComponent
|
import ChatListHeaderComponent
|
||||||
|
import StoryPeerListComponent
|
||||||
|
|
||||||
public enum ChatListContainerNodeFilter: Equatable {
|
public enum ChatListContainerNodeFilter: Equatable {
|
||||||
case all
|
case all
|
||||||
@ -927,7 +928,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
if itemNode.listNode.isTracking && !self.currentItemNode.startedScrollingAtUpperBound && self.tempTopInset == 0.0 {
|
if itemNode.listNode.isTracking && !self.currentItemNode.startedScrollingAtUpperBound && self.tempTopInset == 0.0 {
|
||||||
if case let .known(value) = offset {
|
if case let .known(value) = offset {
|
||||||
if value < -1.0 {
|
if value < -1.0 {
|
||||||
if let storySubscriptions = self.controller?.orderedStorySubscriptions, !storySubscriptions.items.isEmpty {
|
if let storySubscriptions = self.controller?.orderedStorySubscriptions, (shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions) || true) {
|
||||||
self.currentItemNode.startedScrollingAtUpperBound = true
|
self.currentItemNode.startedScrollingAtUpperBound = true
|
||||||
self.tempTopInset = ChatListNavigationBar.storiesScrollHeight
|
self.tempTopInset = ChatListNavigationBar.storiesScrollHeight
|
||||||
}
|
}
|
||||||
@ -958,7 +959,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
}
|
}
|
||||||
let tempTopInset: CGFloat
|
let tempTopInset: CGFloat
|
||||||
if self.currentItemNode.startedScrollingAtUpperBound {
|
if self.currentItemNode.startedScrollingAtUpperBound {
|
||||||
if let storySubscriptions = self.controller?.orderedStorySubscriptions, !storySubscriptions.items.isEmpty {
|
if let storySubscriptions = self.controller?.orderedStorySubscriptions, (shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions) || true) {
|
||||||
tempTopInset = ChatListNavigationBar.storiesScrollHeight
|
tempTopInset = ChatListNavigationBar.storiesScrollHeight
|
||||||
} else {
|
} else {
|
||||||
tempTopInset = 0.0
|
tempTopInset = 0.0
|
||||||
@ -1799,7 +1800,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if let storySubscriptions = controller.orderedStorySubscriptions, !storySubscriptions.items.isEmpty {
|
if let storySubscriptions = controller.orderedStorySubscriptions, (shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions) || true) {
|
||||||
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
if navigationBarComponentView.storiesUnlocked {
|
if navigationBarComponentView.storiesUnlocked {
|
||||||
return true
|
return true
|
||||||
@ -2060,7 +2061,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let storySubscriptions = self.controller?.orderedStorySubscriptions, !storySubscriptions.items.isEmpty {
|
if let storySubscriptions = self.controller?.orderedStorySubscriptions, (shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions) || true) {
|
||||||
self.tempAllowAvatarExpansion = true
|
self.tempAllowAvatarExpansion = true
|
||||||
self.tempDisableStoriesAnimations = !animated
|
self.tempDisableStoriesAnimations = !animated
|
||||||
self.tempNavigationScrollingTransition = animated ? .animated(duration: 0.3, curve: .spring) : .immediate
|
self.tempNavigationScrollingTransition = animated ? .animated(duration: 0.3, curve: .spring) : .immediate
|
||||||
|
@ -1162,11 +1162,17 @@ public class Account {
|
|||||||
let extractedExpr: [Signal<AccountRunningImportantTasks, NoError>] = [
|
let extractedExpr: [Signal<AccountRunningImportantTasks, NoError>] = [
|
||||||
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] },
|
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] },
|
||||||
self.pendingMessageManager.hasPendingMessages |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
self.pendingMessageManager.hasPendingMessages |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
||||||
(self.pendingStoryManager?.hasPending ?? .single(false)) |> map { hasPending in hasPending ? AccountRunningImportantTasks.pendingMessages : [] },
|
(self.pendingStoryManager?.hasPending ?? .single(false)) |> map {
|
||||||
self.pendingUpdateMessageManager.updatingMessageMedia |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
hasPending in hasPending ? AccountRunningImportantTasks.pendingMessages : []
|
||||||
self.pendingPeerMediaUploadManager.uploadingPeerMedia |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
},
|
||||||
|
self.pendingUpdateMessageManager.updatingMessageMedia |> map {
|
||||||
|
!$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : []
|
||||||
|
},
|
||||||
|
self.pendingPeerMediaUploadManager.uploadingPeerMedia |> map {
|
||||||
|
!$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : []
|
||||||
|
},
|
||||||
self.accountPresenceManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] },
|
self.accountPresenceManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] },
|
||||||
self.notificationAutolockReportManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] }
|
//self.notificationAutolockReportManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] }
|
||||||
]
|
]
|
||||||
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = extractedExpr
|
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = extractedExpr
|
||||||
let importantBackgroundOperationsRunning = combineLatest(queue: Queue(), importantBackgroundOperations)
|
let importantBackgroundOperationsRunning = combineLatest(queue: Queue(), importantBackgroundOperations)
|
||||||
|
@ -475,6 +475,7 @@ public final class EngineStorySubscriptions: Equatable {
|
|||||||
public let peer: EnginePeer
|
public let peer: EnginePeer
|
||||||
public let hasUnseen: Bool
|
public let hasUnseen: Bool
|
||||||
public let hasUnseenCloseFriends: Bool
|
public let hasUnseenCloseFriends: Bool
|
||||||
|
public let hasPending: Bool
|
||||||
public let storyCount: Int
|
public let storyCount: Int
|
||||||
public let unseenCount: Int
|
public let unseenCount: Int
|
||||||
public let lastTimestamp: Int32
|
public let lastTimestamp: Int32
|
||||||
@ -483,6 +484,7 @@ public final class EngineStorySubscriptions: Equatable {
|
|||||||
peer: EnginePeer,
|
peer: EnginePeer,
|
||||||
hasUnseen: Bool,
|
hasUnseen: Bool,
|
||||||
hasUnseenCloseFriends: Bool,
|
hasUnseenCloseFriends: Bool,
|
||||||
|
hasPending: Bool,
|
||||||
storyCount: Int,
|
storyCount: Int,
|
||||||
unseenCount: Int,
|
unseenCount: Int,
|
||||||
lastTimestamp: Int32
|
lastTimestamp: Int32
|
||||||
@ -490,6 +492,7 @@ public final class EngineStorySubscriptions: Equatable {
|
|||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.hasUnseen = hasUnseen
|
self.hasUnseen = hasUnseen
|
||||||
self.hasUnseenCloseFriends = hasUnseenCloseFriends
|
self.hasUnseenCloseFriends = hasUnseenCloseFriends
|
||||||
|
self.hasPending = hasPending
|
||||||
self.storyCount = storyCount
|
self.storyCount = storyCount
|
||||||
self.unseenCount = unseenCount
|
self.unseenCount = unseenCount
|
||||||
self.lastTimestamp = lastTimestamp
|
self.lastTimestamp = lastTimestamp
|
||||||
|
@ -645,6 +645,7 @@ public extension TelegramEngine {
|
|||||||
|
|
||||||
additionalDataKeys.append(PostboxViewKey.storyItems(peerId: self.account.peerId))
|
additionalDataKeys.append(PostboxViewKey.storyItems(peerId: self.account.peerId))
|
||||||
additionalDataKeys.append(PostboxViewKey.storiesState(key: .peer(self.account.peerId)))
|
additionalDataKeys.append(PostboxViewKey.storiesState(key: .peer(self.account.peerId)))
|
||||||
|
additionalDataKeys.append(PostboxViewKey.storiesState(key: .local))
|
||||||
|
|
||||||
var subscriptionPeerIds = storySubscriptionsView.peerIds.filter { $0 != self.account.peerId }
|
var subscriptionPeerIds = storySubscriptionsView.peerIds.filter { $0 != self.account.peerId }
|
||||||
if !debugTimer {
|
if !debugTimer {
|
||||||
@ -680,6 +681,7 @@ public extension TelegramEngine {
|
|||||||
peer: EnginePeer(accountPeer),
|
peer: EnginePeer(accountPeer),
|
||||||
hasUnseen: false,
|
hasUnseen: false,
|
||||||
hasUnseenCloseFriends: false,
|
hasUnseenCloseFriends: false,
|
||||||
|
hasPending: false,
|
||||||
storyCount: 0,
|
storyCount: 0,
|
||||||
unseenCount: 0,
|
unseenCount: 0,
|
||||||
lastTimestamp: 0
|
lastTimestamp: 0
|
||||||
@ -696,14 +698,17 @@ public extension TelegramEngine {
|
|||||||
var hasUnseen = false
|
var hasUnseen = false
|
||||||
var hasUnseenCloseFriends = false
|
var hasUnseenCloseFriends = false
|
||||||
var unseenCount = 0
|
var unseenCount = 0
|
||||||
|
var hasPending = false
|
||||||
if let peerState = peerState {
|
if let peerState = peerState {
|
||||||
hasUnseen = peerState.maxReadId < lastEntry.id
|
hasUnseen = peerState.maxReadId < lastEntry.id
|
||||||
|
|
||||||
for item in itemsView.items {
|
for item in itemsView.items {
|
||||||
if item.id > peerState.maxReadId {
|
if item.id > peerState.maxReadId {
|
||||||
unseenCount += 1
|
unseenCount += 1
|
||||||
|
}
|
||||||
|
|
||||||
if case let .item(item) = item.value.get(Stories.StoredItem.self) {
|
if case let .item(item) = item.value.get(Stories.StoredItem.self) {
|
||||||
|
if item.id > peerState.maxReadId {
|
||||||
if item.isCloseFriends {
|
if item.isCloseFriends {
|
||||||
hasUnseenCloseFriends = true
|
hasUnseenCloseFriends = true
|
||||||
}
|
}
|
||||||
@ -712,10 +717,17 @@ public extension TelegramEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let view = views.views[PostboxViewKey.storiesState(key: .local)] as? StoryStatesView, let localState = view.value?.get(Stories.LocalState.self) {
|
||||||
|
if !localState.items.isEmpty {
|
||||||
|
hasPending = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let item = EngineStorySubscriptions.Item(
|
let item = EngineStorySubscriptions.Item(
|
||||||
peer: EnginePeer(accountPeer),
|
peer: EnginePeer(accountPeer),
|
||||||
hasUnseen: hasUnseen,
|
hasUnseen: hasUnseen,
|
||||||
hasUnseenCloseFriends: hasUnseenCloseFriends,
|
hasUnseenCloseFriends: hasUnseenCloseFriends,
|
||||||
|
hasPending: hasPending,
|
||||||
storyCount: itemsView.items.count,
|
storyCount: itemsView.items.count,
|
||||||
unseenCount: unseenCount,
|
unseenCount: unseenCount,
|
||||||
lastTimestamp: lastEntry.timestamp
|
lastTimestamp: lastEntry.timestamp
|
||||||
@ -766,6 +778,7 @@ public extension TelegramEngine {
|
|||||||
peer: EnginePeer(peer),
|
peer: EnginePeer(peer),
|
||||||
hasUnseen: hasUnseen,
|
hasUnseen: hasUnseen,
|
||||||
hasUnseenCloseFriends: hasUnseenCloseFriends,
|
hasUnseenCloseFriends: hasUnseenCloseFriends,
|
||||||
|
hasPending: false,
|
||||||
storyCount: itemsView.items.count,
|
storyCount: itemsView.items.count,
|
||||||
unseenCount: unseenCount,
|
unseenCount: unseenCount,
|
||||||
lastTimestamp: lastEntry.timestamp
|
lastTimestamp: lastEntry.timestamp
|
||||||
|
@ -847,14 +847,6 @@ public final class ChatListHeaderComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let sideContentWidth: CGFloat = 0.0
|
let sideContentWidth: CGFloat = 0.0
|
||||||
/*if let storySubscriptions = component.storySubscriptions, !storySubscriptions.items.isEmpty {
|
|
||||||
sideContentWidth = self.storyPeerListExternalState.collapsedWidth + 12.0
|
|
||||||
}
|
|
||||||
if let chatListTitle = primaryContent.chatListTitle {
|
|
||||||
if chatListTitle.activity {
|
|
||||||
sideContentWidth = 0.0
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
primaryContentView.update(context: component.context, theme: component.theme, strings: component.strings, content: primaryContent, backTitle: primaryContent.backTitle, sideInset: component.sideInset, sideContentWidth: sideContentWidth, sideContentFraction: (1.0 - component.storiesFraction), size: availableSize, transition: primaryContentTransition)
|
primaryContentView.update(context: component.context, theme: component.theme, strings: component.strings, content: primaryContent, backTitle: primaryContent.backTitle, sideInset: component.sideInset, sideContentWidth: sideContentWidth, sideContentFraction: (1.0 - component.storiesFraction), size: availableSize, transition: primaryContentTransition)
|
||||||
primaryContentTransition.setFrame(view: primaryContentView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
primaryContentTransition.setFrame(view: primaryContentView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||||
|
@ -610,44 +610,6 @@ public final class ChatListNavigationBar: Component {
|
|||||||
|
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private func addStoriesUnlockedAnimation(duration: Double, animateScrollUnlocked: Bool) {
|
|
||||||
guard let component = self.component else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.applyScrollFractionAnimator?.invalidate()
|
|
||||||
self.applyScrollFractionAnimator = nil
|
|
||||||
|
|
||||||
let storiesUnlocked = component.storiesUnlocked
|
|
||||||
|
|
||||||
self.storiesOffsetStartFraction = self.storiesOffsetFraction
|
|
||||||
self.storiesUnlockedStartFraction = self.storiesUnlockedFraction
|
|
||||||
|
|
||||||
self.applyScrollFraction = 0.0
|
|
||||||
self.applyScrollUnlockedFraction = 0.0
|
|
||||||
self.applyScrollFractionAnimator = DisplayLinkAnimator(duration: duration * UIView.animationDurationFactor(), from: 0.0, to: 1.0, update: { [weak self] value in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let t = listViewAnimationCurveSystem(value)
|
|
||||||
self.applyScrollFraction = t
|
|
||||||
if animateScrollUnlocked {
|
|
||||||
self.applyScrollUnlockedFraction = storiesUnlocked ? t : (1.0 - t)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let rawScrollOffset = self.rawScrollOffset {
|
|
||||||
self.hasDeferredScrollOffset = true
|
|
||||||
self.applyScroll(offset: rawScrollOffset, allowAvatarsExpansion: self.currentAllowAvatarsExpansion, transition: .immediate)
|
|
||||||
}
|
|
||||||
}, completion: { [weak self] in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.applyScrollFractionAnimator?.invalidate()
|
|
||||||
self.applyScrollFractionAnimator = nil
|
|
||||||
})
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeView() -> View {
|
public func makeView() -> View {
|
||||||
|
@ -5,6 +5,7 @@ import ComponentFlow
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import Postbox
|
import Postbox
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
public final class StoryContentItem {
|
public final class StoryContentItem {
|
||||||
public final class ExternalState {
|
public final class ExternalState {
|
||||||
@ -33,17 +34,20 @@ public final class StoryContentItem {
|
|||||||
public final class Environment: Equatable {
|
public final class Environment: Equatable {
|
||||||
public let externalState: ExternalState
|
public let externalState: ExternalState
|
||||||
public let sharedState: SharedState
|
public let sharedState: SharedState
|
||||||
|
public let theme: PresentationTheme
|
||||||
public let presentationProgressUpdated: (Double, Bool) -> Void
|
public let presentationProgressUpdated: (Double, Bool) -> Void
|
||||||
public let markAsSeen: (StoryId) -> Void
|
public let markAsSeen: (StoryId) -> Void
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
externalState: ExternalState,
|
externalState: ExternalState,
|
||||||
sharedState: SharedState,
|
sharedState: SharedState,
|
||||||
|
theme: PresentationTheme,
|
||||||
presentationProgressUpdated: @escaping (Double, Bool) -> Void,
|
presentationProgressUpdated: @escaping (Double, Bool) -> Void,
|
||||||
markAsSeen: @escaping (StoryId) -> Void
|
markAsSeen: @escaping (StoryId) -> Void
|
||||||
) {
|
) {
|
||||||
self.externalState = externalState
|
self.externalState = externalState
|
||||||
self.sharedState = sharedState
|
self.sharedState = sharedState
|
||||||
|
self.theme = theme
|
||||||
self.presentationProgressUpdated = presentationProgressUpdated
|
self.presentationProgressUpdated = presentationProgressUpdated
|
||||||
self.markAsSeen = markAsSeen
|
self.markAsSeen = markAsSeen
|
||||||
}
|
}
|
||||||
@ -55,6 +59,9 @@ public final class StoryContentItem {
|
|||||||
if lhs.sharedState !== rhs.sharedState {
|
if lhs.sharedState !== rhs.sharedState {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -621,6 +621,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
let itemEnvironment = StoryContentItem.Environment(
|
let itemEnvironment = StoryContentItem.Environment(
|
||||||
externalState: visibleItem.externalState,
|
externalState: visibleItem.externalState,
|
||||||
sharedState: component.storyItemSharedState,
|
sharedState: component.storyItemSharedState,
|
||||||
|
theme: component.theme,
|
||||||
presentationProgressUpdated: { [weak self, weak visibleItem] progress, canSwitch in
|
presentationProgressUpdated: { [weak self, weak visibleItem] progress, canSwitch in
|
||||||
guard let self = self, let component = self.component else {
|
guard let self = self, let component = self.component else {
|
||||||
return
|
return
|
||||||
@ -656,7 +657,6 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
)
|
)
|
||||||
if let view = visibleItem.view.view {
|
if let view = visibleItem.view.view {
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
view.isUserInteractionEnabled = false
|
|
||||||
self.contentContainerView.insertSubview(view, at: 0)
|
self.contentContainerView.insertSubview(view, at: 0)
|
||||||
}
|
}
|
||||||
itemTransition.setFrame(view: view, frame: CGRect(origin: CGPoint(), size: itemLayout.size))
|
itemTransition.setFrame(view: view, frame: CGRect(origin: CGPoint(), size: itemLayout.size))
|
||||||
@ -1140,6 +1140,15 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isUnsupported = false
|
||||||
|
var disabledPlaceholder: String?
|
||||||
|
if component.slice.peer.isService {
|
||||||
|
disabledPlaceholder = "You can't reply to this story"
|
||||||
|
} else if case .unsupported = component.slice.item.storyItem.media {
|
||||||
|
isUnsupported = true
|
||||||
|
disabledPlaceholder = "You can't reply to this story"
|
||||||
|
}
|
||||||
|
|
||||||
let keyboardWasHidden = self.inputPanelExternalState.isKeyboardHidden
|
let keyboardWasHidden = self.inputPanelExternalState.isKeyboardHidden
|
||||||
let inputNodeVisible = self.sendMessageContext.currentInputMode == .media || hasFirstResponder(self)
|
let inputNodeVisible = self.sendMessageContext.currentInputMode == .media || hasFirstResponder(self)
|
||||||
self.inputPanel.parentState = state
|
self.inputPanel.parentState = state
|
||||||
@ -1374,7 +1383,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
displayGradient: false, //(component.inputHeight != 0.0 || inputNodeVisible) && component.metrics.widthClass != .regular,
|
displayGradient: false, //(component.inputHeight != 0.0 || inputNodeVisible) && component.metrics.widthClass != .regular,
|
||||||
bottomInset: component.inputHeight != 0.0 || inputNodeVisible ? 0.0 : bottomContentInset,
|
bottomInset: component.inputHeight != 0.0 || inputNodeVisible ? 0.0 : bottomContentInset,
|
||||||
hideKeyboard: self.sendMessageContext.currentInputMode == .media,
|
hideKeyboard: self.sendMessageContext.currentInputMode == .media,
|
||||||
disabledPlaceholder: component.slice.peer.isService ? "You can't reply to this story" : nil
|
disabledPlaceholder: disabledPlaceholder
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: inputPanelAvailableWidth, height: 200.0)
|
containerSize: CGSize(width: inputPanelAvailableWidth, height: 200.0)
|
||||||
@ -1976,7 +1985,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !component.slice.item.storyItem.text.isEmpty {
|
if !isUnsupported, !component.slice.item.storyItem.text.isEmpty {
|
||||||
var captionItemTransition = transition
|
var captionItemTransition = transition
|
||||||
let captionItem: CaptionItem
|
let captionItem: CaptionItem
|
||||||
if let current = self.captionItem {
|
if let current = self.captionItem {
|
||||||
|
@ -23,6 +23,9 @@ swift_library(
|
|||||||
"//submodules/TelegramUniversalVideoContent",
|
"//submodules/TelegramUniversalVideoContent",
|
||||||
"//submodules/AvatarNode",
|
"//submodules/AvatarNode",
|
||||||
"//submodules/Components/HierarchyTrackingLayer",
|
"//submodules/Components/HierarchyTrackingLayer",
|
||||||
|
"//submodules/TelegramUI/Components/ButtonComponent",
|
||||||
|
"//submodules/Components/MultilineTextComponent",
|
||||||
|
"//submodules/TelegramPresentationData",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -437,6 +437,7 @@ public final class StoryContentContextImpl: StoryContentContext {
|
|||||||
peer: peer,
|
peer: peer,
|
||||||
hasUnseen: state.hasUnseen,
|
hasUnseen: state.hasUnseen,
|
||||||
hasUnseenCloseFriends: state.hasUnseenCloseFriends,
|
hasUnseenCloseFriends: state.hasUnseenCloseFriends,
|
||||||
|
hasPending: false,
|
||||||
storyCount: state.items.count,
|
storyCount: state.items.count,
|
||||||
unseenCount: 0,
|
unseenCount: 0,
|
||||||
lastTimestamp: state.items.last?.timestamp ?? 0
|
lastTimestamp: state.items.last?.timestamp ?? 0
|
||||||
|
@ -12,6 +12,9 @@ import UniversalMediaPlayer
|
|||||||
import TelegramUniversalVideoContent
|
import TelegramUniversalVideoContent
|
||||||
import StoryContainerScreen
|
import StoryContainerScreen
|
||||||
import HierarchyTrackingLayer
|
import HierarchyTrackingLayer
|
||||||
|
import ButtonComponent
|
||||||
|
import MultilineTextComponent
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
final class StoryItemContentComponent: Component {
|
final class StoryItemContentComponent: Component {
|
||||||
typealias EnvironmentType = StoryContentItem.Environment
|
typealias EnvironmentType = StoryContentItem.Environment
|
||||||
@ -39,56 +42,6 @@ final class StoryItemContentComponent: Component {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static func preload(context: AccountContext, message: EngineMessage) -> Signal<Never, NoError> {
|
|
||||||
var messageMedia: EngineMedia?
|
|
||||||
for media in message.media {
|
|
||||||
switch media {
|
|
||||||
case let image as TelegramMediaImage:
|
|
||||||
messageMedia = .image(image)
|
|
||||||
case let file as TelegramMediaFile:
|
|
||||||
messageMedia = .file(file)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let messageMedia else {
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
|
|
||||||
var fetchSignal: Signal<Never, NoError>?
|
|
||||||
switch messageMedia {
|
|
||||||
case let .image(image):
|
|
||||||
if let representation = image.representations.last {
|
|
||||||
fetchSignal = fetchedMediaResource(
|
|
||||||
mediaBox: context.account.postbox.mediaBox,
|
|
||||||
userLocation: .peer(message.id.peerId),
|
|
||||||
userContentType: .image,
|
|
||||||
reference: ImageMediaReference.message(message: MessageReference(message._asMessage()), media: image).resourceReference(representation.resource)
|
|
||||||
)
|
|
||||||
|> ignoreValues
|
|
||||||
|> `catch` { _ -> Signal<Never, NoError> in
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case let .file(file):
|
|
||||||
fetchSignal = fetchedMediaResource(
|
|
||||||
mediaBox: context.account.postbox.mediaBox,
|
|
||||||
userLocation: .peer(message.id.peerId),
|
|
||||||
userContentType: .image,
|
|
||||||
reference: FileMediaReference.message(message: MessageReference(message._asMessage()), media: file).resourceReference(file.resource)
|
|
||||||
)
|
|
||||||
|> ignoreValues
|
|
||||||
|> `catch` { _ -> Signal<Never, NoError> in
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetchSignal ?? .complete()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
final class View: StoryContentItem.View {
|
final class View: StoryContentItem.View {
|
||||||
private let imageNode: TransformImageNode
|
private let imageNode: TransformImageNode
|
||||||
private var videoNode: UniversalVideoNode?
|
private var videoNode: UniversalVideoNode?
|
||||||
@ -100,6 +53,9 @@ final class StoryItemContentComponent: Component {
|
|||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
private var environment: StoryContentItem.Environment?
|
private var environment: StoryContentItem.Environment?
|
||||||
|
|
||||||
|
private var unsupportedText: ComponentView<Empty>?
|
||||||
|
private var unsupportedButton: ComponentView<Empty>?
|
||||||
|
|
||||||
private var isProgressPaused: Bool = false
|
private var isProgressPaused: Bool = false
|
||||||
private var currentProgressTimer: SwiftSignalKit.Timer?
|
private var currentProgressTimer: SwiftSignalKit.Timer?
|
||||||
private var currentProgressTimerValue: Double = 0.0
|
private var currentProgressTimerValue: Double = 0.0
|
||||||
@ -353,10 +309,20 @@ final class StoryItemContentComponent: Component {
|
|||||||
self.environment?.presentationProgressUpdated(clippedProgress, false)
|
self.environment?.presentationProgressUpdated(clippedProgress, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
if let unsupportedButtonView = self.unsupportedButton?.view {
|
||||||
|
if let result = unsupportedButtonView.hitTest(self.convert(point, to: unsupportedButtonView), with: event) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
self.state = state
|
||||||
self.environment = environment[StoryContentItem.Environment.self].value
|
let environment = environment[StoryContentItem.Environment.self].value
|
||||||
|
self.environment = environment
|
||||||
|
|
||||||
let peerReference = PeerReference(component.peer._asPeer())
|
let peerReference = PeerReference(component.peer._asPeer())
|
||||||
|
|
||||||
@ -366,6 +332,8 @@ final class StoryItemContentComponent: Component {
|
|||||||
messageMedia = .image(image)
|
messageMedia = .image(image)
|
||||||
case let .file(file):
|
case let .file(file):
|
||||||
messageMedia = .file(file)
|
messageMedia = .file(file)
|
||||||
|
case .unsupported:
|
||||||
|
self.contentLoaded = true
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -504,6 +472,99 @@ final class StoryItemContentComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch component.item.media {
|
||||||
|
case .image, .file:
|
||||||
|
if let unsupportedText = self.unsupportedText {
|
||||||
|
self.unsupportedText = nil
|
||||||
|
unsupportedText.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
if let unsupportedButton = self.unsupportedButton {
|
||||||
|
self.unsupportedButton = nil
|
||||||
|
unsupportedButton.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.backgroundColor = .black
|
||||||
|
default:
|
||||||
|
var unsuportedTransition = transition
|
||||||
|
|
||||||
|
let unsupportedText: ComponentView<Empty>
|
||||||
|
if let current = self.unsupportedText {
|
||||||
|
unsupportedText = current
|
||||||
|
} else {
|
||||||
|
unsuportedTransition = .immediate
|
||||||
|
unsupportedText = ComponentView()
|
||||||
|
self.unsupportedText = unsupportedText
|
||||||
|
}
|
||||||
|
|
||||||
|
let unsupportedButton: ComponentView<Empty>
|
||||||
|
if let current = self.unsupportedButton {
|
||||||
|
unsupportedButton = current
|
||||||
|
} else {
|
||||||
|
unsuportedTransition = .immediate
|
||||||
|
unsupportedButton = ComponentView()
|
||||||
|
self.unsupportedButton = unsupportedButton
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
let unsupportedTextSize = unsupportedText.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(string: "This story is not supported by\nyour version of Telegram.", font: Font.regular(17.0), textColor: .white)),
|
||||||
|
horizontalAlignment: .center,
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: availableSize.width - 16.0 * 2.0, height: availableSize.height)
|
||||||
|
)
|
||||||
|
let unsupportedButtonSize = unsupportedButton.update(
|
||||||
|
transition: unsuportedTransition,
|
||||||
|
component: AnyComponent(ButtonComponent(
|
||||||
|
background: ButtonComponent.Background(
|
||||||
|
color: environment.theme.list.itemCheckColors.fillColor,
|
||||||
|
foreground: environment.theme.list.itemCheckColors.foregroundColor,
|
||||||
|
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.7)
|
||||||
|
),
|
||||||
|
content: AnyComponentWithIdentity(id: AnyHashable(""), component: AnyComponent(Text(text: "Update Telegram", font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor
|
||||||
|
))),
|
||||||
|
isEnabled: true,
|
||||||
|
displaysProgress: false,
|
||||||
|
action: { [weak self] in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.context.sharedContext.applicationBindings.openAppStorePage()
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 240.0, height: 50.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
let spacing: CGFloat = 24.0
|
||||||
|
let contentHeight = unsupportedTextSize.height + unsupportedButtonSize.height + spacing
|
||||||
|
var contentY = floor((availableSize.height - contentHeight) * 0.5)
|
||||||
|
|
||||||
|
let unsupportedTextFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - unsupportedTextSize.width) * 0.5), y: contentY), size: unsupportedTextSize)
|
||||||
|
contentY += unsupportedTextSize.height + spacing
|
||||||
|
|
||||||
|
let unsupportedButtonFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - unsupportedButtonSize.width) * 0.5), y: contentY), size: unsupportedButtonSize)
|
||||||
|
|
||||||
|
if let unsupportedTextView = unsupportedText.view {
|
||||||
|
if unsupportedTextView.superview == nil {
|
||||||
|
self.addSubview(unsupportedTextView)
|
||||||
|
}
|
||||||
|
unsuportedTransition.setPosition(view: unsupportedTextView, position: unsupportedTextFrame.center)
|
||||||
|
unsupportedTextView.bounds = CGRect(origin: CGPoint(), size: unsupportedTextFrame.size)
|
||||||
|
}
|
||||||
|
if let unsupportedButtonView = unsupportedButton.view {
|
||||||
|
if unsupportedButtonView.superview == nil {
|
||||||
|
self.addSubview(unsupportedButtonView)
|
||||||
|
}
|
||||||
|
unsuportedTransition.setFrame(view: unsupportedButtonView, frame: unsupportedButtonFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.backgroundColor = UIColor(rgb: 0x181818)
|
||||||
|
}
|
||||||
|
|
||||||
self.updateIsProgressPaused()
|
self.updateIsProgressPaused()
|
||||||
|
|
||||||
return availableSize
|
return availableSize
|
||||||
|
@ -11,6 +11,16 @@ import SwiftSignalKit
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import StoryContainerScreen
|
import StoryContainerScreen
|
||||||
|
|
||||||
|
public func shouldDisplayStoriesInChatListHeader(storySubscriptions: EngineStorySubscriptions) -> Bool {
|
||||||
|
if !storySubscriptions.items.isEmpty {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if let accountItem = storySubscriptions.accountItem, (accountItem.hasUnseen || accountItem.hasPending) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private func solveParabolicMotion(from sourcePoint: CGPoint, to targetPosition: CGPoint, progress: CGFloat) -> CGPoint {
|
private func solveParabolicMotion(from sourcePoint: CGPoint, to targetPosition: CGPoint, progress: CGFloat) -> CGPoint {
|
||||||
if sourcePoint.y == targetPosition.y {
|
if sourcePoint.y == targetPosition.y {
|
||||||
return sourcePoint.interpolate(to: targetPosition, amount: progress)
|
return sourcePoint.interpolate(to: targetPosition, amount: progress)
|
||||||
@ -373,12 +383,23 @@ public final class StoryPeerListComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hasStories: Bool = false
|
var hasStories: Bool = false
|
||||||
if let storySubscriptions = component.storySubscriptions, !storySubscriptions.items.isEmpty {
|
if let storySubscriptions = component.storySubscriptions, shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions) {
|
||||||
hasStories = true
|
hasStories = true
|
||||||
}
|
}
|
||||||
let _ = hasStories
|
let _ = hasStories
|
||||||
|
|
||||||
let collapseStartIndex = component.useHiddenList ? 0 : 1
|
let collapseStartIndex: Int
|
||||||
|
if component.useHiddenList {
|
||||||
|
collapseStartIndex = 0
|
||||||
|
} else if let storySubscriptions = component.storySubscriptions {
|
||||||
|
if let accountItem = storySubscriptions.accountItem, (accountItem.hasUnseen || accountItem.hasPending) {
|
||||||
|
collapseStartIndex = 0
|
||||||
|
} else {
|
||||||
|
collapseStartIndex = 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
collapseStartIndex = 1
|
||||||
|
}
|
||||||
|
|
||||||
let collapsedItemWidth: CGFloat = 24.0
|
let collapsedItemWidth: CGFloat = 24.0
|
||||||
let collapsedItemDistance: CGFloat = 14.0
|
let collapsedItemDistance: CGFloat = 14.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user