This commit is contained in:
Ali 2023-07-11 01:50:10 +04:00
parent fbea3fccc0
commit 9672c77070
10 changed files with 159 additions and 13 deletions

View file

@ -7090,6 +7090,7 @@ Sorry for the inconvenience.";
"Time.HoursAgo_many" = "%@ hours ago";
"Time.HoursAgo_0" = "%@ hours ago";
"Time.AtDate" = "%@";
"Time.AtPreciseDate" = "%@ at %@";
"Stickers.ShowMore" = "Show More";

View file

@ -2051,7 +2051,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return
}
if let orderedStorySubscriptions = self.orderedStorySubscriptions, !orderedStorySubscriptions.items.isEmpty {
if case .chatList(groupId: .root) = self.location, let orderedStorySubscriptions = self.orderedStorySubscriptions, !orderedStorySubscriptions.items.isEmpty {
let _ = (ApplicationSpecificNotice.displayChatListStoriesTooltip(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { [weak self] didDisplay in
guard let self else {

View file

@ -434,7 +434,11 @@ private final class ChatListContainerItemNode: ASDisplayNode {
if case .forum = location {
subject = .forum(hasGeneral: hasOnlyGeneralThread)
} else {
subject = .chats(hasArchive: hasOnlyArchive)
if case .chatList(groupId: .archive) = location {
subject = .archive
} else {
subject = .chats(hasArchive: hasOnlyArchive)
}
}
}

View file

@ -13,6 +13,7 @@ import AccountContext
final class ChatListEmptyNode: ASDisplayNode {
enum Subject {
case chats(hasArchive: Bool)
case archive
case filter(showEdit: Bool)
case forum(hasGeneral: Bool)
}
@ -132,11 +133,14 @@ final class ChatListEmptyNode: ASDisplayNode {
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
let text: String
var descriptionText = ""
let buttonText: String
let buttonText: String?
switch self.subject {
case let .chats(hasArchive):
text = hasArchive ? strings.ChatList_EmptyChatListWithArchive : strings.ChatList_EmptyChatList
buttonText = strings.ChatList_EmptyChatListNewMessage
case .archive:
text = strings.ChatList_EmptyChatList
buttonText = nil
case .filter:
text = strings.ChatList_EmptyChatListFilterTitle
descriptionText = strings.ChatList_EmptyChatListFilterText
@ -152,7 +156,12 @@ final class ChatListEmptyNode: ASDisplayNode {
self.textNode.attributedText = string
self.descriptionNode.attributedText = descriptionString
self.buttonNode.title = buttonText
if let buttonText {
self.buttonNode.title = buttonText
self.buttonNode.isHidden = false
} else {
self.buttonNode.isHidden = true
}
self.activityIndicator.type = .custom(theme.list.itemAccentColor, 22.0, 1.0, false)

View file

@ -569,6 +569,16 @@ struct ChatListContactPeer {
}
func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState, savedMessagesPeer: EnginePeer?, foundPeers: [(EnginePeer, EnginePeer?)], hideArchivedFolderByDefault: Bool, displayArchiveIntro: Bool, notice: ChatListNotice?, mode: ChatListNodeMode, chatListLocation: ChatListControllerLocation, contacts: [ChatListContactPeer], accountPeerId: EnginePeer.Id) -> (entries: [ChatListNodeEntry], loading: Bool) {
var groupItems = view.groupItems
if state.archiveStoryState != nil && groupItems.isEmpty {
groupItems.append(EngineChatList.GroupItem(
id: .archive,
topMessage: nil,
items: [],
unreadCount: 0
))
}
var result: [ChatListNodeEntry] = []
if !view.hasEarlier {
@ -588,7 +598,7 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
if !view.hasLater, case .chatList = mode {
var groupEntryCount = 0
for _ in view.groupItems {
for _ in groupItems {
groupEntryCount += 1
}
pinnedIndexOffset += UInt16(groupEntryCount)
@ -831,7 +841,7 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
}
if !view.hasLater, case .chatList = mode {
for groupReference in view.groupItems {
for groupReference in groupItems {
let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: EnginePeer.Id(0), namespace: 0, id: 0), timestamp: 1)
var mappedStoryState: ChatListNodeState.StoryState?
if let archiveStoryState = state.archiveStoryState {

View file

@ -362,7 +362,7 @@ public func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationSt
}
}
public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, preciseTime: Bool = false, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
let difference = timestamp - relativeTimestamp
if difference < 60 {
return strings.Time_JustNow
@ -392,6 +392,8 @@ public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dat
day = .yesterday
}
return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min).string
} else if preciseTime {
return strings.Time_AtPreciseDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat), stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)).string
} else {
return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
}

View file

@ -8,15 +8,22 @@ import TelegramStringFormatting
import MultilineTextComponent
final class StoryAuthorInfoComponent: Component {
struct Counters: Equatable {
var position: Int
var totalCount: Int
}
let context: AccountContext
let peer: EnginePeer?
let timestamp: Int32
let counters: Counters?
let isEdited: Bool
init(context: AccountContext, peer: EnginePeer?, timestamp: Int32, isEdited: Bool) {
init(context: AccountContext, peer: EnginePeer?, timestamp: Int32, counters: Counters?, isEdited: Bool) {
self.context = context
self.peer = peer
self.timestamp = timestamp
self.counters = counters
self.isEdited = isEdited
}
@ -30,6 +37,9 @@ final class StoryAuthorInfoComponent: Component {
if lhs.timestamp != rhs.timestamp {
return false
}
if lhs.counters != rhs.counters {
return false
}
if lhs.isEdited != rhs.isEdited {
return false
}
@ -39,6 +49,7 @@ final class StoryAuthorInfoComponent: Component {
final class View: UIView {
private let title = ComponentView<Empty>()
private let subtitle = ComponentView<Empty>()
private var counterLabel: ComponentView<Empty>?
private var component: StoryAuthorInfoComponent?
private weak var state: EmptyComponentState?
@ -71,7 +82,7 @@ final class StoryAuthorInfoComponent: Component {
}
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
var subtitle = stringForRelativeActivityTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, relativeTimestamp: component.timestamp, relativeTo: timestamp)
var subtitle = stringForRelativeActivityTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, preciseTime: true, relativeTimestamp: component.timestamp, relativeTo: timestamp)
if component.isEdited {
subtitle.append("")
@ -117,6 +128,36 @@ final class StoryAuthorInfoComponent: Component {
}
transition.setFrame(view: subtitleView, frame: subtitleFrame)
}
let countersSpacing: CGFloat = 5.0
if let counters = component.counters {
let counterLabel: ComponentView<Empty>
if let current = self.counterLabel {
counterLabel = current
} else {
counterLabel = ComponentView()
self.counterLabel = counterLabel
}
let counterSize = counterLabel.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "\(counters.position + 1)/\(counters.totalCount)", font: Font.regular(11.0), textColor: UIColor(white: 1.0, alpha: 0.43))),
truncationType: .end,
maximumNumberOfLines: 1
)),
environment: {},
containerSize: CGSize(width: max(1.0, availableSize.width - titleSize.width - countersSpacing), height: 100.0)
)
if let counterLabelView = counterLabel.view {
if counterLabelView.superview == nil {
self.addSubview(counterLabelView)
}
counterLabelView.frame = CGRect(origin: CGPoint(x: titleFrame.maxX + countersSpacing, y: titleFrame.minY + 1.0 + floorToScreenPixels((titleFrame.height - counterSize.height) * 0.5)), size: counterSize)
}
} else if let counterLabel = self.counterLabel {
self.counterLabel = nil
counterLabel.view?.removeFromSuperview()
}
return size
}

View file

@ -269,6 +269,7 @@ public final class StoryContentContextImpl: StoryContentContext {
let allItems = mappedItems.map { item in
return StoryContentItem(
position: nil,
dayCounters: nil,
peerId: peer.id,
storyItem: item,
entityFiles: extractItemEntityFiles(item: item, allEntityFiles: allEntityFiles)
@ -281,6 +282,7 @@ public final class StoryContentContextImpl: StoryContentContext {
additionalPeerData: additionalPeerData,
item: StoryContentItem(
position: mappedFocusedIndex ?? focusedIndex,
dayCounters: nil,
peerId: peer.id,
storyItem: mappedItem,
entityFiles: extractItemEntityFiles(item: mappedItem, allEntityFiles: allEntityFiles)
@ -1011,6 +1013,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
let mainItem = StoryContentItem(
position: 0,
dayCounters: nil,
peerId: peer.id,
storyItem: mappedItem,
entityFiles: extractItemEntityFiles(item: mappedItem, allEntityFiles: allEntityFiles)
@ -1153,20 +1156,58 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
}
}
struct DayIndex: Hashable {
var year: Int32
var day: Int32
init(timestamp: Int32) {
var time: time_t = time_t(timestamp)
var timeinfo: tm = tm()
localtime_r(&time, &timeinfo)
self.year = timeinfo.tm_year
self.day = timeinfo.tm_yday
}
}
let stateValue: StoryContentContextState
if let focusedIndex = focusedIndex {
let item = state.items[focusedIndex]
self.focusedId = item.id
var allItems: [StoryContentItem] = []
var dayCounts: [DayIndex: Int] = [:]
var itemDayIndices: [Int32: (Int, DayIndex)] = [:]
for i in 0 ..< state.items.count {
let stateItem = state.items[i]
allItems.append(StoryContentItem(
position: i,
dayCounters: nil,
peerId: peer.id,
storyItem: stateItem,
entityFiles: extractItemEntityFiles(item: stateItem, allEntityFiles: state.allEntityFiles)
))
let day = DayIndex(timestamp: stateItem.timestamp)
let dayCount: Int
if let current = dayCounts[day] {
dayCount = current + 1
dayCounts[day] = dayCount
} else {
dayCount = 1
dayCounts[day] = dayCount
}
itemDayIndices[stateItem.id] = (dayCount - 1, day)
}
var dayCounters: StoryContentItem.DayCounters?
if let (offset, day) = itemDayIndices[item.id], let dayCount = dayCounts[day] {
dayCounters = StoryContentItem.DayCounters(
position: offset,
totalCount: dayCount
)
}
stateValue = StoryContentContextState(
@ -1175,6 +1216,7 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
additionalPeerData: additionalPeerData,
item: StoryContentItem(
position: focusedIndex,
dayCounters: dayCounters,
peerId: peer.id,
storyItem: item,
entityFiles: extractItemEntityFiles(item: item, allEntityFiles: state.allEntityFiles)

View file

@ -19,6 +19,16 @@ public final class StoryContentItem: Equatable {
case off
}
public struct DayCounters: Equatable {
public var position: Int
public var totalCount: Int
public init(position: Int, totalCount: Int) {
self.position = position
self.totalCount = totalCount
}
}
public final class SharedState {
public init() {
}
@ -78,17 +88,20 @@ public final class StoryContentItem: Equatable {
}
public let position: Int?
public let dayCounters: DayCounters?
public let peerId: EnginePeer.Id?
public let storyItem: EngineStoryItem
public let entityFiles: [EngineMedia.Id: TelegramMediaFile]
public init(
position: Int?,
dayCounters: DayCounters?,
peerId: EnginePeer.Id?,
storyItem: EngineStoryItem,
entityFiles: [EngineMedia.Id: TelegramMediaFile]
) {
self.position = position
self.dayCounters = dayCounters
self.peerId = peerId
self.storyItem = storyItem
self.entityFiles = entityFiles
@ -98,6 +111,9 @@ public final class StoryContentItem: Equatable {
if lhs.position != rhs.position {
return false
}
if lhs.dayCounters != rhs.dayCounters {
return false
}
if lhs.peerId != rhs.peerId {
return false
}

View file

@ -2445,8 +2445,22 @@ public final class StoryItemSetContainerComponent: Component {
}
var currentCenterInfoItem: InfoItem?
if focusedItem != nil {
let centerInfoComponent = AnyComponent(StoryAuthorInfoComponent(context: component.context, peer: component.slice.peer, timestamp: component.slice.item.storyItem.timestamp, isEdited: component.slice.item.storyItem.isEdited))
if let focusedItem {
var counters: StoryAuthorInfoComponent.Counters?
if focusedItem.dayCounters != nil, let position = focusedItem.position {
counters = StoryAuthorInfoComponent.Counters(
position: position,
totalCount: component.slice.totalCount
)
}
let centerInfoComponent = AnyComponent(StoryAuthorInfoComponent(
context: component.context,
peer: component.slice.peer,
timestamp: component.slice.item.storyItem.timestamp,
counters: counters,
isEdited: component.slice.item.storyItem.isEdited
))
if let centerInfoItem = self.centerInfoItem, centerInfoItem.component == centerInfoComponent {
currentCenterInfoItem = centerInfoItem
} else {
@ -2987,11 +3001,18 @@ public final class StoryItemSetContainerComponent: Component {
let navigationStripSideInset: CGFloat = 8.0
let navigationStripTopInset: CGFloat = 8.0
var index = max(0, min(index, component.slice.totalCount - 1))
var count = component.slice.totalCount
if let dayCounters = focusedItem.dayCounters {
index = dayCounters.position
count = dayCounters.totalCount
}
let _ = self.navigationStrip.update(
transition: transition,
component: AnyComponent(MediaNavigationStripComponent(
index: max(0, min(index, component.slice.totalCount - 1)),
count: component.slice.totalCount
index: index,
count: count
)),
environment: {
MediaNavigationStripComponent.EnvironmentType(