mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Stories
This commit is contained in:
parent
ebd9446663
commit
cdd58e05f7
@ -9712,6 +9712,7 @@ Sorry for the inconvenience.";
|
||||
"Story.Privacy.PostStory" = "Post Story";
|
||||
|
||||
"Story.Views.ViewsExpired" = "List of viewers becomes unavailable **24 hours** after the story expires.";
|
||||
"Story.Views.ViewsNotRecorded" = "Information about viewers wasn’t recorded.";
|
||||
"Story.Views.NoViews" = "Nobody has viewed\nyour story yet.";
|
||||
|
||||
"AutoDownloadSettings.Stories" = "Stories";
|
||||
@ -9823,6 +9824,7 @@ Sorry for the inconvenience.";
|
||||
"Story.ViewList.PremiumUpgradeText" = "List of viewers isn't available after 24 hours of story expiration.\n\nTo unlock viewers' lists for expired and saved stories, subscribe to [Telegram Premium]().";
|
||||
"Story.ViewList.PremiumUpgradeAction" = "Learn More";
|
||||
"Story.ViewList.PremiumUpgradeInlineText" = "To unlock viewers' lists for expired and saved stories, subscribe to [Telegram Premium]().";
|
||||
"Story.ViewList.NotFullyRecorded" = "Information about the other viewers wasn’t recorded.";
|
||||
"Story.ViewList.EmptyTextSearch" = "No views found";
|
||||
"Story.ViewList.EmptyTextContacts" = "None of your contacts viewed this story.";
|
||||
"Story.ViewList.ContextSortReactions" = "Reactions First";
|
||||
|
@ -335,7 +335,7 @@ public final class EngineStoryViewListContext {
|
||||
mediaAreas: item.mediaAreas,
|
||||
text: item.text,
|
||||
entities: item.entities,
|
||||
views: Stories.Item.Views(seenCount: Int(count), reactedCount: Int(reactionsCount), seenPeerIds: currentViews.seenPeerIds),
|
||||
views: Stories.Item.Views(seenCount: Int(count), reactedCount: Int(reactionsCount), seenPeerIds: currentViews.seenPeerIds, hasList: currentViews.hasList),
|
||||
privacy: item.privacy,
|
||||
isPinned: item.isPinned,
|
||||
isExpired: item.isExpired,
|
||||
@ -364,7 +364,7 @@ public final class EngineStoryViewListContext {
|
||||
mediaAreas: item.mediaAreas,
|
||||
text: item.text,
|
||||
entities: item.entities,
|
||||
views: Stories.Item.Views(seenCount: Int(count), reactedCount: Int(reactionsCount), seenPeerIds: currentViews.seenPeerIds),
|
||||
views: Stories.Item.Views(seenCount: Int(count), reactedCount: Int(reactionsCount), seenPeerIds: currentViews.seenPeerIds, hasList: currentViews.hasList),
|
||||
privacy: item.privacy,
|
||||
isPinned: item.isPinned,
|
||||
isExpired: item.isExpired,
|
||||
|
@ -43,16 +43,19 @@ public enum Stories {
|
||||
case seenCount = "seenCount"
|
||||
case reactedCount = "reactedCount"
|
||||
case seenPeerIds = "seenPeerIds"
|
||||
case hasList = "hasList"
|
||||
}
|
||||
|
||||
public var seenCount: Int
|
||||
public var reactedCount: Int
|
||||
public var seenPeerIds: [PeerId]
|
||||
public var hasList: Bool
|
||||
|
||||
public init(seenCount: Int, reactedCount: Int, seenPeerIds: [PeerId]) {
|
||||
public init(seenCount: Int, reactedCount: Int, seenPeerIds: [PeerId], hasList: Bool) {
|
||||
self.seenCount = seenCount
|
||||
self.reactedCount = reactedCount
|
||||
self.seenPeerIds = seenPeerIds
|
||||
self.hasList = hasList
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@ -61,6 +64,7 @@ public enum Stories {
|
||||
self.seenCount = Int(try container.decode(Int32.self, forKey: .seenCount))
|
||||
self.reactedCount = Int(try container.decodeIfPresent(Int32.self, forKey: .reactedCount) ?? 0)
|
||||
self.seenPeerIds = try container.decode([Int64].self, forKey: .seenPeerIds).map(PeerId.init)
|
||||
self.hasList = try container.decodeIfPresent(Bool.self, forKey: .hasList) ?? true
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -69,6 +73,7 @@ public enum Stories {
|
||||
try container.encode(Int32(clamping: self.seenCount), forKey: .seenCount)
|
||||
try container.encode(Int32(clamping: self.reactedCount), forKey: .reactedCount)
|
||||
try container.encode(self.seenPeerIds.map { $0.toInt64() }, forKey: .seenPeerIds)
|
||||
try container.encode(self.hasList, forKey: .hasList)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1395,12 +1400,13 @@ extension Api.StoryItem {
|
||||
extension Stories.Item.Views {
|
||||
init(apiViews: Api.StoryViews) {
|
||||
switch apiViews {
|
||||
case let .storyViews(_, viewsCount, reactionsCount, recentViewers):
|
||||
case let .storyViews(flags, viewsCount, reactionsCount, recentViewers):
|
||||
let hasList = (flags & (1 << 1)) != 0
|
||||
var seenPeerIds: [PeerId] = []
|
||||
if let recentViewers = recentViewers {
|
||||
seenPeerIds = recentViewers.map { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }
|
||||
}
|
||||
self.init(seenCount: Int(viewsCount), reactedCount: Int(reactionsCount), seenPeerIds: seenPeerIds)
|
||||
self.init(seenCount: Int(viewsCount), reactedCount: Int(reactionsCount), seenPeerIds: seenPeerIds, hasList: hasList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,13 @@ public final class EngineStoryItem: Equatable {
|
||||
public let seenCount: Int
|
||||
public let reactedCount: Int
|
||||
public let seenPeers: [EnginePeer]
|
||||
public let hasList: Bool
|
||||
|
||||
public init(seenCount: Int, reactedCount: Int, seenPeers: [EnginePeer]) {
|
||||
public init(seenCount: Int, reactedCount: Int, seenPeers: [EnginePeer], hasList: Bool) {
|
||||
self.seenCount = seenCount
|
||||
self.reactedCount = reactedCount
|
||||
self.seenPeers = seenPeers
|
||||
self.hasList = hasList
|
||||
}
|
||||
|
||||
public static func ==(lhs: Views, rhs: Views) -> Bool {
|
||||
@ -32,6 +34,9 @@ public final class EngineStoryItem: Equatable {
|
||||
if lhs.seenPeers != rhs.seenPeers {
|
||||
return false
|
||||
}
|
||||
if lhs.hasList != rhs.hasList {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -154,7 +159,8 @@ extension EngineStoryItem {
|
||||
return Stories.Item.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeerIds: views.seenPeers.map(\.id)
|
||||
seenPeerIds: views.seenPeers.map(\.id),
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: self.privacy.flatMap { privacy in
|
||||
@ -529,7 +535,8 @@ public final class PeerStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return transaction.getPeer(id).flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -656,7 +663,8 @@ public final class PeerStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return transaction.getPeer(id).flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -807,7 +815,8 @@ public final class PeerStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -849,7 +858,8 @@ public final class PeerStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -893,7 +903,8 @@ public final class PeerStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -933,7 +944,8 @@ public final class PeerStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -1097,7 +1109,8 @@ public final class PeerExpiringStoryListContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return transaction.getPeer(id).flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
|
@ -161,7 +161,8 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: item.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
@ -1037,7 +1038,8 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
},
|
||||
hasList: views.hasList
|
||||
)
|
||||
},
|
||||
privacy: itemValue.privacy.flatMap(EngineStoryPrivacy.init),
|
||||
|
@ -586,6 +586,9 @@ final class StoryItemSetViewListComponent: Component {
|
||||
if let baseContentView, baseContentView.configuration == self.configuration, baseContentView.query == nil {
|
||||
parentSource = baseContentView.viewList
|
||||
}
|
||||
if component.context.sharedContext.immediateExperimentalUISettings.storiesExperiment {
|
||||
parentSource = nil
|
||||
}
|
||||
|
||||
self.viewList = component.context.engine.messages.storyViewList(id: component.storyItem.id, views: views, listMode: mappedListMode, sortMode: mappedSortMode, searchQuery: query, parentSource: parentSource)
|
||||
}
|
||||
@ -753,7 +756,7 @@ final class StoryItemSetViewListComponent: Component {
|
||||
}
|
||||
|
||||
var premiumFooterSize: CGSize?
|
||||
if !component.hasPremium, let viewListState = self.viewListState, viewListState.loadMoreToken == nil, !viewListState.items.isEmpty, let views = component.storyItem.views, views.seenCount > viewListState.totalCount, component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) {
|
||||
if let viewListState = self.viewListState, viewListState.loadMoreToken == nil, !viewListState.items.isEmpty, let views = component.storyItem.views, views.seenCount > viewListState.totalCount, component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) {
|
||||
let premiumFooterText: ComponentView<Empty>
|
||||
if let current = self.premiumFooterText {
|
||||
premiumFooterText = current
|
||||
@ -768,7 +771,15 @@ final class StoryItemSetViewListComponent: Component {
|
||||
let link = MarkdownAttributeSet(font: Font.semibold(fontSize), textColor: component.theme.list.itemAccentColor)
|
||||
let attributes = MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { _ in return ("URL", "") })
|
||||
|
||||
let text = component.strings.Story_ViewList_PremiumUpgradeInlineText
|
||||
let text: String
|
||||
let fullWidth: Bool
|
||||
if component.hasPremium {
|
||||
text = component.strings.Story_ViewList_NotFullyRecorded
|
||||
fullWidth = true
|
||||
} else {
|
||||
text = component.strings.Story_ViewList_PremiumUpgradeInlineText
|
||||
fullWidth = false
|
||||
}
|
||||
premiumFooterSize = premiumFooterText.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(BalancedTextComponent(
|
||||
@ -777,14 +788,14 @@ final class StoryItemSetViewListComponent: Component {
|
||||
maximumNumberOfLines: 0,
|
||||
lineSpacing: 0.2,
|
||||
highlightColor: component.theme.list.itemAccentColor.withMultipliedAlpha(0.5),
|
||||
highlightAction: { attributes in
|
||||
highlightAction: component.hasPremium ? nil : { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||
return NSAttributedString.Key(rawValue: "URL")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
},
|
||||
tapAction: { [weak self] _, _ in
|
||||
tapAction: component.hasPremium ? nil : { [weak self] _, _ in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
@ -792,7 +803,7 @@ final class StoryItemSetViewListComponent: Component {
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: min(320.0, availableSize.width - 16.0 * 2.0), height: 1000.0)
|
||||
containerSize: CGSize(width: min(fullWidth ? 500.0 : 320.0, availableSize.width - 16.0 * 2.0), height: 1000.0)
|
||||
)
|
||||
} else {
|
||||
if let premiumFooterText = self.premiumFooterText {
|
||||
@ -894,7 +905,11 @@ final class StoryItemSetViewListComponent: Component {
|
||||
if self.configuration.listMode == .everyone && (self.query == nil || self.query == "") {
|
||||
if component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) {
|
||||
if emptyButton == nil {
|
||||
text = component.strings.Story_Views_ViewsExpired
|
||||
if let views = component.storyItem.views, views.seenCount > 0 {
|
||||
text = component.strings.Story_Views_ViewsNotRecorded
|
||||
} else {
|
||||
text = component.strings.Story_Views_ViewsExpired
|
||||
}
|
||||
} else {
|
||||
text = component.strings.Story_ViewList_PremiumUpgradeText
|
||||
}
|
||||
@ -909,7 +924,11 @@ final class StoryItemSetViewListComponent: Component {
|
||||
} else {
|
||||
if component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) {
|
||||
if emptyButton == nil {
|
||||
text = component.strings.Story_Views_ViewsExpired
|
||||
if let views = component.storyItem.views, views.seenCount > 0 {
|
||||
text = component.strings.Story_Views_ViewsNotRecorded
|
||||
} else {
|
||||
text = component.strings.Story_Views_ViewsExpired
|
||||
}
|
||||
} else {
|
||||
text = component.strings.Story_ViewList_PremiumUpgradeText
|
||||
}
|
||||
@ -1341,7 +1360,7 @@ final class StoryItemSetViewListComponent: Component {
|
||||
|
||||
if !component.hasPremium, component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) {
|
||||
} else {
|
||||
if let views = component.storyItem.views {
|
||||
if let views = component.storyItem.views, views.hasList {
|
||||
if views.seenCount >= 20 || component.context.sharedContext.immediateExperimentalUISettings.storiesExperiment {
|
||||
displayModeSelector = true
|
||||
displaySearchBar = true
|
||||
|
Loading…
x
Reference in New Issue
Block a user