This commit is contained in:
Ali 2023-06-20 13:00:27 +03:00
parent 34e8c54bb0
commit e9e5b4c749
14 changed files with 65 additions and 45 deletions

View File

@ -1253,7 +1253,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return return
} }
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: peerId, singlePeer: false) let storyContent = StoryContentContextImpl(context: self.context, isHidden: false, focusedPeerId: peerId, singlePeer: false)
let _ = (storyContent.state let _ = (storyContent.state
|> filter { $0.slice != nil } |> filter { $0.slice != nil }
|> take(1) |> take(1)
@ -1744,7 +1744,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|> distinctUntilChanged |> distinctUntilChanged
self.preloadStorySubscriptionsDisposable = (combineLatest(queue: .mainQueue(), self.preloadStorySubscriptionsDisposable = (combineLatest(queue: .mainQueue(),
self.context.engine.messages.preloadStorySubscriptions(includeHidden: false), self.context.engine.messages.preloadStorySubscriptions(isHidden: false),
self.context.sharedContext.automaticMediaDownloadSettings, self.context.sharedContext.automaticMediaDownloadSettings,
automaticDownloadNetworkType automaticDownloadNetworkType
) )
@ -1790,7 +1790,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self.preloadStoryResourceDisposables.removeValue(forKey: id) self.preloadStoryResourceDisposables.removeValue(forKey: id)
} }
}) })
self.storySubscriptionsDisposable = (self.context.engine.messages.storySubscriptions(includeHidden: false) self.storySubscriptionsDisposable = (self.context.engine.messages.storySubscriptions(isHidden: false)
|> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in |> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in
guard let self else { guard let self else {
return return
@ -2391,7 +2391,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return return
} }
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: peer?.id, singlePeer: false) let storyContent = StoryContentContextImpl(context: self.context, isHidden: false, focusedPeerId: peer?.id, singlePeer: false)
let _ = (storyContent.state let _ = (storyContent.state
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in |> deliverOnMainQueue).start(next: { [weak self] storyContentState in

View File

@ -515,7 +515,7 @@ public class ContactsController: ViewController {
return return
} }
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: true, focusedPeerId: peer?.id, singlePeer: false) let storyContent = StoryContentContextImpl(context: self.context, isHidden: true, focusedPeerId: peer?.id, singlePeer: false)
let _ = (storyContent.state let _ = (storyContent.state
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in |> deliverOnMainQueue).start(next: { [weak self] storyContentState in

View File

@ -227,7 +227,7 @@ final class ContactsControllerNode: ASDisplayNode {
return self.contentScrollingEnded(listView: listView) return self.contentScrollingEnded(listView: listView)
} }
self.storySubscriptionsDisposable = (self.context.engine.messages.storySubscriptions(includeHidden: true) self.storySubscriptionsDisposable = (self.context.engine.messages.storySubscriptions(isHidden: true)
|> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in |> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in
guard let self else { guard let self else {
return return

View File

@ -1,7 +1,7 @@
import Foundation import Foundation
public enum PostboxStorySubscriptionsKey: Int32 { public enum PostboxStorySubscriptionsKey: Int32 {
case all = 0 case hidden = 0
case filtered = 1 case filtered = 1
} }

View File

@ -975,7 +975,7 @@ public class Account {
let networkStatsContext: NetworkStatsContext let networkStatsContext: NetworkStatsContext
public let filteredStorySubscriptionsContext: StorySubscriptionsContext? public let filteredStorySubscriptionsContext: StorySubscriptionsContext?
public let allStorySubscriptionsContext: StorySubscriptionsContext? public let hiddenStorySubscriptionsContext: StorySubscriptionsContext?
public init(accountManager: AccountManager<TelegramAccountManagerTypes>, id: AccountRecordId, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, networkArguments: NetworkInitializationArguments, peerId: PeerId, auxiliaryMethods: AccountAuxiliaryMethods, supplementary: Bool) { public init(accountManager: AccountManager<TelegramAccountManagerTypes>, id: AccountRecordId, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, networkArguments: NetworkInitializationArguments, peerId: PeerId, auxiliaryMethods: AccountAuxiliaryMethods, supplementary: Bool) {
self.accountManager = accountManager self.accountManager = accountManager
@ -995,11 +995,11 @@ public class Account {
self.peerInputActivityManager = PeerInputActivityManager() self.peerInputActivityManager = PeerInputActivityManager()
if !supplementary { if !supplementary {
self.filteredStorySubscriptionsContext = StorySubscriptionsContext(accountPeerId: peerId, postbox: postbox, network: network, includesHidden: false) self.filteredStorySubscriptionsContext = StorySubscriptionsContext(accountPeerId: peerId, postbox: postbox, network: network, isHidden: false)
self.allStorySubscriptionsContext = StorySubscriptionsContext(accountPeerId: peerId, postbox: postbox, network: network, includesHidden: true) self.hiddenStorySubscriptionsContext = StorySubscriptionsContext(accountPeerId: peerId, postbox: postbox, network: network, isHidden: true)
} else { } else {
self.filteredStorySubscriptionsContext = nil self.filteredStorySubscriptionsContext = nil
self.allStorySubscriptionsContext = nil self.hiddenStorySubscriptionsContext = nil
} }
self.callSessionManager = CallSessionManager(postbox: postbox, network: network, maxLayer: networkArguments.voipMaxLayer, versions: networkArguments.voipVersions, addUpdates: { [weak self] updates in self.callSessionManager = CallSessionManager(postbox: postbox, network: network, maxLayer: networkArguments.voipMaxLayer, versions: networkArguments.voipVersions, addUpdates: { [weak self] updates in

View File

@ -144,7 +144,7 @@ public final class StorySubscriptionsContext {
private let queue: Queue private let queue: Queue
private let postbox: Postbox private let postbox: Postbox
private let network: Network private let network: Network
private let includesHidden: Bool private let isHidden: Bool
private var taskState = TaskState() private var taskState = TaskState()
@ -155,12 +155,12 @@ public final class StorySubscriptionsContext {
private let loadMoreDisposable = MetaDisposable() private let loadMoreDisposable = MetaDisposable()
private let refreshTimerDisposable = MetaDisposable() private let refreshTimerDisposable = MetaDisposable()
init(queue: Queue, accountPeerId: PeerId, postbox: Postbox, network: Network, includesHidden: Bool) { init(queue: Queue, accountPeerId: PeerId, postbox: Postbox, network: Network, isHidden: Bool) {
self.accountPeerId = accountPeerId self.accountPeerId = accountPeerId
self.queue = queue self.queue = queue
self.postbox = postbox self.postbox = postbox
self.network = network self.network = network
self.includesHidden = includesHidden self.isHidden = isHidden
self.taskState.isRefreshScheduled = true self.taskState.isRefreshScheduled = true
@ -183,7 +183,7 @@ public final class StorySubscriptionsContext {
return return
} }
let subscriptionsKey: PostboxStorySubscriptionsKey = self.includesHidden ? .all : .filtered let subscriptionsKey: PostboxStorySubscriptionsKey = self.isHidden ? .hidden : .filtered
if self.taskState.isRefreshScheduled { if self.taskState.isRefreshScheduled {
self.isLoading = true self.isLoading = true
@ -244,7 +244,7 @@ public final class StorySubscriptionsContext {
private func loadImpl(isRefresh: Bool, stateMark: OpaqueStateMark) { private func loadImpl(isRefresh: Bool, stateMark: OpaqueStateMark) {
var flags: Int32 = 0 var flags: Int32 = 0
if self.includesHidden { if self.isHidden {
flags |= 1 << 2 flags |= 1 << 2
} }
@ -270,8 +270,8 @@ public final class StorySubscriptionsContext {
let accountPeerId = self.accountPeerId let accountPeerId = self.accountPeerId
let includesHidden = self.includesHidden let isHidden = self.isHidden
let subscriptionsKey: PostboxStorySubscriptionsKey = self.includesHidden ? .all : .filtered let subscriptionsKey: PostboxStorySubscriptionsKey = self.isHidden ? .hidden : .filtered
self.loadMoreDisposable.set((self.network.request(Api.functions.stories.getAllStories(flags: flags, state: state)) self.loadMoreDisposable.set((self.network.request(Api.functions.stories.getAllStories(flags: flags, state: state))
|> deliverOn(self.queue)).start(next: { [weak self] result in |> deliverOn(self.queue)).start(next: { [weak self] result in
@ -343,7 +343,7 @@ public final class StorySubscriptionsContext {
} }
if isRefresh { if isRefresh {
if !includesHidden { if !isHidden {
if !peerEntries.contains(where: { $0 == accountPeerId }) { if !peerEntries.contains(where: { $0 == accountPeerId }) {
transaction.setStoryItems(peerId: accountPeerId, items: []) transaction.setStoryItems(peerId: accountPeerId, items: [])
} }
@ -396,10 +396,10 @@ public final class StorySubscriptionsContext {
private let queue = Queue(name: "StorySubscriptionsContext") private let queue = Queue(name: "StorySubscriptionsContext")
private let impl: QueueLocalObject<Impl> private let impl: QueueLocalObject<Impl>
init(accountPeerId: PeerId, postbox: Postbox, network: Network, includesHidden: Bool) { init(accountPeerId: PeerId, postbox: Postbox, network: Network, isHidden: Bool) {
let queue = self.queue let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: { self.impl = QueueLocalObject(queue: queue, generate: {
Impl(queue: queue, accountPeerId: accountPeerId, postbox: postbox, network: network, includesHidden: includesHidden) Impl(queue: queue, accountPeerId: accountPeerId, postbox: postbox, network: network, isHidden: isHidden)
}) })
} }

View File

@ -592,7 +592,7 @@ public extension TelegramEngine {
}).start() }).start()
} }
public func storySubscriptions(includeHidden: Bool) -> Signal<EngineStorySubscriptions, NoError> { public func storySubscriptions(isHidden: Bool) -> Signal<EngineStorySubscriptions, NoError> {
let debugTimerSignal: Signal<Bool, NoError> let debugTimerSignal: Signal<Bool, NoError>
#if DEBUG && false #if DEBUG && false
debugTimerSignal = Signal<Bool, NoError>.single(true) debugTimerSignal = Signal<Bool, NoError>.single(true)
@ -609,7 +609,7 @@ public extension TelegramEngine {
debugTimerSignal = .single(true) debugTimerSignal = .single(true)
#endif #endif
let subscriptionsKey: PostboxStorySubscriptionsKey = includeHidden ? .all : .filtered let subscriptionsKey: PostboxStorySubscriptionsKey = isHidden ? .hidden : .filtered
let basicPeerKey = PostboxViewKey.basicPeer(self.account.peerId) let basicPeerKey = PostboxViewKey.basicPeer(self.account.peerId)
let storySubscriptionsKey = PostboxViewKey.storySubscriptions(key: subscriptionsKey) let storySubscriptionsKey = PostboxViewKey.storySubscriptions(key: subscriptionsKey)
@ -759,9 +759,9 @@ public extension TelegramEngine {
} }
} }
public func preloadStorySubscriptions(includeHidden: Bool) -> Signal<[EngineMediaResource.Id: StoryPreloadInfo], NoError> { public func preloadStorySubscriptions(isHidden: Bool) -> Signal<[EngineMediaResource.Id: StoryPreloadInfo], NoError> {
let basicPeerKey = PostboxViewKey.basicPeer(self.account.peerId) let basicPeerKey = PostboxViewKey.basicPeer(self.account.peerId)
let subscriptionsKey: PostboxStorySubscriptionsKey = includeHidden ? .all : .filtered let subscriptionsKey: PostboxStorySubscriptionsKey = isHidden ? .hidden : .filtered
let storySubscriptionsKey = PostboxViewKey.storySubscriptions(key: subscriptionsKey) let storySubscriptionsKey = PostboxViewKey.storySubscriptions(key: subscriptionsKey)
return self.account.postbox.combinedView(keys: [ return self.account.postbox.combinedView(keys: [
basicPeerKey, basicPeerKey,

View File

@ -60,15 +60,28 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
peerIds.removeAll(where: { $0 == updated.id }) peerIds.removeAll(where: { $0 == updated.id })
transaction.replaceAllStorySubscriptions(key: .filtered, state: state, peerIds: peerIds) transaction.replaceAllStorySubscriptions(key: .filtered, state: state, peerIds: peerIds)
} }
if transaction.storySubscriptionsContains(key: .hidden, peerId: updated.id) {
var (state, peerIds) = transaction.getAllStorySubscriptions(key: .filtered)
if !peerIds.contains(updated.id) {
peerIds.append(updated.id)
transaction.replaceAllStorySubscriptions(key: .hidden, state: state, peerIds: peerIds)
}
}
} else { } else {
if transaction.storySubscriptionsContains(key: .all, peerId: updated.id) && !transaction.storySubscriptionsContains(key: .filtered, peerId: updated.id) { if transaction.storySubscriptionsContains(key: .hidden, peerId: updated.id) {
var (state, peerIds) = transaction.getAllStorySubscriptions(key: .all) var (state, peerIds) = transaction.getAllStorySubscriptions(key: .filtered)
peerIds.removeAll(where: { $0 == updated.id }) peerIds.removeAll(where: { $0 == updated.id })
transaction.replaceAllStorySubscriptions(key: .hidden, state: state, peerIds: peerIds)
}
if transaction.storySubscriptionsContains(key: .filtered, peerId: updated.id) {
var (state, peerIds) = transaction.getAllStorySubscriptions(key: .filtered)
if !peerIds.contains(updated.id) {
peerIds.append(updated.id) peerIds.append(updated.id)
transaction.replaceAllStorySubscriptions(key: .filtered, state: state, peerIds: peerIds) transaction.replaceAllStorySubscriptions(key: .filtered, state: state, peerIds: peerIds)
} }
} }
} }
}
case Namespaces.Peer.CloudGroup: case Namespaces.Peer.CloudGroup:
if let group = updated as? TelegramGroup { if let group = updated as? TelegramGroup {
if group.flags.contains(.deactivated) { if group.flags.contains(.deactivated) {

View File

@ -829,7 +829,7 @@ public final class ChatListHeaderComponent: Component {
theme: component.theme, theme: component.theme,
strings: component.strings, strings: component.strings,
sideInset: component.sideInset, sideInset: component.sideInset,
includesHidden: component.storiesIncludeHidden, useHiddenList: component.storiesIncludeHidden,
storySubscriptions: storySubscriptions, storySubscriptions: storySubscriptions,
collapseFraction: 1.0 - component.storiesFraction, collapseFraction: 1.0 - component.storiesFraction,
unlockedFraction: 1.0 - component.storiesUnlockedFraction, unlockedFraction: 1.0 - component.storiesUnlockedFraction,

View File

@ -358,7 +358,7 @@ public final class StoryContentContextImpl: StoryContentContext {
} }
private let context: AccountContext private let context: AccountContext
private let includeHidden: Bool private let isHidden: Bool
public private(set) var stateValue: StoryContentContextState? public private(set) var stateValue: StoryContentContextState?
public var state: Signal<StoryContentContextState, NoError> { public var state: Signal<StoryContentContextState, NoError> {
@ -394,12 +394,12 @@ public final class StoryContentContextImpl: StoryContentContext {
public init( public init(
context: AccountContext, context: AccountContext,
includeHidden: Bool, isHidden: Bool,
focusedPeerId: EnginePeer.Id?, focusedPeerId: EnginePeer.Id?,
singlePeer: Bool singlePeer: Bool
) { ) {
self.context = context self.context = context
self.includeHidden = includeHidden self.isHidden = isHidden
if let focusedPeerId { if let focusedPeerId {
self.focusedItem = (focusedPeerId, nil) self.focusedItem = (focusedPeerId, nil)
} }
@ -493,7 +493,7 @@ public final class StoryContentContextImpl: StoryContentContext {
self.updatePeerContexts() self.updatePeerContexts()
}) })
} else { } else {
self.storySubscriptionsDisposable = (context.engine.messages.storySubscriptions(includeHidden: includeHidden) self.storySubscriptionsDisposable = (context.engine.messages.storySubscriptions(isHidden: isHidden)
|> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in |> deliverOnMainQueue).start(next: { [weak self] storySubscriptions in
guard let self else { guard let self else {
return return

View File

@ -24,7 +24,7 @@ public final class StoryPeerListComponent: Component {
public let theme: PresentationTheme public let theme: PresentationTheme
public let strings: PresentationStrings public let strings: PresentationStrings
public let sideInset: CGFloat public let sideInset: CGFloat
public let includesHidden: Bool public let useHiddenList: Bool
public let storySubscriptions: EngineStorySubscriptions? public let storySubscriptions: EngineStorySubscriptions?
public let collapseFraction: CGFloat public let collapseFraction: CGFloat
public let unlockedFraction: CGFloat public let unlockedFraction: CGFloat
@ -38,7 +38,7 @@ public final class StoryPeerListComponent: Component {
theme: PresentationTheme, theme: PresentationTheme,
strings: PresentationStrings, strings: PresentationStrings,
sideInset: CGFloat, sideInset: CGFloat,
includesHidden: Bool, useHiddenList: Bool,
storySubscriptions: EngineStorySubscriptions?, storySubscriptions: EngineStorySubscriptions?,
collapseFraction: CGFloat, collapseFraction: CGFloat,
unlockedFraction: CGFloat, unlockedFraction: CGFloat,
@ -51,7 +51,7 @@ public final class StoryPeerListComponent: Component {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.sideInset = sideInset self.sideInset = sideInset
self.includesHidden = includesHidden self.useHiddenList = useHiddenList
self.storySubscriptions = storySubscriptions self.storySubscriptions = storySubscriptions
self.collapseFraction = collapseFraction self.collapseFraction = collapseFraction
self.unlockedFraction = unlockedFraction self.unlockedFraction = unlockedFraction
@ -73,7 +73,7 @@ public final class StoryPeerListComponent: Component {
if lhs.sideInset != rhs.sideInset { if lhs.sideInset != rhs.sideInset {
return false return false
} }
if lhs.includesHidden != rhs.includesHidden { if lhs.useHiddenList != rhs.useHiddenList {
return false return false
} }
if lhs.storySubscriptions != rhs.storySubscriptions { if lhs.storySubscriptions != rhs.storySubscriptions {
@ -269,7 +269,7 @@ public final class StoryPeerListComponent: Component {
} }
let _ = hasStories let _ = hasStories
let collapseStartIndex = component.includesHidden ? 0 : 1 let collapseStartIndex = component.useHiddenList ? 0 : 1
let collapsedItemWidth: CGFloat = 24.0 let collapsedItemWidth: CGFloat = 24.0
let collapsedItemDistance: CGFloat = 14.0 let collapsedItemDistance: CGFloat = 14.0
@ -510,8 +510,8 @@ public final class StoryPeerListComponent: Component {
if self.requestedLoadMoreToken != hasMoreToken { if self.requestedLoadMoreToken != hasMoreToken {
self.requestedLoadMoreToken = hasMoreToken self.requestedLoadMoreToken = hasMoreToken
if component.includesHidden { if component.useHiddenList {
if let storySubscriptionsContext = component.context.account.allStorySubscriptionsContext { if let storySubscriptionsContext = component.context.account.hiddenStorySubscriptionsContext {
storySubscriptionsContext.loadMore() storySubscriptionsContext.loadMore()
} }
} else { } else {
@ -526,7 +526,7 @@ public final class StoryPeerListComponent: Component {
self.sortedItems.removeAll(keepingCapacity: true) self.sortedItems.removeAll(keepingCapacity: true)
if let storySubscriptions = component.storySubscriptions { if let storySubscriptions = component.storySubscriptions {
if !component.includesHidden, let accountItem = storySubscriptions.accountItem { if !component.useHiddenList, let accountItem = storySubscriptions.accountItem {
self.sortedItems.append(accountItem) self.sortedItems.append(accountItem)
} }

View File

@ -1686,6 +1686,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} }
var isStory: Bool = false
var game: TelegramMediaGame? var game: TelegramMediaGame?
var webpage: TelegramMediaWebpage? var webpage: TelegramMediaWebpage?
var invoice: TelegramMediaInvoice? var invoice: TelegramMediaInvoice?
@ -1696,6 +1698,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
invoice = media invoice = media
} else if let media = media as? TelegramMediaGame { } else if let media = media as? TelegramMediaGame {
game = media game = media
} else if let _ = media as? TelegramMediaStory {
isStory = true
automaticPlayback = false
} }
} }
@ -1717,6 +1722,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} else if let file = content.file, file.isVideo, !file.isAnimated && !file.isVideoSticker { } else if let file = content.file, file.isVideo, !file.isAnimated && !file.isVideoSticker {
progressRequired = true progressRequired = true
} }
} else if isStory {
progressRequired = true
} }
case .Remote, .Fetching, .Paused: case .Remote, .Fetching, .Paused:
if let webpage = webpage, let automaticDownload = self.automaticDownload, case .full = automaticDownload, case let .Loaded(content) = webpage.content { if let webpage = webpage, let automaticDownload = self.automaticDownload, case .full = automaticDownload, case let .Loaded(content) = webpage.content {
@ -1953,7 +1960,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
state = .customIcon(secretProgressIcon) state = .customIcon(secretProgressIcon)
} else if let file = media as? TelegramMediaFile, !file.isVideoSticker { } else if let file = media as? TelegramMediaFile, !file.isVideoSticker {
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false) let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false)
if !isInlinePlayableVideo && file.isVideo { if (!isInlinePlayableVideo || isStory) && file.isVideo {
state = .play(messageTheme.mediaOverlayControlColors.foregroundColor) state = .play(messageTheme.mediaOverlayControlColors.foregroundColor)
} else { } else {
state = .none state = .none

View File

@ -326,7 +326,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
case "telegram_chatlist": case "telegram_chatlist":
actionTitle = item.presentationData.strings.Conversation_OpenChatFolder actionTitle = item.presentationData.strings.Conversation_OpenChatFolder
case "telegram_story": case "telegram_story":
actionTitle = "Open Story" actionTitle = "OPEN STORY"
default: default:
break break
} }

View File

@ -4094,7 +4094,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
private func openStories(fromAvatar: Bool) { private func openStories(fromAvatar: Bool) {
if let expiringStoryList = self.expiringStoryList, let expiringStoryListState = self.expiringStoryListState, !expiringStoryListState.items.isEmpty { if let expiringStoryList = self.expiringStoryList, let expiringStoryListState = self.expiringStoryListState, !expiringStoryListState.items.isEmpty {
let _ = expiringStoryList let _ = expiringStoryList
let storyContent = StoryContentContextImpl(context: self.context, includeHidden: false, focusedPeerId: self.peerId, singlePeer: true) let storyContent = StoryContentContextImpl(context: self.context, isHidden: false, focusedPeerId: self.peerId, singlePeer: true)
let _ = (storyContent.state let _ = (storyContent.state
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in |> deliverOnMainQueue).start(next: { [weak self] storyContentState in