mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Stories
This commit is contained in:
parent
e42e8c0ba7
commit
1ffc683a82
@ -1244,7 +1244,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
return
|
||||
}
|
||||
|
||||
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: peerId)
|
||||
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: peerId, singlePeer: false)
|
||||
let _ = (storyContent.state
|
||||
|> filter { $0.slice != nil }
|
||||
|> take(1)
|
||||
@ -2325,7 +2325,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
return
|
||||
}
|
||||
|
||||
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: peer?.id)
|
||||
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: peer?.id, singlePeer: false)
|
||||
let _ = (storyContent.state
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in
|
||||
|
@ -515,7 +515,7 @@ public class ContactsController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: true, focusedPeerId: peer?.id)
|
||||
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: true, focusedPeerId: peer?.id, singlePeer: false)
|
||||
let _ = (storyContent.state
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in
|
||||
|
@ -328,10 +328,13 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
private var preloadStoryResourceDisposables: [MediaResourceId: Disposable] = [:]
|
||||
private var pollStoryMetadataDisposables = DisposableSet()
|
||||
|
||||
private var singlePeerListContext: PeerExpiringStoryListContext?
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
includeHidden: Bool,
|
||||
focusedPeerId: EnginePeer.Id?
|
||||
focusedPeerId: EnginePeer.Id?,
|
||||
singlePeer: Bool
|
||||
) {
|
||||
self.context = context
|
||||
self.includeHidden = includeHidden
|
||||
@ -339,73 +342,163 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
self.focusedItem = (focusedPeerId, nil)
|
||||
}
|
||||
|
||||
self.storySubscriptionsDisposable = (context.engine.messages.storySubscriptions(includeHidden: includeHidden)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in
|
||||
guard let self else {
|
||||
if singlePeer {
|
||||
guard let focusedPeerId else {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
|
||||
let startedWithUnseen: Bool
|
||||
if let current = self.startedWithUnseen {
|
||||
startedWithUnseen = current
|
||||
} else {
|
||||
var startedWithUnseenValue = false
|
||||
let singlePeerListContext = PeerExpiringStoryListContext(account: context.account, peerId: focusedPeerId)
|
||||
self.singlePeerListContext = singlePeerListContext
|
||||
self.storySubscriptionsDisposable = (combineLatest(
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: focusedPeerId))
|
||||
singlePeerListContext.state
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer, state in
|
||||
guard let self, let peer else {
|
||||
return
|
||||
}
|
||||
|
||||
if let (focusedPeerId, _) = self.focusedItem, focusedPeerId == self.context.account.peerId {
|
||||
let storySubscriptions = EngineStorySubscriptions(
|
||||
accountItem: nil,
|
||||
items: [EngineStorySubscriptions.Item(
|
||||
peer: peer,
|
||||
hasUnseen: state.hasUnseen,
|
||||
storyCount: state.items.count,
|
||||
lastTimestamp: state.items.last?.timestamp ?? 0
|
||||
)],
|
||||
hasMoreToken: nil
|
||||
)
|
||||
|
||||
let startedWithUnseen: Bool
|
||||
if let current = self.startedWithUnseen {
|
||||
startedWithUnseen = current
|
||||
} else {
|
||||
var centralIndex: Int?
|
||||
if let (focusedPeerId, _) = self.focusedItem {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == focusedPeerId }) {
|
||||
centralIndex = index
|
||||
var startedWithUnseenValue = false
|
||||
|
||||
if let (focusedPeerId, _) = self.focusedItem, focusedPeerId == self.context.account.peerId {
|
||||
} else {
|
||||
var centralIndex: Int?
|
||||
if let (focusedPeerId, _) = self.focusedItem {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == focusedPeerId }) {
|
||||
centralIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
if centralIndex == nil {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.hasUnseen }) {
|
||||
centralIndex = index
|
||||
if centralIndex == nil {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.hasUnseen }) {
|
||||
centralIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
if centralIndex == nil {
|
||||
if !storySubscriptions.items.isEmpty {
|
||||
centralIndex = 0
|
||||
if centralIndex == nil {
|
||||
if !storySubscriptions.items.isEmpty {
|
||||
centralIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
if let centralIndex {
|
||||
if storySubscriptions.items[centralIndex].hasUnseen {
|
||||
startedWithUnseenValue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let centralIndex {
|
||||
if storySubscriptions.items[centralIndex].hasUnseen {
|
||||
startedWithUnseenValue = true
|
||||
}
|
||||
}
|
||||
self.startedWithUnseen = startedWithUnseenValue
|
||||
startedWithUnseen = startedWithUnseenValue
|
||||
}
|
||||
|
||||
self.startedWithUnseen = startedWithUnseenValue
|
||||
startedWithUnseen = startedWithUnseenValue
|
||||
}
|
||||
|
||||
var sortedItems: [EngineStorySubscriptions.Item] = []
|
||||
for peerId in self.fixedSubscriptionOrder {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == peerId }) {
|
||||
sortedItems.append(storySubscriptions.items[index])
|
||||
var sortedItems: [EngineStorySubscriptions.Item] = []
|
||||
for peerId in self.fixedSubscriptionOrder {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == peerId }) {
|
||||
sortedItems.append(storySubscriptions.items[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
for item in storySubscriptions.items {
|
||||
if !sortedItems.contains(where: { $0.peer.id == item.peer.id }) {
|
||||
if startedWithUnseen {
|
||||
if !item.hasUnseen {
|
||||
continue
|
||||
for item in storySubscriptions.items {
|
||||
if !sortedItems.contains(where: { $0.peer.id == item.peer.id }) {
|
||||
if startedWithUnseen {
|
||||
if !item.hasUnseen {
|
||||
continue
|
||||
}
|
||||
}
|
||||
sortedItems.append(item)
|
||||
}
|
||||
}
|
||||
self.fixedSubscriptionOrder = sortedItems.map(\.peer.id)
|
||||
|
||||
self.storySubscriptions = EngineStorySubscriptions(
|
||||
accountItem: storySubscriptions.accountItem,
|
||||
items: sortedItems,
|
||||
hasMoreToken: storySubscriptions.hasMoreToken
|
||||
)
|
||||
self.updatePeerContexts()
|
||||
})
|
||||
} else {
|
||||
self.storySubscriptionsDisposable = (context.engine.messages.storySubscriptions(includeHidden: includeHidden)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let startedWithUnseen: Bool
|
||||
if let current = self.startedWithUnseen {
|
||||
startedWithUnseen = current
|
||||
} else {
|
||||
var startedWithUnseenValue = false
|
||||
|
||||
if let (focusedPeerId, _) = self.focusedItem, focusedPeerId == self.context.account.peerId {
|
||||
} else {
|
||||
var centralIndex: Int?
|
||||
if let (focusedPeerId, _) = self.focusedItem {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == focusedPeerId }) {
|
||||
centralIndex = index
|
||||
}
|
||||
}
|
||||
if centralIndex == nil {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.hasUnseen }) {
|
||||
centralIndex = index
|
||||
}
|
||||
}
|
||||
if centralIndex == nil {
|
||||
if !storySubscriptions.items.isEmpty {
|
||||
centralIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
if let centralIndex {
|
||||
if storySubscriptions.items[centralIndex].hasUnseen {
|
||||
startedWithUnseenValue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
sortedItems.append(item)
|
||||
|
||||
self.startedWithUnseen = startedWithUnseenValue
|
||||
startedWithUnseen = startedWithUnseenValue
|
||||
}
|
||||
}
|
||||
self.fixedSubscriptionOrder = sortedItems.map(\.peer.id)
|
||||
|
||||
self.storySubscriptions = EngineStorySubscriptions(
|
||||
accountItem: storySubscriptions.accountItem,
|
||||
items: sortedItems,
|
||||
hasMoreToken: storySubscriptions.hasMoreToken
|
||||
)
|
||||
self.updatePeerContexts()
|
||||
})
|
||||
|
||||
var sortedItems: [EngineStorySubscriptions.Item] = []
|
||||
for peerId in self.fixedSubscriptionOrder {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == peerId }) {
|
||||
sortedItems.append(storySubscriptions.items[index])
|
||||
}
|
||||
}
|
||||
for item in storySubscriptions.items {
|
||||
if !sortedItems.contains(where: { $0.peer.id == item.peer.id }) {
|
||||
if startedWithUnseen {
|
||||
if !item.hasUnseen {
|
||||
continue
|
||||
}
|
||||
}
|
||||
sortedItems.append(item)
|
||||
}
|
||||
}
|
||||
self.fixedSubscriptionOrder = sortedItems.map(\.peer.id)
|
||||
|
||||
self.storySubscriptions = EngineStorySubscriptions(
|
||||
accountItem: storySubscriptions.accountItem,
|
||||
items: sortedItems,
|
||||
hasMoreToken: storySubscriptions.hasMoreToken
|
||||
)
|
||||
self.updatePeerContexts()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -415,6 +508,7 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
disposable.dispose()
|
||||
}
|
||||
self.pollStoryMetadataDisposables.dispose()
|
||||
self.storySubscriptionsDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func updatePeerContexts() {
|
||||
|
@ -88,6 +88,8 @@ import AvatarEditorScreen
|
||||
import SendInviteLinkScreen
|
||||
import PeerInfoVisualMediaPaneNode
|
||||
import PeerInfoStoryGridScreen
|
||||
import StoryContainerScreen
|
||||
import StoryContentComponent
|
||||
|
||||
enum PeerInfoAvatarEditingMode {
|
||||
case generic
|
||||
@ -2146,6 +2148,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
private var translationState: ChatTranslationState?
|
||||
private var translationStateDisposable: Disposable?
|
||||
|
||||
private var expiringStoryList: PeerExpiringStoryListContext?
|
||||
private var expiringStoryListState: PeerExpiringStoryListContext.State?
|
||||
private var expiringStoryListDisposable: Disposable?
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
@ -3038,6 +3044,58 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
return
|
||||
}
|
||||
|
||||
if !gallery, let expiringStoryList = strongSelf.expiringStoryList, let expiringStoryListState = strongSelf.expiringStoryListState, !expiringStoryListState.items.isEmpty {
|
||||
let _ = expiringStoryList
|
||||
let storyContent = StoryContentContextImpl(context: strongSelf.context, includeHidden: false, focusedPeerId: strongSelf.peerId, singlePeer: true)
|
||||
let _ = (storyContent.state
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { storyContentState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var transitionIn: StoryContainerScreen.TransitionIn?
|
||||
transitionIn = nil
|
||||
|
||||
let transitionView = self.headerNode.avatarListNode.avatarContainerNode.avatarNode.view
|
||||
transitionIn = StoryContainerScreen.TransitionIn(
|
||||
sourceView: transitionView,
|
||||
sourceRect: transitionView.bounds,
|
||||
sourceCornerRadius: transitionView.bounds.height * 0.5
|
||||
)
|
||||
|
||||
self.headerNode.avatarListNode.avatarContainerNode.avatarNode.isHidden = true
|
||||
|
||||
let storyContainerScreen = StoryContainerScreen(
|
||||
context: self.context,
|
||||
content: storyContent,
|
||||
transitionIn: transitionIn,
|
||||
transitionOut: { [weak self] peerId, _ in
|
||||
guard let self else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let transitionView = self.headerNode.avatarListNode.avatarContainerNode.avatarNode.view
|
||||
return StoryContainerScreen.TransitionOut(
|
||||
destinationView: transitionView,
|
||||
transitionView: nil,
|
||||
destinationRect: transitionView.bounds,
|
||||
destinationCornerRadius: transitionView.bounds.height * 0.5,
|
||||
destinationIsAvatar: true,
|
||||
completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.headerNode.avatarListNode.avatarContainerNode.avatarNode.isHidden = false
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
self.controller?.push(storyContainerScreen)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
guard peer.smallProfileImage != nil else {
|
||||
return
|
||||
}
|
||||
@ -3852,6 +3910,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|> deliverOnMainQueue).start(next: { [weak self] translationState in
|
||||
self?.translationState = translationState
|
||||
})
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
let expiringStoryList = PeerExpiringStoryListContext(account: context.account, peerId: peerId)
|
||||
self.expiringStoryList = expiringStoryList
|
||||
self.expiringStoryListDisposable = (expiringStoryList.state
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.expiringStoryListState = state
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -3877,8 +3945,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self.refreshMessageTagStatsDisposable?.dispose()
|
||||
self.forumTopicNotificationExceptionsDisposable?.dispose()
|
||||
self.translationStateDisposable?.dispose()
|
||||
|
||||
self.copyProtectionTooltipController?.dismiss()
|
||||
self.expiringStoryListDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user