From 53ec081c05747fe5f5336a60a2a55a743c6be39e Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 23 Sep 2018 14:46:45 +0100 Subject: [PATCH] no message --- TelegramUI.xcodeproj/project.pbxproj | 4 + TelegramUI/BlockedPeersController.swift | 21 +- TelegramUI/CallListCallItem.swift | 8 +- TelegramUI/CallListController.swift | 11 +- TelegramUI/CallListControllerNode.swift | 38 ++- TelegramUI/CallListNodeEntries.swift | 21 +- TelegramUI/ChannelAdminController.swift | 15 +- TelegramUI/ChannelAdminsController.swift | 21 +- .../ChannelBannedMemberController.swift | 15 +- TelegramUI/ChannelBlacklistController.swift | 27 +- TelegramUI/ChannelInfoController.swift | 15 +- TelegramUI/ChannelMembersController.swift | 21 +- TelegramUI/ChannelVisibilityController.swift | 17 +- TelegramUI/ChatController.swift | 9 +- TelegramUI/ChatDocumentGalleryItem.swift | 18 +- TelegramUI/ChatExternalFileGalleryItem.swift | 20 +- TelegramUI/ChatHistoryGridNode.swift | 2 +- TelegramUI/ChatHistoryListNode.swift | 14 +- .../ChatHistorySearchContainerNode.swift | 27 +- TelegramUI/ChatImageGalleryItem.swift | 18 +- .../ChatItemGalleryFooterContentNode.swift | 16 +- TelegramUI/ChatListController.swift | 4 +- TelegramUI/ChatListControllerNode.swift | 14 +- TelegramUI/ChatListItem.swift | 2 +- TelegramUI/ChatListNode.swift | 10 +- TelegramUI/ChatListPresentationData.swift | 6 +- TelegramUI/ChatListSearchContainerNode.swift | 6 +- .../ChatMessageAttachedContentNode.swift | 2 +- TelegramUI/ChatMessageBubbleItemNode.swift | 2 +- .../ChatMessageCallBubbleContentNode.swift | 2 +- .../ChatMessageContactBubbleContentNode.swift | 4 +- .../ChatMessageInteractiveFileNode.swift | 2 +- ...atMessageInteractiveInstantVideoNode.swift | 2 +- .../ChatMessageLiveLocationTextNode.swift | 10 +- .../ChatMessageMapBubbleContentNode.swift | 4 +- .../ChatMessageMediaBubbleContentNode.swift | 2 +- TelegramUI/ChatMessageStickerItemNode.swift | 2 +- .../ChatMessageTextBubbleContentNode.swift | 2 +- TelegramUI/ChatPresentationData.swift | 6 +- .../ChatPresentationInterfaceState.swift | 69 ++-- .../ChatRecentActionsControllerNode.swift | 2 +- .../ChatRecentActionsFilterController.swift | 21 +- TelegramUI/ChatRestrictedInputPanelNode.swift | 2 +- TelegramUI/ChatTitleView.swift | 8 +- TelegramUI/ContactListNode.swift | 20 +- TelegramUI/ContactsPeerItem.swift | 6 +- TelegramUI/CreateChannelController.swift | 15 +- TelegramUI/CreateGroupController.swift | 32 +- TelegramUI/DateFormat.swift | 34 +- TelegramUI/DeviceContactInfoController.swift | 17 +- ...textResultsChatInputContextPanelNode.swift | 2 +- TelegramUI/EditSettingsController.swift | 15 +- TelegramUI/FeedGroupingControllerNode.swift | 29 +- TelegramUI/FormBlockItemNode.swift | 6 +- TelegramUI/FormController.swift | 2 +- TelegramUI/FormControllerActionItem.swift | 6 +- .../FormControllerDetailActionItem.swift | 6 +- TelegramUI/FormControllerHeaderItem.swift | 2 +- TelegramUI/FormControllerItem.swift | 2 +- TelegramUI/FormControllerNode.swift | 12 +- TelegramUI/FormControllerTextInputItem.swift | 6 +- TelegramUI/FormControllerTextItem.swift | 2 +- TelegramUI/GalleryController.swift | 22 +- .../GalleryThumbnailContainerNode.swift | 3 +- TelegramUI/GroupAdminsController.swift | 21 +- TelegramUI/GroupInfoController.swift | 36 +- TelegramUI/GroupsInCommonController.swift | 21 +- TelegramUI/HashtagSearchController.swift | 2 +- TelegramUI/InstantImageGalleryItem.swift | 18 +- TelegramUI/InstantPageController.swift | 2 +- TelegramUI/InstantPageControllerNode.swift | 8 +- TelegramUI/InstantPageGalleryController.swift | 10 +- .../InstantPageGalleryFooterContentNode.swift | 6 +- TelegramUI/InstantPageLayout.swift | 12 +- TelegramUI/ItemListAvatarAndNameItem.swift | 8 +- TelegramUI/ItemListCallListItem.swift | 312 ++++++++++++++++++ TelegramUI/ItemListPeerItem.swift | 6 +- TelegramUI/ItemListRecentSessionItem.swift | 6 +- TelegramUI/ItemListWebsiteItem.swift | 6 +- TelegramUI/ListMessageFileItemNode.swift | 2 +- TelegramUI/ListMessageItem.swift | 4 +- ...ediaNavigationAccessoryContainerNode.swift | 2 +- .../MediaNavigationAccessoryHeaderNode.swift | 11 +- .../PeerMediaCollectionControllerNode.swift | 2 +- TelegramUI/PeerSelectionControllerNode.swift | 4 +- TelegramUI/PresenceStrings.swift | 70 ++-- TelegramUI/PresentationData.swift | 66 +++- TelegramUI/RecentSessionsController.swift | 48 +-- TelegramUI/SecretMediaPreviewController.swift | 4 +- TelegramUI/SecureIdAuthControllerNode.swift | 69 +++- TelegramUI/SecureIdAuthFormFieldNode.swift | 24 +- TelegramUI/SecureIdAuthListContentNode.swift | 6 +- .../SecureIdDocumentFormController.swift | 4 + .../SecureIdDocumentFormControllerNode.swift | 45 +-- .../SecureIdPlaintextFormControllerNode.swift | 10 +- TelegramUI/SecureIdValueFormFileItem.swift | 8 +- TelegramUI/SecureIdValueFormPhoneItem.swift | 6 +- ...ectivePrivacySettingsPeersController.swift | 21 +- TelegramUI/SettingsController.swift | 15 +- TelegramUI/ShareSearchContainerNode.swift | 6 +- TelegramUI/StorageUsageController.swift | 17 +- .../StringForMessageTimestampStatus.swift | 4 +- .../ThemeAutoNightSettingsController.swift | 10 +- TelegramUI/ThemeSettingsChatPreviewItem.swift | 8 +- TelegramUI/ThemeSettingsController.swift | 16 +- TelegramUI/UniversalVideoCalleryItem.swift | 22 +- TelegramUI/UserInfoController.swift | 63 +++- TelegramUI/WebEmbedPlayerNode.swift | 12 +- TelegramUI/WebEmbedVideoContent.swift | 60 +--- TelegramUI/YoutubeEmbedImplementation.swift | 21 +- 110 files changed, 1225 insertions(+), 690 deletions(-) create mode 100644 TelegramUI/ItemListCallListItem.swift diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index 0518d98ded..67e644f327 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 091BEAB3214552D9003AEA30 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D02DADBE2138D76F00116225 /* Vision.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 092F368D2154AAEA001A9F49 /* SFCompactRounded-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */; }; + 092F36902157AB46001A9F49 /* ItemListCallListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */; }; 09310D2C213ED5FB0020033A /* anim_read.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D14213BC5DE0020033A /* anim_read.json */; }; 09310D2D213ED5FB0020033A /* anim_pin.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D15213BC5DE0020033A /* anim_pin.json */; }; 09310D2E213ED5FB0020033A /* anim_unmute.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D16213BC5DE0020033A /* anim_unmute.json */; }; @@ -1024,6 +1025,7 @@ /* Begin PBXFileReference section */ 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SFCompactRounded-Semibold.otf"; sourceTree = ""; }; + 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListCallListItem.swift; sourceTree = ""; }; 09310D14213BC5DE0020033A /* anim_read.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_read.json; sourceTree = ""; }; 09310D15213BC5DE0020033A /* anim_pin.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_pin.json; sourceTree = ""; }; 09310D16213BC5DE0020033A /* anim_unmute.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_unmute.json; sourceTree = ""; }; @@ -3770,6 +3772,7 @@ D084023320E295F000065674 /* GroupStickerPackSetupController.swift */, D0F19F6120E5694D00EEC860 /* GroupStickerPackCurrentItem.swift */, D0F4B019211073C500912B92 /* DeviceContactInfoController.swift */, + 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */, ); name = "Peer Info"; sourceTree = ""; @@ -4717,6 +4720,7 @@ D0EC6CC41EB9F58800EBF1C3 /* LegacyLocationPicker.swift in Sources */, D0EC6CC51EB9F58800EBF1C3 /* TGDataItem.m in Sources */, D093D7DD2062D09A00BC3599 /* SecureIdAuthFormFieldNode.swift in Sources */, + 092F36902157AB46001A9F49 /* ItemListCallListItem.swift in Sources */, D0EC6CC61EB9F58800EBF1C3 /* PresenceStrings.swift in Sources */, D0EC6CC71EB9F58800EBF1C3 /* PeerNotificationSoundStrings.swift in Sources */, D01C06C01FBF118A001561AB /* MessageUtils.swift in Sources */, diff --git a/TelegramUI/BlockedPeersController.swift b/TelegramUI/BlockedPeersController.swift index c71d3bdea2..ce4670510f 100644 --- a/TelegramUI/BlockedPeersController.swift +++ b/TelegramUI/BlockedPeersController.swift @@ -33,7 +33,7 @@ private enum BlockedPeersEntryStableId: Hashable { private enum BlockedPeersEntry: ItemListNodeEntry { case add(PresentationTheme, String) - case peerItem(Int32, PresentationTheme, PresentationStrings, Peer, ItemListPeerItemEditing, Bool) + case peerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, ItemListPeerItemEditing, Bool) var section: ItemListSectionId { switch self { @@ -48,7 +48,7 @@ private enum BlockedPeersEntry: ItemListNodeEntry { switch self { case .add: return .add - case let .peerItem(_, _, _, peer, _, _): + case let .peerItem(_, _, _, _, peer, _, _): return .peer(peer.id) } } @@ -61,8 +61,8 @@ private enum BlockedPeersEntry: ItemListNodeEntry { } else { return false } - case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsEditing, lhsEnabled): - if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsEditing, rhsEnabled) = rhs { + case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsEditing, lhsEnabled): + if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsEditing, rhsEnabled) = rhs { if lhsIndex != rhsIndex { return false } @@ -72,6 +72,9 @@ private enum BlockedPeersEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !lhsPeer.isEqual(rhsPeer) { return false } @@ -96,11 +99,11 @@ private enum BlockedPeersEntry: ItemListNodeEntry { } else { return false } - case let .peerItem(index, _, _, _, _, _): + case let .peerItem(index, _, _, _, _, _, _): switch rhs { case .add: return false - case let .peerItem(rhsIndex, _, _, _, _, _): + case let .peerItem(rhsIndex, _, _, _, _, _, _): return index < rhsIndex } } @@ -112,8 +115,8 @@ private enum BlockedPeersEntry: ItemListNodeEntry { return ItemListActionItem(theme: theme, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { arguments.addPeer() }) - case let .peerItem(_, theme, strings, peer, editing, enabled): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: { + case let .peerItem(_, theme, strings, dateTimeFormat, peer, editing, enabled): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) @@ -176,7 +179,7 @@ private func blockedPeersControllerEntries(presentationData: PresentationData, s var index: Int32 = 0 for peer in peers { - entries.append(.peerItem(index, presentationData.theme, presentationData.strings, peer, ItemListPeerItemEditing(editable: true, editing: state.editing, revealed: peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != peer.id)) + entries.append(.peerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, ItemListPeerItemEditing(editable: true, editing: state.editing, revealed: peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != peer.id)) index += 1 } } diff --git a/TelegramUI/CallListCallItem.swift b/TelegramUI/CallListCallItem.swift index 228c141cb1..a89c4069f0 100644 --- a/TelegramUI/CallListCallItem.swift +++ b/TelegramUI/CallListCallItem.swift @@ -63,6 +63,7 @@ private func callListNeighbors(item: ListViewItem, topItem: ListViewItem?, botto class CallListCallItem: ListViewItem { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let account: Account let style: ItemListStyle let topMessage: Message @@ -75,9 +76,10 @@ class CallListCallItem: ListViewItem { let headerAccessoryItem: ListViewAccessoryItem? let header: ListViewItemHeader? - init(theme: PresentationTheme, strings: PresentationStrings, account: Account, style: ItemListStyle, topMessage: Message, messages: [Message], editing: Bool, revealed: Bool, interaction: CallListNodeInteraction) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, account: Account, style: ItemListStyle, topMessage: Message, messages: [Message], editing: Bool, revealed: Bool, interaction: CallListNodeInteraction) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.account = account self.style = style self.topMessage = topMessage @@ -410,7 +412,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { localtime_r(&t, &timeinfo) let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - let dateText = stringForRelativeTimestamp(strings: item.strings, relativeTimestamp: item.topMessage.timestamp, relativeTo: timestamp, timeFormat: .regular) + let dateText = stringForRelativeTimestamp(strings: item.strings, relativeTimestamp: item.topMessage.timestamp, relativeTo: timestamp, dateTimeFormat: item.dateTimeFormat) let (dateLayout, dateApply) = makeDateLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: dateText, font: dateFont, textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0.0, params.width - leftInset - rightInset), height: CGFloat.infinity), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) @@ -586,7 +588,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { @objc func infoPressed() { if let item = self.layoutParams?.0 { - item.interaction.openInfo(item.topMessage.id.peerId) + item.interaction.openInfo(item.topMessage.id.peerId, item.messages) } } diff --git a/TelegramUI/CallListController.swift b/TelegramUI/CallListController.swift index 64a2b22ac0..3c6459967d 100644 --- a/TelegramUI/CallListController.swift +++ b/TelegramUI/CallListController.swift @@ -121,7 +121,7 @@ public final class CallListController: ViewController { self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) if self.isNodeLoaded { - self.controllerNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings) + self.controllerNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat) } } @@ -131,15 +131,14 @@ public final class CallListController: ViewController { if let strongSelf = self { strongSelf.call(peerId) } - }, openInfo: { [weak self] peerId in + }, openInfo: { [weak self] peerId, messages in if let strongSelf = self { let _ = (strongSelf.account.postbox.loadedPeerWithId(peerId) |> take(1) |> deliverOnMainQueue).start(next: { peer in if let strongSelf = self { - if let infoController = peerInfoController(account: strongSelf.account, peer: peer) { - (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) - } + let infoController = userInfoController(account: strongSelf.account, peerId: peer.id, mode: .calls(messages: messages)) + (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } }) } @@ -199,7 +198,7 @@ public final class CallListController: ViewController { |> timeout(1.0, queue: Queue.mainQueue(), alternate: .single(true)) |> delay(0.5, queue: Queue.mainQueue()) |> deliverOnMainQueue).start(next: { _ in - if let strongSelf = self, let controller = controller, let navigationController = controller.navigationController as? NavigationController { + if let _ = self, let controller = controller, let navigationController = controller.navigationController as? NavigationController { if navigationController.viewControllers.last === controller { let _ = navigationController.popViewController(animated: true) } diff --git a/TelegramUI/CallListControllerNode.swift b/TelegramUI/CallListControllerNode.swift index 5b2141fa47..7f7d58f81b 100644 --- a/TelegramUI/CallListControllerNode.swift +++ b/TelegramUI/CallListControllerNode.swift @@ -52,11 +52,11 @@ private extension CallListViewEntry { final class CallListNodeInteraction { let setMessageIdWithRevealedOptions: (MessageId?, MessageId?) -> Void let call: (PeerId) -> Void - let openInfo: (PeerId) -> Void + let openInfo: (PeerId, [Message]) -> Void let delete: ([MessageId]) -> Void let updateShowCallsTab: (Bool) -> Void - init(setMessageIdWithRevealedOptions: @escaping (MessageId?, MessageId?) -> Void, call: @escaping (PeerId) -> Void, openInfo: @escaping (PeerId) -> Void, delete: @escaping ([MessageId]) -> Void, updateShowCallsTab: @escaping (Bool) -> Void) { + init(setMessageIdWithRevealedOptions: @escaping (MessageId?, MessageId?) -> Void, call: @escaping (PeerId) -> Void, openInfo: @escaping (PeerId, [Message]) -> Void, delete: @escaping ([MessageId]) -> Void, updateShowCallsTab: @escaping (Bool) -> Void) { self.setMessageIdWithRevealedOptions = setMessageIdWithRevealedOptions self.call = call self.openInfo = openInfo @@ -68,19 +68,20 @@ final class CallListNodeInteraction { struct CallListNodeState: Equatable { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let editing: Bool let messageIdWithRevealedOptions: MessageId? - func withUpdatedPresentationData(theme: PresentationTheme, strings: PresentationStrings) -> CallListNodeState { - return CallListNodeState(theme: theme, strings: strings, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions) + func withUpdatedPresentationData(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> CallListNodeState { + return CallListNodeState(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions) } func withUpdatedEditing(_ editing: Bool) -> CallListNodeState { - return CallListNodeState(theme: self.theme, strings: self.strings, editing: editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions) + return CallListNodeState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, editing: editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions) } func withUpdatedMessageIdWithRevealedOptions(_ messageIdWithRevealedOptions: MessageId?) -> CallListNodeState { - return CallListNodeState(theme: self.theme, strings: self.strings, editing: self.editing, messageIdWithRevealedOptions: messageIdWithRevealedOptions) + return CallListNodeState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, editing: self.editing, messageIdWithRevealedOptions: messageIdWithRevealedOptions) } static func ==(lhs: CallListNodeState, rhs: CallListNodeState) -> Bool { @@ -90,6 +91,9 @@ struct CallListNodeState: Equatable { if lhs.strings !== rhs.strings { return false } + if lhs.dateTimeFormat != rhs.dateTimeFormat { + return false + } if lhs.editing != rhs.editing { return false } @@ -109,8 +113,8 @@ private func mappedInsertEntries(account: Account, showSettings: Bool, nodeInter }), directionHint: entry.directionHint) case let .displayTabInfo(theme, text): return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(theme: theme, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) - case let .messageEntry(topMessage, messages, theme, strings, editing, hasActiveRevealControls): - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: CallListCallItem(theme: theme, strings: strings, account: account, style: showSettings ? .blocks : .plain, topMessage: topMessage, messages: messages, editing: editing, revealed: hasActiveRevealControls, interaction: nodeInteraction), directionHint: entry.directionHint) + case let .messageEntry(topMessage, messages, theme, strings, dateTimeFormat, editing, hasActiveRevealControls): + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: CallListCallItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: account, style: showSettings ? .blocks : .plain, topMessage: topMessage, messages: messages, editing: editing, revealed: hasActiveRevealControls, interaction: nodeInteraction), directionHint: entry.directionHint) case let .holeEntry(_, theme): return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint) } @@ -126,8 +130,8 @@ private func mappedUpdateEntries(account: Account, showSettings: Bool, nodeInter }), directionHint: entry.directionHint) case let .displayTabInfo(theme, text): return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(theme: theme, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) - case let .messageEntry(topMessage, messages, theme, strings, editing, hasActiveRevealControls): - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: CallListCallItem(theme: theme, strings: strings, account: account, style: showSettings ? .blocks : .plain, topMessage: topMessage, messages: messages, editing: editing, revealed: hasActiveRevealControls, interaction: nodeInteraction), directionHint: entry.directionHint) + case let .messageEntry(topMessage, messages, theme, strings, dateTimeFormat, editing, hasActiveRevealControls): + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: CallListCallItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: account, style: showSettings ? .blocks : .plain, topMessage: topMessage, messages: messages, editing: editing, revealed: hasActiveRevealControls, interaction: nodeInteraction), directionHint: entry.directionHint) case let .holeEntry(_, theme): return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint) } @@ -180,13 +184,13 @@ final class CallListControllerNode: ASDisplayNode { private let emptyTextNode: ASTextNode private let call: (PeerId) -> Void - private let openInfo: (PeerId) -> Void + private let openInfo: (PeerId, [Message]) -> Void private let emptyStateUpdated: (Bool) -> Void private let emptyStatePromise = Promise() private let emptyStateDisposable = MetaDisposable() - init(account: Account, mode: CallListControllerMode, presentationData: PresentationData, call: @escaping (PeerId) -> Void, openInfo: @escaping (PeerId) -> Void, emptyStateUpdated: @escaping (Bool) -> Void) { + init(account: Account, mode: CallListControllerMode, presentationData: PresentationData, call: @escaping (PeerId) -> Void, openInfo: @escaping (PeerId, [Message]) -> Void, emptyStateUpdated: @escaping (Bool) -> Void) { self.account = account self.mode = mode self.presentationData = presentationData @@ -194,7 +198,7 @@ final class CallListControllerNode: ASDisplayNode { self.openInfo = openInfo self.emptyStateUpdated = emptyStateUpdated - self.currentState = CallListNodeState(theme: presentationData.theme, strings: presentationData.strings, editing: false, messageIdWithRevealedOptions: nil) + self.currentState = CallListNodeState(theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, editing: false, messageIdWithRevealedOptions: nil) self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true) self.listNode = ListView() @@ -234,8 +238,8 @@ final class CallListControllerNode: ASDisplayNode { } }, call: { [weak self] peerId in self?.call(peerId) - }, openInfo: { [weak self] peerId in - self?.openInfo(peerId) + }, openInfo: { [weak self] peerId, messages in + self?.openInfo(peerId, messages) }, delete: { [weak self] messageIds in if let strongSelf = self { let _ = deleteMessagesInteractively(postbox: strongSelf.account.postbox, messageIds: messageIds, type: .forLocalPeer).start() @@ -367,7 +371,7 @@ final class CallListControllerNode: ASDisplayNode { self.emptyStateDisposable.dispose() } - func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { + func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) { if theme !== self.currentState.theme || strings !== self.currentState.strings { switch self.mode { case .tab: @@ -381,7 +385,7 @@ final class CallListControllerNode: ASDisplayNode { self.updateEmptyPlaceholder(theme: theme, strings: strings, type: self.currentLocationAndType.type, hidden: self.emptyTextNode.isHidden) self.updateState { - return $0.withUpdatedPresentationData(theme: theme, strings: strings) + return $0.withUpdatedPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat) } } } diff --git a/TelegramUI/CallListNodeEntries.swift b/TelegramUI/CallListNodeEntries.swift index d95f59e93a..64bcb82fc2 100644 --- a/TelegramUI/CallListNodeEntries.swift +++ b/TelegramUI/CallListNodeEntries.swift @@ -55,7 +55,7 @@ private func areMessagesEqual(_ lhsMessage: Message, _ rhsMessage: Message) -> B enum CallListNodeEntry: Comparable, Identifiable { case displayTab(PresentationTheme, String, Bool) case displayTabInfo(PresentationTheme, String) - case messageEntry(topMessage: Message, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, editing: Bool, hasActiveRevealControls: Bool) + case messageEntry(topMessage: Message, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, editing: Bool, hasActiveRevealControls: Bool) case holeEntry(index: MessageIndex, theme: PresentationTheme) var index: MessageIndex { @@ -64,7 +64,7 @@ enum CallListNodeEntry: Comparable, Identifiable { return MessageIndex.absoluteUpperBound() case .displayTabInfo: return MessageIndex.absoluteUpperBound().predecessor() - case let .messageEntry(message, _, _, _, _, _): + case let .messageEntry(message, _, _, _, _, _, _): return MessageIndex(message) case let .holeEntry(index, _): return index @@ -77,7 +77,7 @@ enum CallListNodeEntry: Comparable, Identifiable { return .setting(0) case .displayTabInfo: return .setting(1) - case let .messageEntry(message, _, _, _, _, _): + case let .messageEntry(message, _, _, _, _, _, _): return .message(MessageIndex(message)) case let .holeEntry(index, _): return .hole(index) @@ -99,17 +99,17 @@ enum CallListNodeEntry: Comparable, Identifiable { switch rhs { case let .holeEntry(rhsIndex, _): return lhsIndex < rhsIndex - case let .messageEntry(topMessage, _, _, _, _, _): + case let .messageEntry(topMessage, _, _, _, _, _, _): return lhsIndex < MessageIndex(topMessage) default: return true } - case let .messageEntry(lhsTopMessage, _, _, _, _, _): + case let .messageEntry(lhsTopMessage, _, _, _, _, _, _): let lhsIndex = MessageIndex(lhsTopMessage) switch rhs { case let .holeEntry(rhsIndex, _): return lhsIndex < rhsIndex - case let .messageEntry(topMessage, _, _, _, _, _): + case let .messageEntry(topMessage, _, _, _, _, _, _): return lhsIndex < MessageIndex(topMessage) default: return true @@ -132,14 +132,17 @@ enum CallListNodeEntry: Comparable, Identifiable { } else { return false } - case let .messageEntry(lhsMessage, lhsMessages, lhsTheme, lhsStrings, lhsEditing, lhsHasRevealControls): - if case let .messageEntry(rhsMessage, rhsMessages, rhsTheme, rhsStrings, rhsEditing, rhsHasRevealControls) = rhs { + case let .messageEntry(lhsMessage, lhsMessages, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsEditing, lhsHasRevealControls): + if case let .messageEntry(rhsMessage, rhsMessages, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsEditing, rhsHasRevealControls) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsEditing != rhsEditing { return false } @@ -176,7 +179,7 @@ func callListNodeEntriesForView(_ view: CallListView, state: CallListNodeState, for entry in view.entries { switch entry { case let .message(topMessage, messages): - result.append(.messageEntry(topMessage: topMessage, messages: messages, theme: state.theme, strings: state.strings, editing: state.editing, hasActiveRevealControls: state.messageIdWithRevealedOptions == topMessage.id)) + result.append(.messageEntry(topMessage: topMessage, messages: messages, theme: state.theme, strings: state.strings, dateTimeFormat: state.dateTimeFormat, editing: state.editing, hasActiveRevealControls: state.messageIdWithRevealedOptions == topMessage.id)) case let .hole(index): result.append(.holeEntry(index: index, theme: state.theme)) } diff --git a/TelegramUI/ChannelAdminController.swift b/TelegramUI/ChannelAdminController.swift index 7457d44b13..ec77c065f4 100644 --- a/TelegramUI/ChannelAdminController.swift +++ b/TelegramUI/ChannelAdminController.swift @@ -81,7 +81,7 @@ private enum ChannelAdminEntryStableId: Hashable { } private enum ChannelAdminEntry: ItemListNodeEntry { - case info(PresentationTheme, PresentationStrings, Peer, TelegramUserPresence?) + case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, TelegramUserPresence?) case rightsTitle(PresentationTheme, String) case rightItem(PresentationTheme, Int, String, TelegramChannelAdminRightsFlags, TelegramChannelAdminRightsFlags, Bool, Bool) case addAdminsInfo(PresentationTheme, String) @@ -115,14 +115,17 @@ private enum ChannelAdminEntry: ItemListNodeEntry { static func ==(lhs: ChannelAdminEntry, rhs: ChannelAdminEntry) -> Bool { switch lhs { - case let .info(lhsTheme, lhsStrings, lhsPeer, lhsPresence): - if case let .info(rhsTheme, rhsStrings, rhsPeer, rhsPresence) = rhs { + case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsPresence): + if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsPresence) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !arePeersEqual(lhsPeer, rhsPeer) { return false } @@ -221,8 +224,8 @@ private enum ChannelAdminEntry: ItemListNodeEntry { func item(_ arguments: ChannelAdminControllerArguments) -> ListViewItem { switch self { - case let .info(theme, strings, peer, presence): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true), editingNameUpdated: { _ in + case let .info(theme, strings, dateTimeFormat, peer, presence): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true), editingNameUpdated: { _ in }, avatarTapped: { }) case let .rightsTitle(theme, text): @@ -344,7 +347,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s var entries: [ChannelAdminEntry] = [] if let channel = channelView.peers[channelView.peerId] as? TelegramChannel, let admin = adminView.peers[adminView.peerId] { - entries.append(.info(presentationData.theme, presentationData.strings, admin, adminView.peerPresences[admin.id] as? TelegramUserPresence)) + entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, admin, adminView.peerPresences[admin.id] as? TelegramUserPresence)) entries.append(.rightsTitle(presentationData.theme, presentationData.strings.Channel_EditAdmin_PermissionsHeader)) diff --git a/TelegramUI/ChannelAdminsController.swift b/TelegramUI/ChannelAdminsController.swift index df179f065f..c3d6020557 100644 --- a/TelegramUI/ChannelAdminsController.swift +++ b/TelegramUI/ChannelAdminsController.swift @@ -67,7 +67,7 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { case administrationInfo(PresentationTheme, String) case adminsHeader(PresentationTheme, String) - case adminPeerItem(PresentationTheme, PresentationStrings, Bool, Int32, RenderedChannelParticipant, ItemListPeerItemEditing, Bool) + case adminPeerItem(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Bool, Int32, RenderedChannelParticipant, ItemListPeerItemEditing, Bool) case addAdmin(PresentationTheme, String, Bool) case adminsInfo(PresentationTheme, String) @@ -94,7 +94,7 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { return .index(4) case .adminsInfo: return .index(5) - case let .adminPeerItem(_, _, _, _, participant, _, _): + case let .adminPeerItem(_, _, _, _, _, participant, _, _): return .peer(participant.peer.id) } } @@ -125,14 +125,17 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { } else { return false } - case let .adminPeerItem(lhsTheme, lhsStrings, lhsIsGroup, lhsIndex, lhsParticipant, lhsEditing, lhsEnabled): - if case let .adminPeerItem(rhsTheme, rhsStrings, rhsIsGroup, rhsIndex, rhsParticipant, rhsEditing, rhsEnabled) = rhs { + case let .adminPeerItem(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsIsGroup, lhsIndex, lhsParticipant, lhsEditing, lhsEnabled): + if case let .adminPeerItem(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsIsGroup, rhsIndex, rhsParticipant, rhsEditing, rhsEnabled) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsIsGroup != rhsIsGroup { return false } @@ -192,11 +195,11 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { default: return true } - case let .adminPeerItem(_, _, _, index, _, _, _): + case let .adminPeerItem(_, _, _, _, index, _, _, _): switch rhs { case .recentActions, .administrationType, .administrationInfo, .adminsHeader, .addAdmin: return false - case let .adminPeerItem(_, _, _, rhsIndex, _, _, _): + case let .adminPeerItem(_, _, _, _, rhsIndex, _, _, _): return index < rhsIndex default: return true @@ -227,7 +230,7 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) case let .adminsHeader(theme, title): return ItemListSectionHeaderItem(theme: theme, text: title, sectionId: self.section) - case let .adminPeerItem(theme, strings, isGroup, _, participant, editing, enabled): + case let .adminPeerItem(theme, strings, dateTimeFormat, isGroup, _, participant, editing, enabled): let peerText: String let action: (() -> Void)? switch participant.participant { @@ -248,7 +251,7 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { arguments.openAdmin(participant.participant) } } - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: participant.peer, presence: nil, text: .text(peerText), label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: action, setPeerIdWithRevealedOptions: { previousId, id in + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: participant.peer, presence: nil, text: .text(peerText), label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: action, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) }, removePeer: { peerId in arguments.removeAdmin(peerId) @@ -447,7 +450,7 @@ private func channelAdminsControllerEntries(presentationData: PresentationData, editable = false } } - entries.append(.adminPeerItem(presentationData.theme, presentationData.strings, isGroup, index, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), existingParticipantIds.contains(participant.peer.id))) + entries.append(.adminPeerItem(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, isGroup, index, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), existingParticipantIds.contains(participant.peer.id))) index += 1 } } diff --git a/TelegramUI/ChannelBannedMemberController.swift b/TelegramUI/ChannelBannedMemberController.swift index 73ceb477d6..dd7603dc9f 100644 --- a/TelegramUI/ChannelBannedMemberController.swift +++ b/TelegramUI/ChannelBannedMemberController.swift @@ -63,7 +63,7 @@ private enum ChannelBannedMemberEntryStableId: Hashable { } private enum ChannelBannedMemberEntry: ItemListNodeEntry { - case info(PresentationTheme, PresentationStrings, Peer, TelegramUserPresence?) + case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, TelegramUserPresence?) case rightItem(PresentationTheme, Int, String, TelegramChannelBannedRightsFlags, TelegramChannelBannedRightsFlags, Bool, Bool) case timeout(PresentationTheme, String, String) @@ -91,14 +91,17 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry { static func ==(lhs: ChannelBannedMemberEntry, rhs: ChannelBannedMemberEntry) -> Bool { switch lhs { - case let .info(lhsTheme, lhsStrings, lhsPeer, lhsPresence): - if case let .info(rhsTheme, rhsStrings, rhsPeer, rhsPresence) = rhs { + case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsPresence): + if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsPresence) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !arePeersEqual(lhsPeer, rhsPeer) { return false } @@ -171,8 +174,8 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry { func item(_ arguments: ChannelBannedMemberControllerArguments) -> ListViewItem { switch self { - case let .info(theme, strings, peer, presence): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true), editingNameUpdated: { _ in + case let .info(theme, strings, dateTimeFormat, peer, presence): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true), editingNameUpdated: { _ in }, avatarTapped: { }) case let .rightItem(theme, _, text, right, flags, value, enabled): @@ -303,7 +306,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation var entries: [ChannelBannedMemberEntry] = [] if let _ = channelView.peers[channelView.peerId] as? TelegramChannel, let member = memberView.peers[memberView.peerId] { - entries.append(.info(presentationData.theme, presentationData.strings, member, memberView.peerPresences[member.id] as? TelegramUserPresence)) + entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, member, memberView.peerPresences[member.id] as? TelegramUserPresence)) let currentRightsFlags: TelegramChannelBannedRightsFlags if let updatedFlags = state.updatedFlags { diff --git a/TelegramUI/ChannelBlacklistController.swift b/TelegramUI/ChannelBlacklistController.swift index 75f9c464a2..7bdb6af047 100644 --- a/TelegramUI/ChannelBlacklistController.swift +++ b/TelegramUI/ChannelBlacklistController.swift @@ -42,7 +42,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { case add(PresentationTheme, String) case restrictedHeader(PresentationTheme, String) case bannedHeader(PresentationTheme, String) - case peerItem(PresentationTheme, PresentationStrings, Int32, ChannelBlacklistPeerCategory, RenderedChannelParticipant, ItemListPeerItemEditing, Bool, Bool) + case peerItem(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Int32, ChannelBlacklistPeerCategory, RenderedChannelParticipant, ItemListPeerItemEditing, Bool, Bool) var section: ItemListSectionId { switch self { @@ -52,7 +52,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { return ChannelBlacklistSection.restricted.rawValue case .bannedHeader: return ChannelBlacklistSection.banned.rawValue - case let .peerItem(_, _, _, category, _, _, _, _): + case let .peerItem(_, _, _, _, category, _, _, _, _): switch category { case .restricted: return ChannelBlacklistSection.restricted.rawValue @@ -70,7 +70,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { return .index(1) case .bannedHeader: return .index(2) - case let .peerItem(_, _, _, _, participant, _, _, _): + case let .peerItem(_, _, _, _, _, participant, _, _, _): return .peer(participant.peer.id) } } @@ -95,14 +95,17 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { } else { return false } - case let .peerItem(lhsTheme, lhsStrings, lhsIndex, lhsCategory, lhsParticipant, lhsEditing, lhsEnabled, lhsCanOpen): - if case let .peerItem(rhsTheme, rhsStrings, rhsIndex, rhsCategory, rhsParticipant, rhsEditing, rhsEnabled, rhsCanOpen) = rhs { + case let .peerItem(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsIndex, lhsCategory, lhsParticipant, lhsEditing, lhsEnabled, lhsCanOpen): + if case let .peerItem(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsIndex, rhsCategory, rhsParticipant, rhsEditing, rhsEnabled, rhsCanOpen) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsIndex != rhsIndex { return false } @@ -148,7 +151,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { switch rhs { case .add, .restrictedHeader, .bannedHeader: return false - case let .peerItem(_, _, _, category, _, _, _, _): + case let .peerItem(_, _, _, _, category, _, _, _, _): switch category { case .restricted: return false @@ -156,7 +159,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { return true } } - case let .peerItem(_, _, index, category, _, _, _, _): + case let .peerItem(_, _, _, index, category, _, _, _, _): switch rhs { case .add, .restrictedHeader: return false @@ -167,7 +170,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { case .banned: return false } - case let .peerItem(_, _, rhsIndex, _, _, _, _, _): + case let .peerItem(_, _, _, rhsIndex, _, _, _, _, _): return index < rhsIndex } } @@ -183,7 +186,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) case let .bannedHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) - case let .peerItem(theme, strings, _, _, participant, editing, enabled, canOpen): + case let .peerItem(theme, strings, dateTimeFormat, _, _, participant, editing, enabled, canOpen): var text: ItemListPeerItemText = .none switch participant.participant { case let .member(_, _, _, banInfo): @@ -193,7 +196,7 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { default: break } - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: participant.peer, presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: canOpen ? { + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: participant.peer, presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: canOpen ? { arguments.openPeer(participant.participant) } : { arguments.openPeerInfo(participant.peer) @@ -282,7 +285,7 @@ private func channelBlacklistControllerEntries(presentationData: PresentationDat if case .creator = participant.participant { editable = false } - entries.append(.peerItem(presentationData.theme, presentationData.strings, index, .restricted, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != participant.peer.id, canOpen)) + entries.append(.peerItem(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, index, .restricted, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != participant.peer.id, canOpen)) index += 1 } if !blacklist.banned.isEmpty { @@ -293,7 +296,7 @@ private func channelBlacklistControllerEntries(presentationData: PresentationDat if case .creator = participant.participant { editable = false } - entries.append(.peerItem(presentationData.theme, presentationData.strings, index, .banned, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != participant.peer.id, canOpen)) + entries.append(.peerItem(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, index, .banned, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != participant.peer.id, canOpen)) index += 1 } } diff --git a/TelegramUI/ChannelInfoController.swift b/TelegramUI/ChannelInfoController.swift index a594a95d72..43fcd90619 100644 --- a/TelegramUI/ChannelInfoController.swift +++ b/TelegramUI/ChannelInfoController.swift @@ -65,7 +65,7 @@ private enum ChannelInfoEntryTag { } private enum ChannelInfoEntry: ItemListNodeEntry { - case info(PresentationTheme, PresentationStrings, peer: Peer?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) + case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) case about(theme: PresentationTheme, text: String, value: String) case addressName(theme: PresentationTheme, text: String, value: String) case channelPhotoSetup(theme: PresentationTheme, text: String) @@ -144,14 +144,17 @@ private enum ChannelInfoEntry: ItemListNodeEntry { static func ==(lhs: ChannelInfoEntry, rhs: ChannelInfoEntry) -> Bool { switch lhs { - case let .info(lhsTheme, lhsStrings, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar): - if case let .info(rhsTheme, rhsStrings, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs { + case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar): + if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -288,8 +291,8 @@ private enum ChannelInfoEntry: ItemListNodeEntry { func item(_ arguments: ChannelInfoControllerArguments) -> ListViewItem { switch self { - case let .info(theme, strings, peer, cachedData, state, updatingAvatar): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: nil, cachedData: cachedData, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in + case let .info(theme, strings, dateTimeFormat, peer, cachedData, state, updatingAvatar): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: nil, cachedData: cachedData, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { arguments.tapAvatarAction() @@ -438,7 +441,7 @@ private func channelInfoEntries(account: Account, presentationData: Presentation let canEditMembers = peer.hasAdminRights(.canBanUsers) let infoState = ItemListAvatarAndNameInfoItemState(editingName: canEditChannel ? state.editingState?.editingName : nil, updatingName: nil) - entries.append(.info(presentationData.theme, presentationData.strings, peer: peer, cachedData: view.cachedData, state: infoState, updatingAvatar: state.updatingAvatar)) + entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer, cachedData: view.cachedData, state: infoState, updatingAvatar: state.updatingAvatar)) if state.editingState != nil && canEditChannel { entries.append(.channelPhotoSetup(theme: presentationData.theme, text: presentationData.strings.Channel_UpdatePhotoItem)) diff --git a/TelegramUI/ChannelMembersController.swift b/TelegramUI/ChannelMembersController.swift index 57d286f5e2..04b9ba9df6 100644 --- a/TelegramUI/ChannelMembersController.swift +++ b/TelegramUI/ChannelMembersController.swift @@ -62,7 +62,7 @@ private enum ChannelMembersEntry: ItemListNodeEntry { case addMember(PresentationTheme, String) case addMemberInfo(PresentationTheme, String) case inviteLink(PresentationTheme, String) - case peerItem(Int32, PresentationTheme, PresentationStrings, RenderedChannelParticipant, ItemListPeerItemEditing, Bool) + case peerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, RenderedChannelParticipant, ItemListPeerItemEditing, Bool) var section: ItemListSectionId { switch self { @@ -81,7 +81,7 @@ private enum ChannelMembersEntry: ItemListNodeEntry { return .index(1) case .inviteLink: return .index(2) - case let .peerItem(_, _, _, participant, _, _): + case let .peerItem(_, _, _, _, participant, _, _): return .peer(participant.peer.id) } } @@ -106,8 +106,8 @@ private enum ChannelMembersEntry: ItemListNodeEntry { } else { return false } - case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsParticipant, lhsEditing, lhsEnabled): - if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsParticipant, rhsEditing, rhsEnabled) = rhs { + case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsParticipant, lhsEditing, lhsEnabled): + if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsParticipant, rhsEditing, rhsEnabled) = rhs { if lhsIndex != rhsIndex { return false } @@ -117,6 +117,9 @@ private enum ChannelMembersEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsParticipant != rhsParticipant { return false } @@ -152,9 +155,9 @@ private enum ChannelMembersEntry: ItemListNodeEntry { return true } - case let .peerItem(index, _, _, _, _, _): + case let .peerItem(index, _, _, _, _, _, _): switch rhs { - case let .peerItem(rhsIndex, _, _, _, _, _): + case let .peerItem(rhsIndex, _, _, _, _, _, _): return index < rhsIndex case .addMember, .addMemberInfo, .inviteLink: return false @@ -174,8 +177,8 @@ private enum ChannelMembersEntry: ItemListNodeEntry { }) case let .addMemberInfo(theme, text): return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) - case let .peerItem(_, theme, strings, participant, editing, enabled): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: participant.peer, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: { + case let .peerItem(_, theme, strings, dateTimeFormat, participant, editing, enabled): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: participant.peer, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: { arguments.openPeer(participant.peer) }, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) @@ -290,7 +293,7 @@ private func ChannelMembersControllerEntries(account: Account, presentationData: editable = canEditMembers } } - entries.append(.peerItem(index, presentationData.theme, presentationData.strings, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != participant.peer.id)) + entries.append(.peerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, participant, ItemListPeerItemEditing(editable: editable, editing: state.editing, revealed: participant.peer.id == state.peerIdWithRevealedOptions), state.removingPeerId != participant.peer.id)) index += 1 } } diff --git a/TelegramUI/ChannelVisibilityController.swift b/TelegramUI/ChannelVisibilityController.swift index c69d34ec75..20dae511dc 100644 --- a/TelegramUI/ChannelVisibilityController.swift +++ b/TelegramUI/ChannelVisibilityController.swift @@ -56,7 +56,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry { case publicLinkStatus(PresentationTheme, String, AddressNameValidationStatus) case existingLinksInfo(PresentationTheme, String) - case existingLinkPeerItem(Int32, PresentationTheme, PresentationStrings, Peer, ItemListPeerItemEditing, Bool) + case existingLinkPeerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, ItemListPeerItemEditing, Bool) var section: ItemListSectionId { switch self { @@ -102,7 +102,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry { return 12 case .existingLinksInfo: return 13 - case let .existingLinkPeerItem(index, _, _, _, _, _): + case let .existingLinkPeerItem(index, _, _, _, _, _, _): return 14 + index } } @@ -193,8 +193,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry { } else { return false } - case let .existingLinkPeerItem(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsEditing, lhsEnabled): - if case let .existingLinkPeerItem(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsEditing, rhsEnabled) = rhs { + case let .existingLinkPeerItem(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsEditing, lhsEnabled): + if case let .existingLinkPeerItem(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsEditing, rhsEnabled) = rhs { if lhsIndex != rhsIndex { return false } @@ -204,6 +204,9 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !lhsPeer.isEqual(rhsPeer) { return false } @@ -292,12 +295,12 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry { return ItemListActivityTextItem(displayActivity: displayActivity, theme: theme, text: NSAttributedString(string: text, textColor: color), sectionId: self.section) case let .existingLinksInfo(theme, text): return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) - case let .existingLinkPeerItem(_, theme, strings, peer, editing, enabled): + case let .existingLinkPeerItem(_, theme, strings, dateTimeFormat, peer, editing, enabled): var label = "" if let addressName = peer.addressName { label = "t.me/" + addressName } - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: nil, text: .text(label), label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { previousId, id in + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: nil, text: .text(label), label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) }, removePeer: { peerId in arguments.revokePeerId(peerId) @@ -476,7 +479,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa } return lhsDate > rhsDate }) { - entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil)) + entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil)) index += 1 } } else { diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index 9019b11b39..e7b9d49fe3 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -209,7 +209,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin self.presentationData = (account.applicationContext as! TelegramApplicationContext).currentPresentationData.with { $0 } self.automaticMediaDownloadSettings = (account.applicationContext as! TelegramApplicationContext).currentAutomaticMediaDownloadSettings.with { $0 } - self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, fontSize: self.presentationData.fontSize, accountPeerId: account.peerId, mode: mode, chatLocation: chatLocation) + self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, fontSize: self.presentationData.fontSize, accountPeerId: account.peerId, mode: mode, chatLocation: chatLocation) var enableMediaAccessoryPanel = false if case .standard = mode { @@ -940,7 +940,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin self.controllerInteraction = controllerInteraction - self.chatTitleView = ChatTitleView(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat) + self.chatTitleView = ChatTitleView(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat) self.navigationItem.titleView = self.chatTitleView self.chatTitleView?.pressed = { [weak self] in if let strongSelf = self { @@ -1370,6 +1370,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin var state = state state = state.updatedTheme(self.presentationData.theme) state = state.updatedStrings(self.presentationData.strings) + state = state.updatedDateTimeFormat(self.presentationData.dateTimeFormat) state = state.updatedChatWallpaper(self.presentationData.chatWallpaper) return state }) @@ -2261,7 +2262,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin banDescription = strongSelf.presentationInterfaceState.strings.Group_ErrorSendRestrictedStickers case .mediaRecording: if bannedRights.untilDate != 0 && bannedRights.untilDate != Int32.max { - banDescription = strongSelf.presentationInterfaceState.strings.Conversation_RestrictedMediaTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: strongSelf.presentationInterfaceState.strings, timeFormat: .regular)).0 + banDescription = strongSelf.presentationInterfaceState.strings.Conversation_RestrictedMediaTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: strongSelf.presentationInterfaceState.strings, dateTimeFormat: strongSelf.presentationInterfaceState.dateTimeFormat)).0 } else { banDescription = strongSelf.presentationInterfaceState.strings.Conversation_RestrictedMedia } @@ -3241,7 +3242,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin if editMediaOptions == nil, let bannedRights = (peer as? TelegramChannel)?.bannedRights, bannedRights.flags.contains(.banSendMedia) { let banDescription: String if bannedRights.untilDate != 0 && bannedRights.untilDate != Int32.max { - banDescription = strongSelf.presentationInterfaceState.strings.Conversation_RestrictedMediaTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: strongSelf.presentationInterfaceState.strings, timeFormat: .regular)).0 + banDescription = strongSelf.presentationInterfaceState.strings.Conversation_RestrictedMediaTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: strongSelf.presentationInterfaceState.strings, dateTimeFormat: strongSelf.presentationInterfaceState.dateTimeFormat)).0 } else { banDescription = strongSelf.presentationInterfaceState.strings.Conversation_RestrictedMedia } diff --git a/TelegramUI/ChatDocumentGalleryItem.swift b/TelegramUI/ChatDocumentGalleryItem.swift index 9aa0e56b7e..4ebd1c69ec 100644 --- a/TelegramUI/ChatDocumentGalleryItem.swift +++ b/TelegramUI/ChatDocumentGalleryItem.swift @@ -7,21 +7,19 @@ import TelegramCore class ChatDocumentGalleryItem: GalleryItem { let account: Account - let theme: PresentationTheme - let strings: PresentationStrings + let presentationData: PresentationData let message: Message let location: MessageHistoryEntryLocation? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, message: Message, location: MessageHistoryEntryLocation?) { + init(account: Account, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?) { self.account = account - self.theme = theme - self.strings = strings + self.presentationData = presentationData self.message = message self.location = location } func node() -> GalleryItemNode { - let node = ChatDocumentGalleryItemNode(account: self.account, theme: self.theme, strings: self.strings) + let node = ChatDocumentGalleryItemNode(account: self.account, presentationData: self.presentationData) for media in self.message.media { if let file = media as? TelegramMediaFile { @@ -36,7 +34,7 @@ class ChatDocumentGalleryItem: GalleryItem { } if let location = self.location { - node._title.set(.single("\(location.index + 1) of \(location.count)")) + node._title.set(.single("\(location.index + 1) \(self.presentationData.strings.Common_of) \(location.count)")) } node.setMessage(self.message) @@ -45,7 +43,7 @@ class ChatDocumentGalleryItem: GalleryItem { func updateNode(node: GalleryItemNode) { if let node = node as? ChatDocumentGalleryItemNode, let location = self.location { - node._title.set(.single("\(location.index + 1) of \(location.count)")) + node._title.set(.single("\(location.index + 1) \(self.presentationData.strings.Common_of) \(location.count)")) node.setMessage(self.message) } } @@ -105,7 +103,7 @@ class ChatDocumentGalleryItemNode: GalleryItemNode, WKNavigationDelegate { private let statusDisposable = MetaDisposable() private var status: MediaResourceStatus? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { if #available(iOSApplicationExtension 11.0, *) { let preferences = WKPreferences() preferences.javaScriptEnabled = false @@ -122,7 +120,7 @@ class ChatDocumentGalleryItemNode: GalleryItemNode, WKNavigationDelegate { webView.scalesPageToFit = true self.webView = webView } - self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, theme: theme, strings: strings) + self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, presentationData: presentationData) self.statusNodeContainer = HighlightableButtonNode() self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) diff --git a/TelegramUI/ChatExternalFileGalleryItem.swift b/TelegramUI/ChatExternalFileGalleryItem.swift index 13eba6da8c..795102a4e1 100644 --- a/TelegramUI/ChatExternalFileGalleryItem.swift +++ b/TelegramUI/ChatExternalFileGalleryItem.swift @@ -7,21 +7,19 @@ import TelegramCore class ChatExternalFileGalleryItem: GalleryItem { let account: Account - let theme: PresentationTheme - let strings: PresentationStrings + let presentationData: PresentationData let message: Message let location: MessageHistoryEntryLocation? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, message: Message, location: MessageHistoryEntryLocation?) { + init(account: Account, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?) { self.account = account - self.theme = theme - self.strings = strings + self.presentationData = presentationData self.message = message self.location = location } func node() -> GalleryItemNode { - let node = ChatExternalFileGalleryItemNode(account: self.account, theme: self.theme, strings: self.strings) + let node = ChatExternalFileGalleryItemNode(account: self.account, presentationData: self.presentationData) for media in self.message.media { if let file = media as? TelegramMediaFile { @@ -36,7 +34,7 @@ class ChatExternalFileGalleryItem: GalleryItem { } if let location = self.location { - node._title.set(.single("\(location.index + 1) of \(location.count)")) + node._title.set(.single("\(location.index + 1) \(self.presentationData.strings.Common_of) \(location.count)")) } node.setMessage(self.message) @@ -45,7 +43,7 @@ class ChatExternalFileGalleryItem: GalleryItem { func updateNode(node: GalleryItemNode) { if let node = node as? ChatExternalFileGalleryItemNode, let location = self.location { - node._title.set(.single("\(location.index + 1) of \(location.count)")) + node._title.set(.single("\(location.index + 1) \(self.presentationData.strings.Common_of) \(location.count)")) node.setMessage(self.message) } } @@ -79,7 +77,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode { private let statusDisposable = MetaDisposable() private var status: MediaResourceStatus? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { self.containerNode = ASDisplayNode() self.containerNode.backgroundColor = .white @@ -87,13 +85,13 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode { self.containerNode.addSubnode(self.fileNameNode) self.actionTitleNode = ImmediateTextNode() - self.actionTitleNode.attributedText = NSAttributedString(string: strings.Conversation_LinkDialogOpen, font: Font.regular(17.0), textColor: theme.list.itemAccentColor) + self.actionTitleNode.attributedText = NSAttributedString(string: presentationData.strings.Conversation_LinkDialogOpen, font: Font.regular(17.0), textColor: presentationData.theme.list.itemAccentColor) self.containerNode.addSubnode(self.actionTitleNode) self.actionButtonNode = HighlightableButtonNode() self.containerNode.addSubnode(self.actionButtonNode) - self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, theme: theme, strings: strings) + self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, presentationData: presentationData) self.statusNodeContainer = HighlightableButtonNode() self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) diff --git a/TelegramUI/ChatHistoryGridNode.swift b/TelegramUI/ChatHistoryGridNode.swift index 9b9f405ccb..2774823de3 100644 --- a/TelegramUI/ChatHistoryGridNode.swift +++ b/TelegramUI/ChatHistoryGridNode.swift @@ -254,7 +254,7 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode { self.chatPresentationDataPromise.set(account.telegramApplicationContext.presentationData |> map { presentationData in - return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.fontSize, strings: self.presentationData.strings, timeFormat: presentationData.timeFormat) + return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) }) self.floatingSections = true diff --git a/TelegramUI/ChatHistoryListNode.swift b/TelegramUI/ChatHistoryListNode.swift index 5b44bddcdb..f977b0bb35 100644 --- a/TelegramUI/ChatHistoryListNode.swift +++ b/TelegramUI/ChatHistoryListNode.swift @@ -150,7 +150,7 @@ private func mappedInsertEntries(account: Account, chatLocation: ChatLocation, a case .bubbles: item = ChatMessageItem(presentationData: presentationData, account: account, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin)) case let .list(search, _): - item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search) + item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search) } return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) case let .MessageGroupEntry(_, messages, presentationData): @@ -160,7 +160,7 @@ private func mappedInsertEntries(account: Account, chatLocation: ChatLocation, a item = ChatMessageItem(presentationData: presentationData, account: account, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages)) case let .list(search, _): assertionFailure() - item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: search) + item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: search) } return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) case let .HoleEntry(_, theme, strings): @@ -195,7 +195,7 @@ private func mappedUpdateEntries(account: Account, chatLocation: ChatLocation, a case .bubbles: item = ChatMessageItem(presentationData: presentationData, account: account, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin)) case let .list(search, _): - item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search) + item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search) } return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) case let .MessageGroupEntry(_, messages, presentationData): @@ -205,7 +205,7 @@ private func mappedUpdateEntries(account: Account, chatLocation: ChatLocation, a item = ChatMessageItem(presentationData: presentationData, account: account, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages)) case let .list(search, _): assertionFailure() - item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: search) + item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, account: account, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: search) } return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) case let .HoleEntry(_, theme, strings): @@ -357,7 +357,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { self.currentPresentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.currentPresentationData.theme, wallpaper: self.currentPresentationData.chatWallpaper), fontSize: self.currentPresentationData.fontSize, strings: self.currentPresentationData.strings, timeFormat: self.currentPresentationData.timeFormat)) + self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.currentPresentationData.theme, wallpaper: self.currentPresentationData.chatWallpaper), fontSize: self.currentPresentationData.fontSize, strings: self.currentPresentationData.strings, dateTimeFormat: self.currentPresentationData.dateTimeFormat)) super.init() @@ -684,7 +684,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { dateNode.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings) } } - strongSelf.chatPresentationDataPromise.set(.single(ChatPresentationData(theme: themeData, fontSize: presentationData.fontSize, strings: presentationData.strings, timeFormat: presentationData.timeFormat))) + strongSelf.chatPresentationDataPromise.set(.single(ChatPresentationData(theme: themeData, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat))) } } }) @@ -1146,7 +1146,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { case .bubbles: item = ChatMessageItem(presentationData: presentationData, account: self.account, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin)) case let .list(search, _): - item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, account: self.account, chatLocation: self.chatLocation, controllerInteraction: self.controllerInteraction, message: message, selection: selection, displayHeader: search) + item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, account: self.account, chatLocation: self.chatLocation, controllerInteraction: self.controllerInteraction, message: message, selection: selection, displayHeader: search) } let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil) self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) diff --git a/TelegramUI/ChatHistorySearchContainerNode.swift b/TelegramUI/ChatHistorySearchContainerNode.swift index c9ec89b1bd..e5f83bfacf 100644 --- a/TelegramUI/ChatHistorySearchContainerNode.swift +++ b/TelegramUI/ChatHistorySearchContainerNode.swift @@ -29,19 +29,19 @@ private enum ChatHistorySearchEntryStableId: Hashable { private enum ChatHistorySearchEntry: Comparable, Identifiable { - case message(Message, PresentationTheme, PresentationStrings) + case message(Message, PresentationTheme, PresentationStrings, PresentationDateTimeFormat) var stableId: ChatHistorySearchEntryStableId { switch self { - case let .message(message, _, _): + case let .message(message, _, _, _): return .messageId(message.id) } } static func ==(lhs: ChatHistorySearchEntry, rhs: ChatHistorySearchEntry) -> Bool { switch lhs { - case let .message(lhsMessage, lhsTheme, lhsStrings): - if case let .message(rhsMessage, rhsTheme, rhsStrings) = rhs { + case let .message(lhsMessage, lhsTheme, lhsStrings, lhsDateTimeFormat): + if case let .message(rhsMessage, rhsTheme, rhsStrings, rhsDateTimeFormat) = rhs { if lhsMessage.id != rhsMessage.id { return false } @@ -54,6 +54,9 @@ private enum ChatHistorySearchEntry: Comparable, Identifiable { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } return true } else { return false @@ -63,8 +66,8 @@ private enum ChatHistorySearchEntry: Comparable, Identifiable { static func <(lhs: ChatHistorySearchEntry, rhs: ChatHistorySearchEntry) -> Bool { switch lhs { - case let .message(lhsMessage, _, _): - if case let .message(rhsMessage, _, _) = rhs { + case let .message(lhsMessage, _, _, _): + if case let .message(rhsMessage, _, _, _) = rhs { return MessageIndex(lhsMessage) < MessageIndex(rhsMessage) } else { return false @@ -74,8 +77,8 @@ private enum ChatHistorySearchEntry: Comparable, Identifiable { func item(account: Account, peerId: PeerId, interaction: ChatControllerInteraction) -> ListViewItem { switch self { - case let .message(message, theme, strings): - return ListMessageItem(theme: theme, strings: strings, account: account, chatLocation: .peer(peerId), controllerInteraction: interaction, message: message, selection: .none, displayHeader: true) + case let .message(message, theme, strings, dateTimeFormat): + return ListMessageItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: account, chatLocation: .peer(peerId), controllerInteraction: interaction, message: message, selection: .none, displayHeader: true) } } } @@ -117,7 +120,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode { } private var presentationData: PresentationData - private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)> + private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationDateTimeFormat)> private var enqueuedTransitions: [(ChatHistorySearchContainerTransition, Bool)] = [] @@ -126,7 +129,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode { self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings)) + self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.dateTimeFormat)) self.dimNode = ASDisplayNode() self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5) @@ -160,7 +163,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode { return nil } else { return messages.map { message -> ChatHistorySearchEntry in - return .message(message, themeAndStrings.0, themeAndStrings.1) + return .message(message, themeAndStrings.0, themeAndStrings.1, themeAndStrings.2) } } } @@ -273,7 +276,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode { if let currentEntries = self.currentEntries { for entry in currentEntries { switch entry { - case let .message(message, _, _): + case let .message(message, _, _, _): if message.id == id { return message } diff --git a/TelegramUI/ChatImageGalleryItem.swift b/TelegramUI/ChatImageGalleryItem.swift index a2b3caf2d6..4a89b3b9e4 100644 --- a/TelegramUI/ChatImageGalleryItem.swift +++ b/TelegramUI/ChatImageGalleryItem.swift @@ -76,21 +76,19 @@ final class ChatMediaGalleryThumbnailItem: GalleryThumbnailItem { class ChatImageGalleryItem: GalleryItem { let account: Account - let theme: PresentationTheme - let strings: PresentationStrings + let presentationData: PresentationData let message: Message let location: MessageHistoryEntryLocation? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, message: Message, location: MessageHistoryEntryLocation?) { + init(account: Account, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?) { self.account = account - self.theme = theme - self.strings = strings + self.presentationData = presentationData self.message = message self.location = location } func node() -> GalleryItemNode { - let node = ChatImageGalleryItemNode(account: self.account, theme: self.theme, strings: self.strings) + let node = ChatImageGalleryItemNode(account: self.account, presentationData: self.presentationData) for media in self.message.media { if let image = media as? TelegramMediaImage { @@ -111,7 +109,7 @@ class ChatImageGalleryItem: GalleryItem { } if let location = self.location { - node._title.set(.single("\(location.index + 1) of \(location.count)")) + node._title.set(.single("\(location.index + 1) \(self.presentationData.strings.Common_of) \(location.count)")) } node.setMessage(self.message) @@ -121,7 +119,7 @@ class ChatImageGalleryItem: GalleryItem { func updateNode(node: GalleryItemNode) { if let node = node as? ChatImageGalleryItemNode, let location = self.location { - node._title.set(.single("\(location.index + 1) of \(location.count)")) + node._title.set(.single("\(location.index + 1) \(self.presentationData.strings.Common_of) \(location.count)")) node.setMessage(self.message) } @@ -164,11 +162,11 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { private let statusDisposable = MetaDisposable() private var status: MediaResourceStatus? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { self.account = account self.imageNode = TransformImageNode() - self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, theme: theme, strings: strings) + self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, presentationData: presentationData) self.statusNodeContainer = HighlightableButtonNode() self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) diff --git a/TelegramUI/ChatItemGalleryFooterContentNode.swift b/TelegramUI/ChatItemGalleryFooterContentNode.swift index 1169d0320f..c4dfdc01f4 100644 --- a/TelegramUI/ChatItemGalleryFooterContentNode.swift +++ b/TelegramUI/ChatItemGalleryFooterContentNode.swift @@ -68,6 +68,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { private let account: Account private var theme: PresentationTheme private var strings: PresentationStrings + private var dateTimeFormat: PresentationDateTimeFormat private let deleteButton: UIButton private let actionButton: UIButton @@ -125,10 +126,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { } } - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { self.account = account - self.theme = theme - self.strings = strings + self.theme = presentationData.theme + self.strings = presentationData.strings + self.dateTimeFormat = presentationData.dateTimeFormat self.deleteButton = UIButton() self.actionButton = UIButton() @@ -184,7 +186,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { func setup(origin: GalleryItemOriginData?, caption: String) { let titleText = origin?.title - let dateText = origin?.timestamp.flatMap { humanReadableStringForTimestamp(strings: self.strings, timeFormat: .regular, timestamp: $0) } + let dateText = origin?.timestamp.flatMap { humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: $0) } if self.currentMessageText != caption || self.currentAuthorNameText != titleText || self.currentDateText != dateText { self.currentMessageText = caption @@ -246,7 +248,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { authorNameText = peer.displayTitle } - let dateText = humanReadableStringForTimestamp(strings: self.strings, timeFormat: .regular, timestamp: message.timestamp) + let dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: message.timestamp) var messageText = "" var hasCaption = false @@ -515,9 +517,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { for m in messages[0].media { if let image = m as? TelegramMediaImage { subject = .image(image.representations) - } else if let webpage = m as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let _ = content.image { + } else if let webpage = m as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let image = content.image { + subject = .media(.webPage(webPage: WebpageReference(webpage), media: image)) preferredAction = .saveToCameraRoll } else if let file = m as? TelegramMediaFile { + subject = .media(.message(message: MessageReference(messages[0]), media: file)) if file.isAnimated { preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Preview_SaveGif, action: { [weak self] in if let strongSelf = self { diff --git a/TelegramUI/ChatListController.swift b/TelegramUI/ChatListController.swift index 56726e2914..9a9be487db 100644 --- a/TelegramUI/ChatListController.swift +++ b/TelegramUI/ChatListController.swift @@ -270,12 +270,12 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) if self.isNodeLoaded { - self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) + self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) } } override public func loadDisplayNode() { - self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) + self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) self.chatListDisplayNode.navigationBar = self.navigationBar diff --git a/TelegramUI/ChatListControllerNode.swift b/TelegramUI/ChatListControllerNode.swift index a185a9d504..20bbd75fc3 100644 --- a/TelegramUI/ChatListControllerNode.swift +++ b/TelegramUI/ChatListControllerNode.swift @@ -21,14 +21,14 @@ class ChatListControllerNode: ASDisplayNode { var requestOpenRecentPeerOptions: ((Peer) -> Void)? var requestOpenMessageFromSearch: ((Peer, MessageId) -> Void)? - var themeAndStrings: (PresentationTheme, PresentationStrings, timeFormat: PresentationTimeFormat) + var themeAndStrings: (PresentationTheme, PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) - init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { + init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.account = account self.groupId = groupId - self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder) + self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder) - self.themeAndStrings = (theme, strings, timeFormat) + self.themeAndStrings = (theme, strings, dateTimeFormat) super.init() @@ -61,11 +61,11 @@ class ChatListControllerNode: ASDisplayNode { } } - func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { - self.themeAndStrings = (theme, strings, timeFormat) + func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { + self.themeAndStrings = (theme, strings, dateTimeFormat) self.backgroundColor = theme.chatList.backgroundColor - self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder) + self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder) self.searchDisplayController?.updateThemeAndStrings(theme: theme, strings: strings) self.chatListEmptyNode?.updateThemeAndStrings(theme: theme, strings: strings) } diff --git a/TelegramUI/ChatListItem.swift b/TelegramUI/ChatListItem.swift index 8adb2d88f9..1850ed581a 100644 --- a/TelegramUI/ChatListItem.swift +++ b/TelegramUI/ChatListItem.swift @@ -563,7 +563,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { localtime_r(&t, &timeinfo) let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - let dateText = stringForRelativeTimestamp(strings: item.presentationData.strings, relativeTimestamp: item.index.messageIndex.timestamp, relativeTo: timestamp, timeFormat: item.presentationData.timeFormat) + let dateText = stringForRelativeTimestamp(strings: item.presentationData.strings, relativeTimestamp: item.index.messageIndex.timestamp, relativeTo: timestamp, dateTimeFormat: item.presentationData.dateTimeFormat) if isAd { dateAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_AdLabel, font: dateFont, textColor: theme.dateTextColor) diff --git a/TelegramUI/ChatListNode.swift b/TelegramUI/ChatListNode.swift index 5c96a35011..97c748c319 100644 --- a/TelegramUI/ChatListNode.swift +++ b/TelegramUI/ChatListNode.swift @@ -333,12 +333,12 @@ final class ChatListNode: ListView { var isEmptyUpdated: ((Bool) -> Void)? private var wasEmpty: Bool? - init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { + init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.account = account self.controlsHistoryPreload = controlsHistoryPreload self.mode = mode - self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil) + self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil) self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true) self.theme = theme @@ -768,8 +768,8 @@ final class ChatListNode: ListView { self.activityStatusesDisposable?.dispose() } - func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { - if theme !== self.currentState.presentationData.theme || strings !== self.currentState.presentationData.strings || timeFormat != self.currentState.presentationData.timeFormat { + func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { + if theme !== self.currentState.presentationData.theme || strings !== self.currentState.presentationData.strings || dateTimeFormat != self.currentState.presentationData.dateTimeFormat { self.theme = theme if self.keepTopItemOverscrollBackground != nil { @@ -777,7 +777,7 @@ final class ChatListNode: ListView { } self.updateState { - return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)) + return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)) } } } diff --git a/TelegramUI/ChatListPresentationData.swift b/TelegramUI/ChatListPresentationData.swift index 5978e5d2c9..812474f3bc 100644 --- a/TelegramUI/ChatListPresentationData.swift +++ b/TelegramUI/ChatListPresentationData.swift @@ -3,14 +3,14 @@ import Foundation final class ChatListPresentationData { let theme: PresentationTheme let strings: PresentationStrings - let timeFormat: PresentationTimeFormat + let dateTimeFormat: PresentationDateTimeFormat let nameSortOrder: PresentationPersonNameOrder let nameDisplayOrder: PresentationPersonNameOrder - init(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.theme = theme self.strings = strings - self.timeFormat = timeFormat + self.dateTimeFormat = dateTimeFormat self.nameSortOrder = nameSortOrder self.nameDisplayOrder = nameDisplayOrder } diff --git a/TelegramUI/ChatListSearchContainerNode.swift b/TelegramUI/ChatListSearchContainerNode.swift index 1cc7077688..ff7d72a821 100644 --- a/TelegramUI/ChatListSearchContainerNode.swift +++ b/TelegramUI/ChatListSearchContainerNode.swift @@ -38,7 +38,7 @@ private enum ChatListRecentEntryStableId: Hashable { private enum ChatListRecentEntry: Comparable, Identifiable { case topPeers([Peer], PresentationTheme, PresentationStrings) - case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool) + case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool) var stableId: ChatListRecentEntryStableId { switch self { @@ -507,7 +507,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { self.openMessage = openMessage self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)) + self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)) self.recentListNode = ListView() self.listNode = ListView() @@ -697,7 +697,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { } peerIds.insert(peer.id) - entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.timeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, state.peerIdWithRevealedOptions == peer.id)) + entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, state.peerIdWithRevealedOptions == peer.id)) index += 1 } } diff --git a/TelegramUI/ChatMessageAttachedContentNode.swift b/TelegramUI/ChatMessageAttachedContentNode.swift index 63d8cb8903..f65e626916 100644 --- a/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/TelegramUI/ChatMessageAttachedContentNode.swift @@ -305,7 +305,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { sentViaBot = true } - let dateText = stringForMessageTimestampStatus(message: message, timeFormat: presentationData.timeFormat, strings: presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: message, dateTimeFormat: presentationData.dateTimeFormat, strings: presentationData.strings) var webpageGalleryMediaCount: Int? for media in message.media { diff --git a/TelegramUI/ChatMessageBubbleItemNode.swift b/TelegramUI/ChatMessageBubbleItemNode.swift index 298fae4c5e..fa3f4c429f 100644 --- a/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/TelegramUI/ChatMessageBubbleItemNode.swift @@ -689,7 +689,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { sentViaBot = true } - let dateText = stringForMessageTimestampStatus(message: message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType if message.effectivelyIncoming(item.account.peerId) { diff --git a/TelegramUI/ChatMessageCallBubbleContentNode.swift b/TelegramUI/ChatMessageCallBubbleContentNode.swift index 70c84258e4..ab5a20000c 100644 --- a/TelegramUI/ChatMessageCallBubbleContentNode.swift +++ b/TelegramUI/ChatMessageCallBubbleContentNode.swift @@ -132,7 +132,7 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode { buttonImage = PresentationResourcesChat.chatBubbleOutgoingCallButtonImage(item.presentationData.theme.theme) } - let dateText = stringForMessageTimestampStatus(message: item.message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings) let statusText: String if let callDuration = callDuration, callDuration > 1 { diff --git a/TelegramUI/ChatMessageContactBubbleContentNode.swift b/TelegramUI/ChatMessageContactBubbleContentNode.swift index 2e0ec83d76..ceb1071bfa 100644 --- a/TelegramUI/ChatMessageContactBubbleContentNode.swift +++ b/TelegramUI/ChatMessageContactBubbleContentNode.swift @@ -151,7 +151,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { sentViaBot = true } - let dateText = stringForMessageTimestampStatus(message: item.message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { @@ -234,7 +234,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { customLetters = [String(firstName[.. NSObjectProtocol? { - if let (color, updateTimestamp, strings, timeFormat) = self.timeoutAndColors { + if let (color, updateTimestamp, strings, dateTimeFormat) = self.timeoutAndColors { let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let string = stringForRelativeLiveLocationTimestamp(strings: strings, relativeTimestamp: Int32(updateTimestamp), relativeTo: Int32(timestamp), timeFormat: timeFormat) + let string = stringForRelativeLiveLocationTimestamp(strings: strings, relativeTimestamp: Int32(updateTimestamp), relativeTo: Int32(timestamp), dateTimeFormat: dateTimeFormat) return ChatMessageLiveLocationTextNodeParams(color: color, string: string) } else { diff --git a/TelegramUI/ChatMessageMapBubbleContentNode.swift b/TelegramUI/ChatMessageMapBubbleContentNode.swift index c541141fea..62778f0e50 100644 --- a/TelegramUI/ChatMessageMapBubbleContentNode.swift +++ b/TelegramUI/ChatMessageMapBubbleContentNode.swift @@ -188,7 +188,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { } } - let dateText = stringForMessageTimestampStatus(message: item.message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { @@ -358,7 +358,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { } } - strongSelf.liveTextNode?.update(color: timerTextColor, timestamp: Double(updateTimestamp), strings: item.presentationData.strings, timeFormat: item.presentationData.timeFormat) + strongSelf.liveTextNode?.update(color: timerTextColor, timestamp: Double(updateTimestamp), strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat) let timeoutDeadline = item.message.timestamp + activeLiveBroadcastingTimeout if strongSelf.timeoutTimer?.1 != timeoutDeadline { diff --git a/TelegramUI/ChatMessageMediaBubbleContentNode.swift b/TelegramUI/ChatMessageMediaBubbleContentNode.swift index 3d2f8ea132..1217f5abef 100644 --- a/TelegramUI/ChatMessageMediaBubbleContentNode.swift +++ b/TelegramUI/ChatMessageMediaBubbleContentNode.swift @@ -119,7 +119,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { sentViaBot = true } - let dateText = stringForMessageTimestampStatus(message: item.message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { diff --git a/TelegramUI/ChatMessageStickerItemNode.swift b/TelegramUI/ChatMessageStickerItemNode.swift index 7577adb86c..2c23168158 100644 --- a/TelegramUI/ChatMessageStickerItemNode.swift +++ b/TelegramUI/ChatMessageStickerItemNode.swift @@ -212,7 +212,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { let sentViaBot = false let viewCount: Int? = nil - let dateText = stringForMessageTimestampStatus(message: item.message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings, format: .minimal) + let dateText = stringForMessageTimestampStatus(message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings, format: .minimal) let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.presentationData.theme, item.presentationData.strings, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude)) diff --git a/TelegramUI/ChatMessageTextBubbleContentNode.swift b/TelegramUI/ChatMessageTextBubbleContentNode.swift index df57d97920..9aee6d5f2a 100644 --- a/TelegramUI/ChatMessageTextBubbleContentNode.swift +++ b/TelegramUI/ChatMessageTextBubbleContentNode.swift @@ -87,7 +87,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { sentViaBot = true } - let dateText = stringForMessageTimestampStatus(message: item.message, timeFormat: item.presentationData.timeFormat, strings: item.presentationData.strings) + let dateText = stringForMessageTimestampStatus(message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { diff --git a/TelegramUI/ChatPresentationData.swift b/TelegramUI/ChatPresentationData.swift index c08c23c517..b6da832eb5 100644 --- a/TelegramUI/ChatPresentationData.swift +++ b/TelegramUI/ChatPresentationData.swift @@ -52,18 +52,18 @@ public final class ChatPresentationData { let theme: ChatPresentationThemeData let fontSize: PresentationFontSize let strings: PresentationStrings - let timeFormat: PresentationTimeFormat + let dateTimeFormat: PresentationDateTimeFormat let messageFont: UIFont let messageBoldFont: UIFont let messageItalicFont: UIFont let messageFixedFont: UIFont - init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) { self.theme = theme self.fontSize = fontSize self.strings = strings - self.timeFormat = timeFormat + self.dateTimeFormat = dateTimeFormat let baseFontSize = fontSize.baseDisplaySize self.messageFont = UIFont.systemFont(ofSize: baseFontSize) diff --git a/TelegramUI/ChatPresentationInterfaceState.swift b/TelegramUI/ChatPresentationInterfaceState.swift index 70279b2482..30b379740e 100644 --- a/TelegramUI/ChatPresentationInterfaceState.swift +++ b/TelegramUI/ChatPresentationInterfaceState.swift @@ -387,11 +387,12 @@ final class ChatPresentationInterfaceState: Equatable { let chatWallpaper: TelegramWallpaper let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let fontSize: PresentationFontSize let accountPeerId: PeerId let mode: ChatControllerPresentationMode - init(chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation) { + init(chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation) { self.interfaceState = ChatInterfaceState() self.inputTextPanelState = ChatTextInputPanelState() self.editMessageState = nil @@ -419,12 +420,13 @@ final class ChatPresentationInterfaceState: Equatable { self.chatWallpaper = chatWallpaper self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.fontSize = fontSize self.accountPeerId = accountPeerId self.mode = mode } - init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isContact: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, canReportPeer: Bool, callsAvailable: Bool, callsPrivate: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) { + init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isContact: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, canReportPeer: Bool, callsAvailable: Bool, callsPrivate: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) { self.interfaceState = interfaceState self.chatLocation = chatLocation self.renderedPeer = renderedPeer @@ -452,6 +454,7 @@ final class ChatPresentationInterfaceState: Equatable { self.chatWallpaper = chatWallpaper self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.fontSize = fontSize self.accountPeerId = accountPeerId self.mode = mode @@ -588,6 +591,10 @@ final class ChatPresentationInterfaceState: Equatable { return false } + if lhs.dateTimeFormat != rhs.dateTimeFormat { + return false + } + if lhs.fontSize != rhs.fontSize { return false } @@ -604,15 +611,15 @@ final class ChatPresentationInterfaceState: Equatable { } func updatedInterfaceState(_ f: (ChatInterfaceState) -> ChatInterfaceState) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPeer(_ f: (RenderedPeer?) -> RenderedPeer?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedIsContact(_ isContact: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedInputQueryResult(queryKind: ChatPresentationInputQueryKind, _ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState { @@ -623,99 +630,103 @@ final class ChatPresentationInterfaceState: Equatable { } else { inputQueryResults.removeValue(forKey: queryKind) } - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedInputTextPanelState(_ f: (ChatTextInputPanelState) -> ChatTextInputPanelState) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: f(self.inputTextPanelState), editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: f(self.inputTextPanelState), editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedEditMessageState(_ editMessageState: ChatEditInterfaceMessageState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedRecordedMediaPreview(_ recordedMediaPreview: ChatRecordedMediaPreview?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedInputMode(_ f: (ChatInputMode) -> ChatInputMode) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: f(self.inputMode), titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: f(self.inputMode), titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedTitlePanelContext(_ f: ([ChatTitlePanelContext]) -> [ChatTitlePanelContext]) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: f(self.titlePanelContexts), keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: f(self.titlePanelContexts), keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedKeyboardButtonsMessage(_ message: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: message, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: message, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPinnedMessage(_ pinnedMessage: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPeerIsBlocked(_ peerIsBlocked: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPeerIsMuted(_ peerIsMuted: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedCanReportPeer(_ canReportPeer: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedCallsAvailable(_ callsAvailable: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedCallsPrivate(_ callsPrivate: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedBotStartPayload(_ botStartPayload: String?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedChatHistoryState(_ chatHistoryState: ChatHistoryNodeHistoryState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedUrlPreview(_ urlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedEditingUrlPreview(_ editingUrlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedSearch(_ search: ChatSearchData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedSearchQuerySuggestionResult(_ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: f(self.searchQuerySuggestionResult), chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: f(self.searchQuerySuggestionResult), chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedMode(_ mode: ChatControllerPresentationMode) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: mode) } func updatedTheme(_ theme: PresentationTheme) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedStrings(_ strings: PresentationStrings) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + } + + func updatedDateTimeFormat(_ dateTimeFormat: PresentationDateTimeFormat) -> ChatPresentationInterfaceState { + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedChatWallpaper(_ chatWallpaper: TelegramWallpaper) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: chatWallpaper, theme: self.theme, strings: self.strings, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } } diff --git a/TelegramUI/ChatRecentActionsControllerNode.swift b/TelegramUI/ChatRecentActionsControllerNode.swift index 2d4d878e81..db680dbf4d 100644 --- a/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/TelegramUI/ChatRecentActionsControllerNode.swift @@ -97,7 +97,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.state = ChatRecentActionsControllerState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, fontSize: self.presentationData.fontSize) - self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.fontSize, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat)) + self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat)) self.context = ChannelAdminEventLogContext(postbox: self.account.postbox, network: self.account.network, peerId: self.peer.id) diff --git a/TelegramUI/ChatRecentActionsFilterController.swift b/TelegramUI/ChatRecentActionsFilterController.swift index a2017aefb6..5734e29376 100644 --- a/TelegramUI/ChatRecentActionsFilterController.swift +++ b/TelegramUI/ChatRecentActionsFilterController.swift @@ -64,7 +64,7 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { case adminsTitle(PresentationTheme, String) case allAdmins(PresentationTheme, String, Bool) - case adminPeerItem(PresentationTheme, PresentationStrings, Int32, RenderedChannelParticipant, Bool) + case adminPeerItem(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Int32, RenderedChannelParticipant, Bool) var section: ItemListSectionId { switch self { @@ -87,7 +87,7 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { return .index(200) case .allAdmins: return .index(201) - case let .adminPeerItem(_, _, _, participant, _): + case let .adminPeerItem(_, _, _, _, participant, _): return .peer(participant.peer.id) } } @@ -124,14 +124,17 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { } else { return false } - case let .adminPeerItem(lhsTheme, lhsStrings, lhsIndex, lhsParticipant, lhsChecked): - if case let .adminPeerItem(rhsTheme, rhsStrings, rhsIndex, rhsParticipant, rhsChecked) = rhs { + case let .adminPeerItem(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsIndex, lhsParticipant, lhsChecked): + if case let .adminPeerItem(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsIndex, rhsParticipant, rhsChecked) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsIndex != rhsIndex { return false } @@ -182,9 +185,9 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { default: return false } - case let .adminPeerItem(_, _, lhsIndex, _, _): + case let .adminPeerItem(_, _, _, lhsIndex, _, _): switch rhs { - case let .adminPeerItem(_, _, rhsIndex, _, _): + case let .adminPeerItem(_, _, _, rhsIndex, _, _): return lhsIndex < rhsIndex default: return false @@ -210,7 +213,7 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { return ItemListSwitchItem(theme: theme, title: text, value: value, enabled: true, sectionId: self.section, style: .blocks, updated: { _ in arguments.toggleAllAdmins() }) - case let .adminPeerItem(theme, strings, _, participant, checked): + case let .adminPeerItem(theme, strings, dateTimeFormat, _, participant, checked): let peerText: String switch participant.participant { case .creator: @@ -218,7 +221,7 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { case .member: peerText = strings.ChatAdmins_AdminLabel.capitalized } - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: participant.peer, presence: nil, text: .text(peerText), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: checked, style: .check), enabled: true, sectionId: self.section, action: { + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: participant.peer, presence: nil, text: .text(peerText), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: checked, style: .check), enabled: true, sectionId: self.section, action: { arguments.toggleAdmin(participant.peer.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) @@ -342,7 +345,7 @@ private func channelRecentActionsFilterControllerEntries(presentationData: Prese } else { adminSelected = true } - entries.append(.adminPeerItem(presentationData.theme, presentationData.strings, index, participant, adminSelected)) + entries.append(.adminPeerItem(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, index, participant, adminSelected)) index += 1 } } diff --git a/TelegramUI/ChatRestrictedInputPanelNode.swift b/TelegramUI/ChatRestrictedInputPanelNode.swift index 278e37e4eb..1766801cb4 100644 --- a/TelegramUI/ChatRestrictedInputPanelNode.swift +++ b/TelegramUI/ChatRestrictedInputPanelNode.swift @@ -27,7 +27,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode { if let renderedPeer = interfaceState.renderedPeer, let channel = renderedPeer.peer as? TelegramChannel, let bannedRights = channel.bannedRights { if bannedRights.untilDate != 0 && bannedRights.untilDate != Int32.max { - self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_RestrictedTextTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: interfaceState.strings, timeFormat: .regular)).0, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor) + self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_RestrictedTextTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: interfaceState.strings, dateTimeFormat: interfaceState.dateTimeFormat)).0, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor) } else { self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_RestrictedText, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor) } diff --git a/TelegramUI/ChatTitleView.swift b/TelegramUI/ChatTitleView.swift index 234d06a5ce..4790fd442b 100644 --- a/TelegramUI/ChatTitleView.swift +++ b/TelegramUI/ChatTitleView.swift @@ -78,7 +78,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { private var theme: PresentationTheme private var strings: PresentationStrings - private var timeFormat: PresentationTimeFormat + private var dateTimeFormat: PresentationDateTimeFormat private let contentContainer: ASDisplayNode private let titleNode: ASTextNode @@ -317,7 +317,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } else { userPresence = TelegramUserPresence(status: .none) } - let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, timeFormat: self.timeFormat, presence: userPresence, relativeTo: Int32(timestamp)) + let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, dateTimeFormat: self.dateTimeFormat, presence: userPresence, relativeTo: Int32(timestamp)) let attributedString = NSAttributedString(string: string, font: Font.regular(13.0), textColor: activity ? self.theme.rootController.navigationBar.accentTextColor : self.theme.rootController.navigationBar.secondaryTextColor) if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: attributedString) { self.infoNode.attributedText = attributedString @@ -404,11 +404,11 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) { self.account = account self.theme = theme self.strings = strings - self.timeFormat = timeFormat + self.dateTimeFormat = dateTimeFormat self.contentContainer = ASDisplayNode() diff --git a/TelegramUI/ContactListNode.swift b/TelegramUI/ContactListNode.swift index 69c5e65e7e..1be12d9011 100644 --- a/TelegramUI/ContactListNode.swift +++ b/TelegramUI/ContactListNode.swift @@ -118,7 +118,7 @@ enum ContactListPeer: Equatable { private enum ContactListNodeEntry: Comparable, Identifiable { case search(PresentationTheme, PresentationStrings) case option(Int, ContactListAdditionalOption, PresentationTheme, PresentationStrings) - case peer(Int, ContactListPeer, PeerPresence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool) + case peer(Int, ContactListPeer, PeerPresence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool) var stableId: ContactListNodeEntryId { switch self { @@ -144,7 +144,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { }) case let .option(_, option, theme, _): return ContactListActionItem(theme: theme, title: option.title, icon: option.icon, action: option.action) - case let .peer(_, peer, presence, header, selection, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, enabled): + case let .peer(_, peer, presence, header, selection, theme, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, enabled): let status: ContactsPeerItemStatus let itemPeer: ContactsPeerItemPeer switch peer { @@ -153,7 +153,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { status = .addressName("") } else { let presence = presence ?? TelegramUserPresence(status: .none) - status = .presence(presence, timeFormat) + status = .presence(presence, dateTimeFormat) } itemPeer = .peer(peer: peer, chatPeer: peer) case let .deviceContact(id, contact): @@ -297,7 +297,7 @@ private extension PeerIndexNameRepresentation { } } -private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer], presences: [PeerId: PeerPresence], presentation: ContactListPresentation, selectionState: ContactListNodeGroupSelectionState?, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, disabledPeerIds:Set) -> [ContactListNodeEntry] { +private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer], presences: [PeerId: PeerPresence], presentation: ContactListPresentation, selectionState: ContactListNodeGroupSelectionState?, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, disabledPeerIds:Set) -> [ContactListNodeEntry] { var entries: [ContactListNodeEntry] = [] var orderedPeers: [ContactListPeer] @@ -443,7 +443,7 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer] default: enabled = true } - entries.append(.peer(i, orderedPeers[i], presence, header, selection, theme, strings, timeFormat, sortOrder, displayOrder, enabled)) + entries.append(.peer(i, orderedPeers[i], presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, enabled)) } return entries } @@ -565,7 +565,7 @@ final class ContactListNode: ASDisplayNode { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder)> + private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder)> init(account: Account, presentation: ContactListPresentation, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil) { self.account = account @@ -576,7 +576,7 @@ final class ContactListNode: ASDisplayNode { self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.timeFormat, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder)) + self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.dateTimeFormat, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder)) super.init() @@ -679,7 +679,7 @@ final class ContactListNode: ASDisplayNode { peers.append(.deviceContact(stableId, contact)) } - let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: [:], presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds) + let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: [:], presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, dateTimeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds) let previous = previousEntries.swap(entries) return .single(preparedContactListNodeTransition(account: account, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, animated: false)) } @@ -719,7 +719,7 @@ final class ContactListNode: ASDisplayNode { } } - let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds) + let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, dateTimeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds) let previous = previousEntries.swap(entries) let animated: Bool if let previous = previous { @@ -752,7 +752,7 @@ final class ContactListNode: ASDisplayNode { if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings { strongSelf.backgroundColor = presentationData.theme.chatList.backgroundColor - strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.timeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder))) + strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder))) strongSelf.listNode.forEachAccessoryItemNode({ accessoryItemNode in if let accessoryItemNode = accessoryItemNode as? ContactsSectionHeaderAccessoryItemNode { diff --git a/TelegramUI/ContactsPeerItem.swift b/TelegramUI/ContactsPeerItem.swift index d09e72aab1..293eff2197 100644 --- a/TelegramUI/ContactsPeerItem.swift +++ b/TelegramUI/ContactsPeerItem.swift @@ -13,7 +13,7 @@ private let badgeFont = Font.regular(14.0) enum ContactsPeerItemStatus { case none - case presence(PeerPresence, PresentationTimeFormat) + case presence(PeerPresence, PresentationDateTimeFormat) case addressName(String) case custom(String) } @@ -467,11 +467,11 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { switch item.status { case .none: break - case let .presence(presence, timeFormat): + case let .presence(presence, dateTimeFormat): let presence = (presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none) userPresence = presence let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: timeFormat, presence: presence, relativeTo: Int32(timestamp)) + let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, dateTimeFormat: dateTimeFormat, presence: presence, relativeTo: Int32(timestamp)) statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.theme.list.itemAccentColor : item.theme.list.itemSecondaryTextColor) case let .addressName(suffix): if let addressName = peer.addressName { diff --git a/TelegramUI/CreateChannelController.swift b/TelegramUI/CreateChannelController.swift index 84c820f792..7026163360 100644 --- a/TelegramUI/CreateChannelController.swift +++ b/TelegramUI/CreateChannelController.swift @@ -40,7 +40,7 @@ private enum CreateChannelEntryTag: ItemListItemTag { } private enum CreateChannelEntry: ItemListNodeEntry { - case channelInfo(PresentationTheme, PresentationStrings, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) + case channelInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) case setProfilePhoto(PresentationTheme, String) case descriptionSetup(PresentationTheme, String, String) @@ -70,14 +70,17 @@ private enum CreateChannelEntry: ItemListNodeEntry { static func ==(lhs: CreateChannelEntry, rhs: CreateChannelEntry) -> Bool { switch lhs { - case let .channelInfo(lhsTheme, lhsStrings, lhsPeer, lhsEditingState, lhsAvatar): - if case let .channelInfo(rhsTheme, rhsStrings, rhsPeer, rhsEditingState, rhsAvatar) = rhs { + case let .channelInfo(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsEditingState, lhsAvatar): + if case let .channelInfo(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsEditingState, rhsAvatar) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -122,8 +125,8 @@ private enum CreateChannelEntry: ItemListNodeEntry { func item(_ arguments: CreateChannelArguments) -> ListViewItem { switch self { - case let .channelInfo(theme, strings, peer, state, avatar): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: nil, cachedData: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { editingName in + case let .channelInfo(theme, strings, dateTimeFormat, peer, state, avatar): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: nil, cachedData: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { }, updatingImage: avatar, tag: CreateChannelEntryTag.info) @@ -173,7 +176,7 @@ private func CreateChannelEntries(presentationData: PresentationData, state: Cre let peer = TelegramGroup(id: PeerId(namespace: -1, id: 0), title: state.editingName.composedTitle, photo: [], participantCount: 0, role: .creator, membership: .Member, flags: [], migrationReference: nil, creationDate: 0, version: 0) - entries.append(.channelInfo(presentationData.theme, presentationData.strings, peer, groupInfoState, state.avatar)) + entries.append(.channelInfo(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, groupInfoState, state.avatar)) entries.append(.setProfilePhoto(presentationData.theme, presentationData.strings.Channel_UpdatePhotoItem)) entries.append(.descriptionSetup(presentationData.theme, presentationData.strings.Channel_Edit_AboutItem, state.editingDescriptionText)) diff --git a/TelegramUI/CreateGroupController.swift b/TelegramUI/CreateGroupController.swift index 8199ec0230..90468943cc 100644 --- a/TelegramUI/CreateGroupController.swift +++ b/TelegramUI/CreateGroupController.swift @@ -39,10 +39,10 @@ private enum CreateGroupEntryTag: ItemListItemTag { } private enum CreateGroupEntry: ItemListNodeEntry { - case groupInfo(PresentationTheme, PresentationStrings, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) + case groupInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) case setProfilePhoto(PresentationTheme, String) - case member(Int32, PresentationTheme, PresentationStrings, Peer, PeerPresence?) + case member(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, PeerPresence?) var section: ItemListSectionId { switch self { @@ -59,21 +59,24 @@ private enum CreateGroupEntry: ItemListNodeEntry { return 0 case .setProfilePhoto: return 1 - case let .member(index, _, _, _, _): + case let .member(index, _, _, _, _, _): return 2 + index } } static func ==(lhs: CreateGroupEntry, rhs: CreateGroupEntry) -> Bool { switch lhs { - case let .groupInfo(lhsTheme, lhsStrings, lhsPeer, lhsEditingState, lhsAvatar): - if case let .groupInfo(rhsTheme, rhsStrings, rhsPeer, rhsEditingState, rhsAvatar) = rhs { + case let .groupInfo(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsEditingState, lhsAvatar): + if case let .groupInfo(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsEditingState, rhsAvatar) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -97,8 +100,8 @@ private enum CreateGroupEntry: ItemListNodeEntry { } else { return false } - case let .member(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsPresence): - if case let .member(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsPresence) = rhs { + case let .member(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsPresence): + if case let .member(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsPresence) = rhs { if lhsIndex != rhsIndex { return false } @@ -108,6 +111,9 @@ private enum CreateGroupEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !lhsPeer.isEqual(rhsPeer) { return false } @@ -131,8 +137,8 @@ private enum CreateGroupEntry: ItemListNodeEntry { func item(_ arguments: CreateGroupArguments) -> ListViewItem { switch self { - case let .groupInfo(theme, strings, peer, state, avatar): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: nil, cachedData: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { editingName in + case let .groupInfo(theme, strings, dateTimeFormat, peer, state, avatar): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: nil, cachedData: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { }, updatingImage: avatar, tag: CreateGroupEntryTag.info) @@ -140,8 +146,8 @@ private enum CreateGroupEntry: ItemListNodeEntry { return ItemListActionItem(theme: theme, title: text, kind: .generic, alignment: .natural, sectionId: ItemListSectionId(self.section), style: .blocks, action: { arguments.changeProfilePhoto() }) - case let .member(_, theme, strings, peer, presence): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: presence, text: .presence, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) + case let .member(_, theme, strings, dateTimeFormat, peer, presence): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: presence, text: .presence, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) } } } @@ -173,7 +179,7 @@ private func createGroupEntries(presentationData: PresentationData, state: Creat let peer = TelegramGroup(id: PeerId(namespace: -1, id: 0), title: state.editingName.composedTitle, photo: [], participantCount: 0, role: .creator, membership: .Member, flags: [], migrationReference: nil, creationDate: 0, version: 0) - entries.append(.groupInfo(presentationData.theme, presentationData.strings, peer, groupInfoState, state.avatar)) + entries.append(.groupInfo(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, groupInfoState, state.avatar)) entries.append(.setProfilePhoto(presentationData.theme, presentationData.strings.GroupInfo_SetGroupPhoto)) var peers: [Peer] = [] @@ -204,7 +210,7 @@ private func createGroupEntries(presentationData: PresentationData, state: Creat }) for i in 0 ..< peers.count { - entries.append(.member(Int32(i), presentationData.theme, presentationData.strings, peers[i], view.presences[peers[i].id])) + entries.append(.member(Int32(i), presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peers[i], view.presences[peers[i].id])) } return entries diff --git a/TelegramUI/DateFormat.swift b/TelegramUI/DateFormat.swift index 0d0a875c80..3e033661e2 100644 --- a/TelegramUI/DateFormat.swift +++ b/TelegramUI/DateFormat.swift @@ -1,7 +1,7 @@ import Foundation -func stringForShortTimestamp(hours: Int32, minutes: Int32, timeFormat: PresentationTimeFormat) -> String { - switch timeFormat { +func stringForShortTimestamp(hours: Int32, minutes: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String { + switch dateTimeFormat.timeFormat { case .regular: let hourString: String if hours == 0 { @@ -28,7 +28,7 @@ func stringForShortTimestamp(hours: Int32, minutes: Int32, timeFormat: Presentat } } -func stringForMessageTimestamp(timestamp: Int32, timeFormat: PresentationTimeFormat, local: Bool = true) -> String { +func stringForMessageTimestamp(timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat, local: Bool = true) -> String { var t = Int(timestamp) var timeinfo = tm() if local { @@ -37,39 +37,39 @@ func stringForMessageTimestamp(timestamp: Int32, timeFormat: PresentationTimeFor gmtime_r(&t, &timeinfo) } - return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, timeFormat: timeFormat) + return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat) } -func stringForFullDate(timestamp: Int32, strings: PresentationStrings, timeFormat: PresentationTimeFormat) -> String { +func stringForFullDate(timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> String { var t: time_t = Int(timestamp) var timeinfo = tm() localtime_r(&t, &timeinfo); switch timeinfo.tm_mon + 1 { case 1: - return strings.Time_PreciseDate_m1("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m1("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 2: - return strings.Time_PreciseDate_m2("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m2("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 3: - return strings.Time_PreciseDate_m3("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m3("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 4: - return strings.Time_PreciseDate_m4("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m4("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 5: - return strings.Time_PreciseDate_m5("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m5("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 6: - return strings.Time_PreciseDate_m6("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m6("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 7: - return strings.Time_PreciseDate_m7("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m7("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 8: - return strings.Time_PreciseDate_m8("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m8("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 9: - return strings.Time_PreciseDate_m9("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m9("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 10: - return strings.Time_PreciseDate_m10("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m10("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 11: - return strings.Time_PreciseDate_m11("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m11("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 case 12: - return strings.Time_PreciseDate_m12("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), timeFormat: timeFormat)).0 + return strings.Time_PreciseDate_m12("\(timeinfo.tm_mday)", "\(2000 + timeinfo.tm_year - 100)", stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)).0 default: return "" } diff --git a/TelegramUI/DeviceContactInfoController.swift b/TelegramUI/DeviceContactInfoController.swift index 62ac4e382c..cccd3c1ac9 100644 --- a/TelegramUI/DeviceContactInfoController.swift +++ b/TelegramUI/DeviceContactInfoController.swift @@ -94,7 +94,7 @@ private enum DeviceContactInfoEntryId: Hashable { } private enum DeviceContactInfoEntry: ItemListNodeEntry { - case info(Int, PresentationTheme, PresentationStrings, peer: Peer, state: ItemListAvatarAndNameInfoItemState, job: String?) + case info(Int, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer, state: ItemListAvatarAndNameInfoItemState, job: String?) case invite(Int, PresentationTheme, String) case sendMessage(Int, PresentationTheme, String) @@ -162,8 +162,8 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { static func ==(lhs: DeviceContactInfoEntry, rhs: DeviceContactInfoEntry) -> Bool { switch lhs { - case let .info(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsState, lhsJobSummary): - if case let .info(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsState, rhsJobSummary) = rhs { + case let .info(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsState, lhsJobSummary): + if case let .info(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsState, rhsJobSummary) = rhs { if lhsIndex != rhsIndex { return false } @@ -173,6 +173,9 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !arePeersEqual(lhsPeer, rhsPeer) { return false } @@ -275,7 +278,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { private var sortIndex: Int { switch self { - case let .info(index, _, _, _, _, _): + case let .info(index, _, _, _, _, _, _): return index case let .sendMessage(index, _, _): return index @@ -314,8 +317,8 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { func item(_ arguments: DeviceContactInfoControllerArguments) -> ListViewItem { switch self { - case let .info(_, theme, strings, peer, state, jobSummary): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .contact, peer: peer, presence: nil, label: jobSummary, cachedData: nil, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in + case let .info(_, theme, strings, dateTimeFormat, peer, state, jobSummary): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .contact, peer: peer, presence: nil, label: jobSummary, cachedData: nil, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { }, context: nil, call: nil) @@ -557,7 +560,7 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen let isOrganization = personName.0.isEmpty && personName.1.isEmpty && !contactData.organization.isEmpty - entries.append(.info(entries.count, presentationData.theme, presentationData.strings, peer: peer ?? TelegramUser(id: PeerId(namespace: -1, id: 0), accessHash: nil, firstName: isOrganization ? contactData.organization : personName.0, lastName: isOrganization ? nil : personName.1, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), job: isOrganization ? nil : jobSummary)) + entries.append(.info(entries.count, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer ?? TelegramUser(id: PeerId(namespace: -1, id: 0), accessHash: nil, firstName: isOrganization ? contactData.organization : personName.0, lastName: isOrganization ? nil : personName.1, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), job: isOrganization ? nil : jobSummary)) if !selecting { if let _ = peer { diff --git a/TelegramUI/DisabledContextResultsChatInputContextPanelNode.swift b/TelegramUI/DisabledContextResultsChatInputContextPanelNode.swift index a84162022d..98fe5e2721 100644 --- a/TelegramUI/DisabledContextResultsChatInputContextPanelNode.swift +++ b/TelegramUI/DisabledContextResultsChatInputContextPanelNode.swift @@ -40,7 +40,7 @@ final class DisabledContextResultsChatInputContextPanelNode: ChatInputContextPan } let banDescription: String if bannedRights.untilDate != 0 && bannedRights.untilDate != Int32.max { - banDescription = interfaceState.strings.Conversation_RestrictedInlineTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: interfaceState.strings, timeFormat: .regular)).0 + banDescription = interfaceState.strings.Conversation_RestrictedInlineTimed(stringForFullDate(timestamp: bannedRights.untilDate, strings: interfaceState.strings, dateTimeFormat: interfaceState.dateTimeFormat)).0 } else { banDescription = interfaceState.strings.Conversation_RestrictedInline } diff --git a/TelegramUI/EditSettingsController.swift b/TelegramUI/EditSettingsController.swift index 35717ec818..d84f526097 100644 --- a/TelegramUI/EditSettingsController.swift +++ b/TelegramUI/EditSettingsController.swift @@ -28,7 +28,7 @@ private enum SettingsSection: Int32 { } private enum SettingsEntry: ItemListNodeEntry { - case userInfo(PresentationTheme, PresentationStrings, Peer?, CachedPeerData?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) + case userInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, CachedPeerData?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) case userInfoNotice(PresentationTheme, String) case bioText(PresentationTheme, String, String) @@ -73,14 +73,17 @@ private enum SettingsEntry: ItemListNodeEntry { static func ==(lhs: SettingsEntry, rhs: SettingsEntry) -> Bool { switch lhs { - case let .userInfo(lhsTheme, lhsStrings, lhsPeer, lhsCachedData, lhsEditingState, lhsUpdatingImage): - if case let .userInfo(rhsTheme, rhsStrings, rhsPeer, rhsCachedData, rhsEditingState, rhsUpdatingImage) = rhs { + case let .userInfo(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsEditingState, lhsUpdatingImage): + if case let .userInfo(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsEditingState, rhsUpdatingImage) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -150,8 +153,8 @@ private enum SettingsEntry: ItemListNodeEntry { func item(_ arguments: EditSettingsItemArguments) -> ListViewItem { switch self { - case let .userInfo(theme, strings, peer, cachedData, state, updatingImage): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .editSettings, peer: peer, presence: TelegramUserPresence(status: .present(until: Int32.max)), cachedData: cachedData, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { editingName in + case let .userInfo(theme, strings, dateTimeFormat, peer, cachedData, state, updatingImage): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .editSettings, peer: peer, presence: TelegramUserPresence(status: .present(until: Int32.max)), cachedData: cachedData, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { arguments.avatarTapAction() @@ -242,7 +245,7 @@ private func editSettingsEntries(presentationData: PresentationData, state: Edit if let peer = peerViewMainPeer(view) as? TelegramUser { let userInfoState = ItemListAvatarAndNameInfoItemState(editingName: state.editingName, updatingName: state.updatingName) - entries.append(.userInfo(presentationData.theme, presentationData.strings, peer, view.cachedData, userInfoState, state.updatingAvatar)) + entries.append(.userInfo(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, view.cachedData, userInfoState, state.updatingAvatar)) entries.append(.userInfoNotice(presentationData.theme, presentationData.strings.Login_InfoHelp)) entries.append(.bioText(presentationData.theme, state.editingBioText, presentationData.strings.UserInfo_About_Placeholder)) diff --git a/TelegramUI/FeedGroupingControllerNode.swift b/TelegramUI/FeedGroupingControllerNode.swift index 7a5b308cf4..9ed6b46406 100644 --- a/TelegramUI/FeedGroupingControllerNode.swift +++ b/TelegramUI/FeedGroupingControllerNode.swift @@ -80,7 +80,7 @@ private enum FeedGroupingSection: ItemListSectionId { private enum FeedGroupingEntry: ItemListNodeEntry { case groupHeader(PresentationTheme, String) - case peer(PresentationTheme, PresentationStrings, Int, Peer, Bool) + case peer(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Int, Peer, Bool) case ungroup(PresentationTheme, String) var section: ItemListSectionId { @@ -96,7 +96,7 @@ private enum FeedGroupingEntry: ItemListNodeEntry { switch self { case .groupHeader: return .index(0) - case let .peer(_, _, _, peer, _): + case let .peer(_, _, _, _, peer, _): return .peer(peer.id) case .ungroup: return .index(1) @@ -111,14 +111,17 @@ private enum FeedGroupingEntry: ItemListNodeEntry { } else { return false } - case let .peer(lhsTheme, lhsStrings, lhsIndex, lhsPeer, lhsValue): - if case let .peer(rhsTheme, rhsStrings, rhsIndex, rhsPeer, rhsValue) = rhs { + case let .peer(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsIndex, lhsPeer, lhsValue): + if case let .peer(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsIndex, rhsPeer, rhsValue) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsIndex != rhsIndex { return false } @@ -145,11 +148,11 @@ private enum FeedGroupingEntry: ItemListNodeEntry { switch lhs { case .groupHeader: return true - case let .peer(_, _, index, _, _): + case let .peer(_, _, _, index, _, _): switch rhs { case .groupHeader: return false - case let .peer(_, _, rhsIndex, _, _): + case let .peer(_, _, _, rhsIndex, _, _): return index < rhsIndex default: return true @@ -163,8 +166,8 @@ private enum FeedGroupingEntry: ItemListNodeEntry { switch self { case let .groupHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) - case let .peer(theme, strings, _, peer, value): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: value, style: .standard), enabled: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: { value in + case let .peer(theme, strings, dateTimeFormat, _, peer, value): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: value, style: .standard), enabled: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: { value in arguments.togglePeer(peer, value) }) case let .ungroup(theme, text): @@ -196,16 +199,18 @@ private final class FeedGroupingEntriesState { private final class FeedGroupingState { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let peers: [FeedGroupingPeerState] - init(theme: PresentationTheme, strings: PresentationStrings, peers: [FeedGroupingPeerState]) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, peers: [FeedGroupingPeerState]) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.peers = peers } func withUpdatedPeers(_ peers: [FeedGroupingPeerState]) -> FeedGroupingState { - return FeedGroupingState(theme: self.theme, strings: self.strings, peers: peers) + return FeedGroupingState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, peers: peers) } } @@ -215,7 +220,7 @@ private func entriesStateFromState(_ state: FeedGroupingState) -> FeedGroupingEn entries.append(.groupHeader(state.theme, "GROUP CHANNELS")) var index = 0 for peer in state.peers { - entries.append(.peer(state.theme, state.strings, index, peer.peer, peer.included)) + entries.append(.peer(state.theme, state.strings, state.dateTimeFormat, index, peer.peer, peer.included)) index += 1 } entries.append(.ungroup(state.theme, "Ungroup All Channels")) @@ -279,7 +284,7 @@ final class FeedGroupingControllerNode: ViewControllerTracingNode { self.blockingOverlay = ASDisplayNode() self.blockingOverlay.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor - self._stateValue = FeedGroupingState(theme: self.presentationData.theme, strings: self.presentationData.strings, peers: []) + self._stateValue = FeedGroupingState(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, peers: []) self.statePromise.set(.single(self._stateValue)) super.init() diff --git a/TelegramUI/FormBlockItemNode.swift b/TelegramUI/FormBlockItemNode.swift index 32116fa464..053621d035 100644 --- a/TelegramUI/FormBlockItemNode.swift +++ b/TelegramUI/FormBlockItemNode.swift @@ -59,8 +59,8 @@ class FormBlockItemNode: ASDisplayNode, FormController } } - final func updateInternal(item: Item, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { - let (preLayout, apply) = self.update(item: item, theme: theme, strings: strings, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) + final func updateInternal(item: Item, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + let (preLayout, apply) = self.update(item: item, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) return (preLayout, { params in self.backgroundNode.backgroundColor = theme.list.itemBlocksBackgroundColor self.topSeparatorNode.backgroundColor = theme.list.itemBlocksSeparatorColor @@ -99,7 +99,7 @@ class FormBlockItemNode: ASDisplayNode, FormController }) } - func update(item: Item, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(item: Item, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { preconditionFailure() } diff --git a/TelegramUI/FormController.swift b/TelegramUI/FormController.swift index 59f8750b53..b758934d2b 100644 --- a/TelegramUI/FormController.swift +++ b/TelegramUI/FormController.swift @@ -45,7 +45,7 @@ class FormController (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { guard let node = node as? FormControllerActionItemNode else { assertionFailure() return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in return 0.0 }) } - return node.updateInternal(item: self, theme: theme, strings: strings, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) + return node.updateInternal(item: self, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) } } @@ -53,7 +53,7 @@ final class FormControllerActionItemNode: FormBlockItemNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + override func update(item: FormControllerActionItem, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { self.item = item let leftInset: CGFloat = 16.0 diff --git a/TelegramUI/FormControllerDetailActionItem.swift b/TelegramUI/FormControllerDetailActionItem.swift index 246fa6c7ac..246eeb4a5f 100644 --- a/TelegramUI/FormControllerDetailActionItem.swift +++ b/TelegramUI/FormControllerDetailActionItem.swift @@ -24,14 +24,14 @@ final class FormControllerDetailActionItem: FormControllerItem { return FormControllerDetailActionItemNode() } - func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { guard let node = node as? FormControllerDetailActionItemNode else { assertionFailure() return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in return 0.0 }) } - return node.updateInternal(item: self, theme: theme, strings: strings, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) + return node.updateInternal(item: self, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) } } @@ -62,7 +62,7 @@ final class FormControllerDetailActionItemNode: FormBlockItemNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + override func update(item: FormControllerDetailActionItem, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { self.item = item let leftInset: CGFloat = 16.0 diff --git a/TelegramUI/FormControllerHeaderItem.swift b/TelegramUI/FormControllerHeaderItem.swift index 12f1ccbdbb..c14125d5f5 100644 --- a/TelegramUI/FormControllerHeaderItem.swift +++ b/TelegramUI/FormControllerHeaderItem.swift @@ -15,7 +15,7 @@ final class FormControllerHeaderItem: FormControllerItem { return FormControllerHeaderItemNode() } - func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in guard let node = node as? FormControllerHeaderItemNode else { assertionFailure() diff --git a/TelegramUI/FormControllerItem.swift b/TelegramUI/FormControllerItem.swift index ba1b2df311..9c658319bf 100644 --- a/TelegramUI/FormControllerItem.swift +++ b/TelegramUI/FormControllerItem.swift @@ -25,7 +25,7 @@ struct FormControllerItemLayoutParams { protocol FormControllerItem { func node() -> ASDisplayNode & FormControllerItemNode - func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) } protocol FormControllerItemNode { diff --git a/TelegramUI/FormControllerNode.swift b/TelegramUI/FormControllerNode.swift index 1a8d90766b..7b4967b32b 100644 --- a/TelegramUI/FormControllerNode.swift +++ b/TelegramUI/FormControllerNode.swift @@ -34,6 +34,7 @@ struct FormControllerLayoutState { struct FormControllerPresentationState { var theme: PresentationTheme var strings: PresentationStrings + var dateTimeFormat: PresentationDateTimeFormat func isEqual(to: FormControllerPresentationState) -> Bool { if self.theme !== to.theme { @@ -42,6 +43,9 @@ struct FormControllerPresentationState { if self.strings !== to.strings { return false } + if self.dateTimeFormat != to.dateTimeFormat { + return false + } return true } } @@ -125,14 +129,14 @@ class FormControllerNode: View preconditionFailure() } - required init(initParams: InitParams, theme: PresentationTheme, strings: PresentationStrings) { - self.internalState = FormControllerInternalState(layoutState: nil, presentationState: FormControllerPresentationState(theme: theme, strings: strings), innerState: nil) + required init(initParams: InitParams, presentationData: PresentationData) { + self.internalState = FormControllerInternalState(layoutState: nil, presentationState: FormControllerPresentationState(theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat), innerState: nil) self.scrollNode = FormControllerScrollerNode() super.init() - self.backgroundColor = theme.list.blocksBackgroundColor + self.backgroundColor = presentationData.theme.list.blocksBackgroundColor self.scrollNode.backgroundColor = nil self.scrollNode.isOpaque = false @@ -262,7 +266,7 @@ class FormControllerNode: View itemTransition = transition } - let (preLayout, apply) = item.update(node: itemNodes[itemNodeIndex], theme: state.presentationState.theme, strings: state.presentationState.strings, width: layout.size.width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: itemTransition) + let (preLayout, apply) = item.update(node: itemNodes[itemNodeIndex], theme: state.presentationState.theme, strings: state.presentationState.strings, dateTimeFormat: state.presentationState.dateTimeFormat, width: layout.size.width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: itemTransition) applyLayouts.append((itemTransition, preLayout, apply)) itemNodeIndex += 1 diff --git a/TelegramUI/FormControllerTextInputItem.swift b/TelegramUI/FormControllerTextInputItem.swift index fd52b167ae..22c9910b91 100644 --- a/TelegramUI/FormControllerTextInputItem.swift +++ b/TelegramUI/FormControllerTextInputItem.swift @@ -44,14 +44,14 @@ final class FormControllerTextInputItem: FormControllerItem { return FormControllerTextInputItemNode() } - func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { guard let node = node as? FormControllerTextInputItemNode else { assertionFailure() return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in return 0.0 }) } - return node.updateInternal(item: self, theme: theme, strings: strings, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) + return node.updateInternal(item: self, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) } } @@ -84,7 +84,7 @@ final class FormControllerTextInputItemNode: FormBlockItemNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + override func update(item: FormControllerTextInputItem, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { self.item = item let leftInset: CGFloat = 16.0 diff --git a/TelegramUI/FormControllerTextItem.swift b/TelegramUI/FormControllerTextItem.swift index a1754af6fd..ce21fc4546 100644 --- a/TelegramUI/FormControllerTextItem.swift +++ b/TelegramUI/FormControllerTextItem.swift @@ -22,7 +22,7 @@ final class FormControllerTextItem: FormControllerItem { return FormControllerTextItemNode() } - func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in guard let node = node as? FormControllerTextItemNode else { assertionFailure() diff --git a/TelegramUI/GalleryController.swift b/TelegramUI/GalleryController.swift index 63dff18142..5238ac5225 100644 --- a/TelegramUI/GalleryController.swift +++ b/TelegramUI/GalleryController.swift @@ -134,12 +134,12 @@ func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) -> return false } -func galleryItemForEntry(account: Account, theme: PresentationTheme, strings: PresentationStrings, entry: MessageHistoryEntry, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, playbackCompleted: @escaping () -> Void = {}) -> GalleryItem? { +func galleryItemForEntry(account: Account, presentationData: PresentationData, entry: MessageHistoryEntry, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, playbackCompleted: @escaping () -> Void = {}) -> GalleryItem? { switch entry { case let .MessageEntry(message, _, location, _): if let media = mediaForMessage(message: message) { if let _ = media as? TelegramMediaImage { - return ChatImageGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location) + return ChatImageGalleryItem(account: account, presentationData: presentationData, message: message, location: location) } else if let file = media as? TelegramMediaFile { if file.isVideo || supportedVideoMimeTypes.contains(file.mimeType) { let content: UniversalVideoContent @@ -148,30 +148,30 @@ func galleryItemForEntry(account: Account, theme: PresentationTheme, strings: Pr } else { content = NativeVideoContent(id: .message(message.id, message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: loopVideos) } - return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: content, originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: message.text, hideControls: hideControls, playbackCompleted: playbackCompleted) + return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: message.text, hideControls: hideControls, playbackCompleted: playbackCompleted) } else { if file.mimeType.hasPrefix("image/") && file.mimeType != "image/gif" { if file.size == nil || file.size! < 5 * 1024 * 1024 { - return ChatImageGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location) + return ChatImageGalleryItem(account: account, presentationData: presentationData, message: message, location: location) } else { - return ChatDocumentGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location) + return ChatDocumentGalleryItem(account: account, presentationData: presentationData, message: message, location: location) } } else if internalDocumentItemSupportsMimeType(file.mimeType, fileName: file.fileName) { - return ChatDocumentGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location) + return ChatDocumentGalleryItem(account: account, presentationData: presentationData, message: message, location: location) } else { - return ChatExternalFileGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location) + return ChatExternalFileGalleryItem(account: account, presentationData: presentationData, message: message, location: location) } } } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = webpage.content { switch websiteType(of: webpageContent) { case .instagram where webpageContent.file != nil && webpageContent.image != nil && webpageContent.file!.isVideo: - return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: NativeVideoContent(id: NativeVideoContentId.message(message.id, message.stableId, webpage.webpageId), fileReference: .message(message: MessageReference(message), media: webpageContent.file!), streamVideo: true, enableSound: true), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "") + return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: NativeVideoContent(id: NativeVideoContentId.message(message.id, message.stableId, webpage.webpageId), fileReference: .message(message: MessageReference(message), media: webpageContent.file!), streamVideo: true, enableSound: true), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "") //return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: SystemVideoContent(url: webpageContent.embedUrl!, image: webpageContent.image!, dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0)), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "") /*case .twitter where webpageContent.embedUrl != nil && webpageContent.image != nil: return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: SystemVideoContent(url: webpageContent.embedUrl!, image: webpageContent.image!, dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0)), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "")*/ default: if let content = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent) { - return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: content, originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "") + return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "") } } } @@ -360,7 +360,7 @@ class GalleryController: ViewController { var items: [GalleryItem] = [] var centralItemIndex: Int? for entry in strongSelf.entries { - if let item = galleryItemForEntry(account: account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, entry: entry, streamVideos: streamSingleVideo) { + if let item = galleryItemForEntry(account: account, presentationData: strongSelf.presentationData, entry: entry, streamVideos: streamSingleVideo) { if case let .MessageEntry(message, _, _, _) = entry, message.stableId == strongSelf.centralEntryStableId { centralItemIndex = items.count } @@ -568,7 +568,7 @@ class GalleryController: ViewController { var items: [GalleryItem] = [] var centralItemIndex: Int? for entry in self.entries { - if let item = galleryItemForEntry(account: account, theme: self.presentationData.theme, strings: self.presentationData.strings, entry: entry, streamVideos: self.streamVideos) { + if let item = galleryItemForEntry(account: account, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos) { if case let .MessageEntry(message, _, _, _) = entry, message.stableId == self.centralEntryStableId { centralItemIndex = items.count } diff --git a/TelegramUI/GalleryThumbnailContainerNode.swift b/TelegramUI/GalleryThumbnailContainerNode.swift index 5218dd86f5..b81862c245 100644 --- a/TelegramUI/GalleryThumbnailContainerNode.swift +++ b/TelegramUI/GalleryThumbnailContainerNode.swift @@ -5,6 +5,7 @@ import SwiftSignalKit private let itemBaseSize = CGSize(width: 23.0, height: 42.0) private let spacing: CGFloat = 2.0 +private let maxWidth: CGFloat = 75.0 protocol GalleryThumbnailItem { func isEqual(to: GalleryThumbnailItem) -> Bool @@ -35,7 +36,7 @@ private final class GalleryThumbnailItemNode: ASDisplayNode { func updateLayout(height: CGFloat, progress: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { let boundingSize = self.imageSize.aspectFilled(CGSize(width: 1.0, height: height)) - let width = itemBaseSize.width * (1.0 - progress) + boundingSize.width * progress + let width = itemBaseSize.width * (1.0 - progress) + min(maxWidth, boundingSize.width) * progress let arguments = TransformImageArguments(corners: ImageCorners(radius: 0), imageSize: boundingSize, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets()) let makeLayout = self.imageNode.asyncLayout() let apply = makeLayout(arguments) diff --git a/TelegramUI/GroupAdminsController.swift b/TelegramUI/GroupAdminsController.swift index 897939a72d..3cc3ba0aa2 100644 --- a/TelegramUI/GroupAdminsController.swift +++ b/TelegramUI/GroupAdminsController.swift @@ -56,7 +56,7 @@ private enum GroupAdminsEntryStableId: Hashable { private enum GroupAdminsEntry: ItemListNodeEntry { case allAdmins(PresentationTheme, String, Bool) case allAdminsInfo(PresentationTheme, String) - case peerItem(Int32, PresentationTheme, PresentationStrings, Peer, String, Bool, Bool) + case peerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, String, Bool, Bool) var section: ItemListSectionId { switch self { @@ -73,7 +73,7 @@ private enum GroupAdminsEntry: ItemListNodeEntry { return .index(0) case .allAdminsInfo: return .index(1) - case let .peerItem(_, _, _, peer, _, _, _): + case let .peerItem(_, _, _, _, peer, _, _, _): return .peer(peer.id) } } @@ -92,8 +92,8 @@ private enum GroupAdminsEntry: ItemListNodeEntry { } else { return false } - case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsLabel, lhsToggled, lhsEnabled): - if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsLabel, rhsToggled, rhsEnabled) = rhs { + case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsLabel, lhsToggled, lhsEnabled): + if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsLabel, rhsToggled, rhsEnabled) = rhs { if lhsIndex != rhsIndex { return false } @@ -103,6 +103,9 @@ private enum GroupAdminsEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !lhsPeer.isEqual(rhsPeer) { return false } @@ -133,9 +136,9 @@ private enum GroupAdminsEntry: ItemListNodeEntry { default: return true } - case let .peerItem(index, _, _, _, _, _, _): + case let .peerItem(index, _, _, _, _, _, _, _): switch rhs { - case let .peerItem(rhsIndex, _, _, _, _, _, _): + case let .peerItem(rhsIndex, _, _, _, _, _, _, _): return index < rhsIndex case .allAdmins, .allAdminsInfo: return false @@ -151,8 +154,8 @@ private enum GroupAdminsEntry: ItemListNodeEntry { }) case let .allAdminsInfo(theme, text): return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) - case let .peerItem(_, theme, strings, peer, label, toggled, enabled): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: toggled, style: .standard), enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: { value in + case let .peerItem(_, theme, strings, dateTimeFormat, peer, label, toggled, enabled): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: toggled, style: .standard), enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: { value in arguments.updatePeerIsAdmin(peer.id, value) }) } @@ -273,7 +276,7 @@ private func groupAdminsControllerEntries(account: Account, presentationData: Pr } } } - entries.append(.peerItem(index, presentationData.theme, presentationData.strings, peer, label, isAdmin, isEnabled)) + entries.append(.peerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, label, isAdmin, isEnabled)) index += 1 } } diff --git a/TelegramUI/GroupInfoController.swift b/TelegramUI/GroupInfoController.swift index 33778c842b..4c48751bfa 100644 --- a/TelegramUI/GroupInfoController.swift +++ b/TelegramUI/GroupInfoController.swift @@ -128,7 +128,7 @@ private struct ParticipantRevealAction: Equatable { } private enum GroupInfoEntry: ItemListNodeEntry { - case info(PresentationTheme, PresentationStrings, peer: Peer?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) + case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) case setGroupPhoto(PresentationTheme, String) case about(PresentationTheme, String) case link(PresentationTheme, String) @@ -144,7 +144,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { case membersAdmins(PresentationTheme, String, String) case membersBlacklist(PresentationTheme, String, String) case addMember(PresentationTheme, String, editing: Bool) - case member(PresentationTheme, PresentationStrings, index: Int, peerId: PeerId, peer: Peer, participant: RenderedChannelParticipant?, presence: PeerPresence?, memberStatus: GroupInfoMemberStatus, editing: ItemListPeerItemEditing, revealActions: [ParticipantRevealAction], enabled: Bool) + case member(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, index: Int, peerId: PeerId, peer: Peer, participant: RenderedChannelParticipant?, presence: PeerPresence?, memberStatus: GroupInfoMemberStatus, editing: ItemListPeerItemEditing, revealActions: [ParticipantRevealAction], enabled: Bool) case convertToSupergroup(PresentationTheme, String) case leave(PresentationTheme, String) @@ -171,14 +171,17 @@ private enum GroupInfoEntry: ItemListNodeEntry { static func ==(lhs: GroupInfoEntry, rhs: GroupInfoEntry) -> Bool { switch lhs { - case let .info(lhsTheme, lhsStrings, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar): - if case let .info(rhsTheme, rhsStrings, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs { + case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar): + if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -323,14 +326,17 @@ private enum GroupInfoEntry: ItemListNodeEntry { } else { return false } - case let .member(lhsTheme, lhsStrings, lhsIndex, lhsPeerId, lhsPeer, lhsParticipant, lhsPresence, lhsMemberStatus, lhsEditing, lhsActions, lhsEnabled): - if case let .member(rhsTheme, rhsStrings, rhsIndex, rhsPeerId, rhsPeer, rhsParticipant, rhsPresence, rhsMemberStatus, rhsEditing, rhsActions, rhsEnabled) = rhs { + case let .member(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsIndex, lhsPeerId, lhsPeer, lhsParticipant, lhsPresence, lhsMemberStatus, lhsEditing, lhsActions, lhsEnabled): + if case let .member(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsIndex, rhsPeerId, rhsPeer, rhsParticipant, rhsPresence, rhsMemberStatus, rhsEditing, rhsActions, rhsEnabled) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsIndex != rhsIndex { return false } @@ -371,7 +377,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { var stableId: GroupEntryStableId { switch self { - case let .member(_, _, _, peerId, _, _, _, _, _, _, _): + case let .member(_, _, _, _, peerId, _, _, _, _, _, _, _): return .peer(peerId) default: return .index(self.sortIndex) @@ -412,7 +418,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { return 14 case .addMember: return 15 - case let .member(_, _, index, _, _, _, _, _, _, _, _): + case let .member(_, _, _, index, _, _, _, _, _, _, _, _): return 20 + index case .convertToSupergroup: return 100000 @@ -427,8 +433,8 @@ private enum GroupInfoEntry: ItemListNodeEntry { func item(_ arguments: GroupInfoArguments) -> ListViewItem { switch self { - case let .info(theme, strings, peer, cachedData, state, updatingAvatar): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: nil, cachedData: cachedData, state: state, sectionId: self.section, style: .blocks(withTopInset: false), editingNameUpdated: { editingName in + case let .info(theme, strings, dateTimeFormat, peer, cachedData, state, updatingAvatar): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: nil, cachedData: cachedData, state: state, sectionId: self.section, style: .blocks(withTopInset: false), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { arguments.tapAvatarAction() @@ -493,7 +499,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { return ItemListDisclosureItem(theme: theme, title: title, label: text, sectionId: self.section, style: .blocks, action: { arguments.pushController(channelBlacklistController(account: arguments.account, peerId: arguments.peerId)) }) - case let .member(theme, strings, _, _, peer, participant, presence, memberStatus, editing, actions, enabled): + case let .member(theme, strings, dateTimeFormat, _, _, peer, participant, presence, memberStatus, editing, actions, enabled): let label: String? switch memberStatus { case .admin: @@ -518,7 +524,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { } })) } - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: presence, text: .presence, label: label == nil ? .none : .text(label!), editing: editing, revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: enabled, sectionId: self.section, action: { + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: presence, text: .presence, label: label == nil ? .none : .text(label!), editing: editing, revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: enabled, sectionId: self.section, action: { if let infoController = peerInfoController(account: arguments.account, peer: peer) { arguments.pushController(infoController) } @@ -726,7 +732,7 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa if let peer = peerViewMainPeer(view) { let infoState = ItemListAvatarAndNameInfoItemState(editingName: canEditGroupInfo ? state.editingState?.editingName : nil, updatingName: state.updatingName) - entries.append(.info(presentationData.theme, presentationData.strings, peer: peer, cachedData: view.cachedData, state: infoState, updatingAvatar: state.updatingAvatar)) + entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer, cachedData: view.cachedData, state: infoState, updatingAvatar: state.updatingAvatar)) } if canEditGroupInfo { @@ -909,7 +915,7 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa } else { memberStatus = .member } - entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, index: i, peerId: peer.id, peer: peer, participant: nil, presence: peerPresences[peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: canRemoveParticipant(account: account, isAdmin: canEditMembers, participantId: peer.id, invitedBy: sortedParticipants[i].invitedBy), editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == peer.id), revealActions: [ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove)], enabled: !disabledPeerIds.contains(peer.id))) + entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, index: i, peerId: peer.id, peer: peer, participant: nil, presence: peerPresences[peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: canRemoveParticipant(account: account, isAdmin: canEditMembers, participantId: peer.id, invitedBy: sortedParticipants[i].invitedBy), editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == peer.id), revealActions: [ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove)], enabled: !disabledPeerIds.contains(peer.id))) } } } else if let channel = view.peers[view.peerId] as? TelegramChannel, let cachedChannelData = view.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount { @@ -1034,7 +1040,7 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa peerActions.append(ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove)) } - entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, index: i, peerId: participant.peer.id, peer: participant.peer, participant: participant, presence: participant.presences[participant.peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: !peerActions.isEmpty, editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == participant.peer.id), revealActions: peerActions, enabled: !disabledPeerIds.contains(participant.peer.id))) + entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, index: i, peerId: participant.peer.id, peer: participant.peer, participant: participant, presence: participant.presences[participant.peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: !peerActions.isEmpty, editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == participant.peer.id), revealActions: peerActions, enabled: !disabledPeerIds.contains(participant.peer.id))) } } diff --git a/TelegramUI/GroupsInCommonController.swift b/TelegramUI/GroupsInCommonController.swift index 070414a45d..a6fdc213c5 100644 --- a/TelegramUI/GroupsInCommonController.swift +++ b/TelegramUI/GroupsInCommonController.swift @@ -42,7 +42,7 @@ private enum GroupsInCommonEntryStableId: Hashable { } private enum GroupsInCommonEntry: ItemListNodeEntry { - case peerItem(Int32, PresentationTheme, PresentationStrings, Peer) + case peerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer) var section: ItemListSectionId { switch self { @@ -53,15 +53,15 @@ private enum GroupsInCommonEntry: ItemListNodeEntry { var stableId: GroupsInCommonEntryStableId { switch self { - case let .peerItem(_, _, _, peer): + case let .peerItem(_, _, _, _, peer): return .peer(peer.id) } } static func ==(lhs: GroupsInCommonEntry, rhs: GroupsInCommonEntry) -> Bool { switch lhs { - case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsPeer): - if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsPeer) = rhs { + case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer): + if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer) = rhs { if lhsIndex != rhsIndex { return false } @@ -71,6 +71,9 @@ private enum GroupsInCommonEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !lhsPeer.isEqual(rhsPeer) { return false } @@ -83,9 +86,9 @@ private enum GroupsInCommonEntry: ItemListNodeEntry { static func <(lhs: GroupsInCommonEntry, rhs: GroupsInCommonEntry) -> Bool { switch lhs { - case let .peerItem(index, _, _, _): + case let .peerItem(index, _, _, _, _): switch rhs { - case let .peerItem(rhsIndex, _, _, _): + case let .peerItem(rhsIndex, _, _, _, _): return index < rhsIndex } } @@ -93,8 +96,8 @@ private enum GroupsInCommonEntry: ItemListNodeEntry { func item(_ arguments: GroupsInCommonControllerArguments) -> ListViewItem { switch self { - case let .peerItem(_, theme, strings, peer): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: { + case let .peerItem(_, theme, strings, dateTimeFormat, peer): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: { arguments.openPeer(peer.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in @@ -115,7 +118,7 @@ private func groupsInCommonControllerEntries(presentationData: PresentationData, if let peers = peers { var index: Int32 = 0 for peer in peers { - entries.append(.peerItem(index, presentationData.theme, presentationData.strings, peer)) + entries.append(.peerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer)) index += 1 } } diff --git a/TelegramUI/HashtagSearchController.swift b/TelegramUI/HashtagSearchController.swift index 989e8d0a29..4ea49df506 100644 --- a/TelegramUI/HashtagSearchController.swift +++ b/TelegramUI/HashtagSearchController.swift @@ -33,7 +33,7 @@ final class HashtagSearchController: TelegramController { self.title = query self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) - let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) + let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) let location: SearchMessagesLocation = .general let search = searchMessages(account: account, location: location, query: query) diff --git a/TelegramUI/InstantImageGalleryItem.swift b/TelegramUI/InstantImageGalleryItem.swift index c2ab6b8abe..91341c9e8e 100644 --- a/TelegramUI/InstantImageGalleryItem.swift +++ b/TelegramUI/InstantImageGalleryItem.swift @@ -35,27 +35,25 @@ private struct InstantImageGalleryThumbnailItem: GalleryThumbnailItem { class InstantImageGalleryItem: GalleryItem { let account: Account - let theme: PresentationTheme - let strings: PresentationStrings + let presentationData: PresentationData let imageReference: ImageMediaReference let caption: String let location: InstantPageGalleryEntryLocation - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, imageReference: ImageMediaReference, caption: String, location: InstantPageGalleryEntryLocation) { + init(account: Account, presentationData: PresentationData, imageReference: ImageMediaReference, caption: String, location: InstantPageGalleryEntryLocation) { self.account = account - self.theme = theme - self.strings = strings + self.presentationData = presentationData self.imageReference = imageReference self.caption = caption self.location = location } func node() -> GalleryItemNode { - let node = InstantImageGalleryItemNode(account: self.account, theme: self.theme, strings: self.strings) + let node = InstantImageGalleryItemNode(account: self.account, presentationData: self.presentationData) node.setImage(imageReference: self.imageReference) - node._title.set(.single("\(self.location.position + 1) of \(self.location.totalCount)")) + node._title.set(.single("\(self.location.position + 1) \(self.presentationData.strings.Common_of) \(self.location.totalCount)")) node.setCaption(self.caption) @@ -64,7 +62,7 @@ class InstantImageGalleryItem: GalleryItem { func updateNode(node: GalleryItemNode) { if let node = node as? InstantImageGalleryItemNode { - node._title.set(.single("\(self.location.position + 1) of \(self.location.totalCount)")) + node._title.set(.single("\(self.location.position + 1) \(self.presentationData.strings.Common_of) \(self.location.totalCount)")) node.setCaption(self.caption) } @@ -93,11 +91,11 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { private var fetchDisposable = MetaDisposable() - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { self.account = account self.imageNode = TransformImageNode() - self.footerContentNode = InstantPageGalleryFooterContentNode(account: account, theme: theme, strings: strings) + self.footerContentNode = InstantPageGalleryFooterContentNode(account: account, presentationData: presentationData) super.init() diff --git a/TelegramUI/InstantPageController.swift b/TelegramUI/InstantPageController.swift index f7da622e78..c4db418347 100644 --- a/TelegramUI/InstantPageController.swift +++ b/TelegramUI/InstantPageController.swift @@ -72,7 +72,7 @@ final class InstantPageController: ViewController { } override public func loadDisplayNode() { - self.displayNode = InstantPageControllerNode(account: self.account, settings: self.settings, presentationTheme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, statusBar: self.statusBar, getNavigationController: { [weak self] in + self.displayNode = InstantPageControllerNode(account: self.account, settings: self.settings, presentationTheme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, statusBar: self.statusBar, getNavigationController: { [weak self] in return self?.navigationController as? NavigationController }, present: { [weak self] c, a in self?.present(c, in: .window(.root), with: a) diff --git a/TelegramUI/InstantPageControllerNode.swift b/TelegramUI/InstantPageControllerNode.swift index 773df56eb4..cc18af5a84 100644 --- a/TelegramUI/InstantPageControllerNode.swift +++ b/TelegramUI/InstantPageControllerNode.swift @@ -11,7 +11,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { private var settings: InstantPagePresentationSettings? private var presentationTheme: PresentationTheme private var strings: PresentationStrings - private var timeFormat: PresentationTimeFormat + private var dateTimeFormat: PresentationDateTimeFormat private var theme: InstantPageTheme? private var manualThemeOverride: InstantPageThemeType? private let getNavigationController: () -> NavigationController? @@ -51,10 +51,10 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { private var themeReferenceDate: Date? - init(account: Account, settings: InstantPagePresentationSettings?, presentationTheme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, statusBar: StatusBar, getNavigationController: @escaping () -> NavigationController?, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, openPeer: @escaping (PeerId) -> Void, navigateBack: @escaping () -> Void) { + init(account: Account, settings: InstantPagePresentationSettings?, presentationTheme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, statusBar: StatusBar, getNavigationController: @escaping () -> NavigationController?, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, openPeer: @escaping (PeerId) -> Void, navigateBack: @escaping () -> Void) { self.account = account self.presentationTheme = presentationTheme - self.timeFormat = timeFormat + self.dateTimeFormat = dateTimeFormat self.strings = strings self.settings = settings let themeReferenceDate = Date() @@ -294,7 +294,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { return } - let currentLayout = instantPageLayoutForWebPage(webPage, boundingWidth: containerLayout.size.width, safeInset: containerLayout.safeInsets.left, strings: self.strings, theme: theme, timeFormat: self.timeFormat) + let currentLayout = instantPageLayoutForWebPage(webPage, boundingWidth: containerLayout.size.width, safeInset: containerLayout.safeInsets.left, strings: self.strings, theme: theme, dateTimeFormat: self.dateTimeFormat) for (_, tileNode) in self.visibleTiles { tileNode.removeFromSupernode() diff --git a/TelegramUI/InstantPageGalleryController.swift b/TelegramUI/InstantPageGalleryController.swift index fe93d5e2b9..a94e751e9c 100644 --- a/TelegramUI/InstantPageGalleryController.swift +++ b/TelegramUI/InstantPageGalleryController.swift @@ -26,11 +26,11 @@ struct InstantPageGalleryEntry: Equatable { return lhs.index == rhs.index && lhs.pageId == rhs.pageId && lhs.media == rhs.media && lhs.caption == rhs.caption && lhs.location == rhs.location } - func item(account: Account, webPage: TelegramMediaWebpage, theme: PresentationTheme, strings: PresentationStrings) -> GalleryItem { + func item(account: Account, webPage: TelegramMediaWebpage, presentationData: PresentationData) -> GalleryItem { if let image = self.media.media as? TelegramMediaImage { - return InstantImageGalleryItem(account: account, theme: theme, strings: strings, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: self.caption, location: self.location) + return InstantImageGalleryItem(account: account, presentationData: presentationData, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: self.caption, location: self.location) } else if let file = self.media.media as? TelegramMediaFile, file.isVideo { - return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: NativeVideoContent(id: .instantPage(self.pageId, file.fileId), fileReference: .webPage(webPage: WebpageReference(webPage), media: file)), originData: nil, indexData: GalleryItemIndexData(position: self.location.position, totalCount: self.location.totalCount), contentInfo: .webPage(webPage, file), caption: self.caption) + return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: NativeVideoContent(id: .instantPage(self.pageId, file.fileId), fileReference: .webPage(webPage: WebpageReference(webPage), media: file)), originData: nil, indexData: GalleryItemIndexData(position: self.location.position, totalCount: self.location.totalCount), contentInfo: .webPage(webPage, file), caption: self.caption) } else { preconditionFailure() } @@ -100,7 +100,7 @@ class InstantPageGalleryController: ViewController { strongSelf.centralEntryIndex = centralIndex if strongSelf.isViewLoaded { strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ - $0.item(account: account, webPage: webPage, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings) + $0.item(account: account, webPage: webPage, presentationData: strongSelf.presentationData) }), centralItemIndex: centralIndex, keepFirst: false) let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in @@ -202,7 +202,7 @@ class InstantPageGalleryController: ViewController { } self.galleryNode.pager.replaceItems(self.entries.map({ - $0.item(account: account, webPage: self.webPage, theme: self.presentationData.theme, strings: self.presentationData.strings) + $0.item(account: account, webPage: self.webPage, presentationData: self.presentationData) }), centralItemIndex: self.centralEntryIndex) self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in diff --git a/TelegramUI/InstantPageGalleryFooterContentNode.swift b/TelegramUI/InstantPageGalleryFooterContentNode.swift index d87786abe2..c52f2a3549 100644 --- a/TelegramUI/InstantPageGalleryFooterContentNode.swift +++ b/TelegramUI/InstantPageGalleryFooterContentNode.swift @@ -21,10 +21,10 @@ final class InstantPageGalleryFooterContentNode: GalleryFooterContentNode { private var currentMessageText: String? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { self.account = account - self.theme = theme - self.strings = strings + self.theme = presentationData.theme + self.strings = presentationData.strings self.actionButton = UIButton() diff --git a/TelegramUI/InstantPageLayout.swift b/TelegramUI/InstantPageLayout.swift index c718d07ca0..a38f2e5c4f 100644 --- a/TelegramUI/InstantPageLayout.swift +++ b/TelegramUI/InstantPageLayout.swift @@ -40,10 +40,10 @@ private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantP } } -func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToWidthAndHeight: Bool, media: [MediaId: Media], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) -> InstantPageLayout { +func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToWidthAndHeight: Bool, media: [MediaId: Media], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> InstantPageLayout { switch block { case let .cover(block): - return layoutInstantPageBlock(webpage: webpage, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToWidthAndHeight: fillToWidthAndHeight, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, timeFormat: timeFormat) + return layoutInstantPageBlock(webpage: webpage, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToWidthAndHeight: fillToWidthAndHeight, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat) case let .title(text): let styleStack = InstantPageTextStyleStack() setupStyleStack(styleStack, theme: theme, category: .header, link: false) @@ -361,7 +361,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlo nextItemOrigin.x = 0.0 nextItemOrigin.y += itemSize + spacing } - let subLayout = layoutInstantPageBlock(webpage: webpage, block: subItem, boundingWidth: itemSize, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: true, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, timeFormat: timeFormat) + let subLayout = layoutInstantPageBlock(webpage: webpage, block: subItem, boundingWidth: itemSize, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: true, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat) items.append(contentsOf: subLayout.flattenedItemsWithOrigin(nextItemOrigin)) nextItemOrigin.x += itemSize + spacing } @@ -442,7 +442,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlo var previousBlock: InstantPageBlock? for subBlock in blocks { - let subLayout = layoutInstantPageBlock(webpage: webpage, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, timeFormat: timeFormat) + let subLayout = layoutInstantPageBlock(webpage: webpage, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat) let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock) let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + lineInset, y: contentSize.height + spacing)) @@ -600,7 +600,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlo } } -func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, timeFormat: PresentationTimeFormat) -> InstantPageLayout { +func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat) -> InstantPageLayout { var maybeLoadedContent: TelegramMediaWebpageLoadedContent? if case let .Loaded(content) = webPage.content { maybeLoadedContent = content @@ -624,7 +624,7 @@ func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth: var previousBlock: InstantPageBlock? for block in pageBlocks { - let blockLayout = layoutInstantPageBlock(webpage: webPage, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, timeFormat: timeFormat) + let blockLayout = layoutInstantPageBlock(webpage: webPage, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat) let spacing = spacingBetweenBlocks(upper: previousBlock, lower: block) let blockItems = blockLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing)) items.append(contentsOf: blockItems) diff --git a/TelegramUI/ItemListAvatarAndNameItem.swift b/TelegramUI/ItemListAvatarAndNameItem.swift index cb154f664c..c035423555 100644 --- a/TelegramUI/ItemListAvatarAndNameItem.swift +++ b/TelegramUI/ItemListAvatarAndNameItem.swift @@ -152,6 +152,7 @@ class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { let account: Account let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let mode: ItemListAvatarAndNameInfoItemMode let peer: Peer? let presence: PeerPresence? @@ -171,10 +172,11 @@ class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { let selectable: Bool - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, mode: ItemListAvatarAndNameInfoItemMode, peer: Peer?, presence: PeerPresence?, label: String? = nil, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, sectionId: ItemListSectionId, style: ItemListAvatarAndNameInfoItemStyle, editingNameUpdated: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, avatarTapped: @escaping () -> Void, context: ItemListAvatarAndNameInfoItemContext? = nil, updatingImage: ItemListAvatarAndNameInfoItemUpdatingAvatar? = nil, call: (() -> Void)? = nil, action: (() -> Void)? = nil, longTapAction: (() -> Void)? = nil, tag: ItemListItemTag? = nil) { + init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, mode: ItemListAvatarAndNameInfoItemMode, peer: Peer?, presence: PeerPresence?, label: String? = nil, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, sectionId: ItemListSectionId, style: ItemListAvatarAndNameInfoItemStyle, editingNameUpdated: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, avatarTapped: @escaping () -> Void, context: ItemListAvatarAndNameInfoItemContext? = nil, updatingImage: ItemListAvatarAndNameInfoItemUpdatingAvatar? = nil, call: (() -> Void)? = nil, action: (() -> Void)? = nil, longTapAction: (() -> Void)? = nil, tag: ItemListItemTag? = nil) { self.account = account self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.mode = mode self.peer = peer self.presence = presence @@ -410,10 +412,10 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite } else if let _ = peer.botInfo { statusText = item.strings.Bot_GenericBotStatus statusColor = item.theme.list.itemSecondaryTextColor - } else if case .generic = item.mode, !(peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id == 777000) { + } else if case .generic = item.mode, !(peer.id.namespace == Namespaces.Peer.CloudUser && (peer.id.id == 777000 || peer.id.id == 333000)) { let presence = (item.presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none) let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: .regular, presence: presence, relativeTo: Int32(timestamp)) + let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, dateTimeFormat: item.dateTimeFormat, presence: presence, relativeTo: Int32(timestamp)) statusText = string if activity { statusColor = item.theme.list.itemAccentColor diff --git a/TelegramUI/ItemListCallListItem.swift b/TelegramUI/ItemListCallListItem.swift new file mode 100644 index 0000000000..e834aeecb0 --- /dev/null +++ b/TelegramUI/ItemListCallListItem.swift @@ -0,0 +1,312 @@ +import Foundation +import Display +import AsyncDisplayKit +import SwiftSignalKit +import Postbox +import TelegramCore + +class ItemListCallListItem: ListViewItem, ItemListItem { + let theme: PresentationTheme + let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat + let messages: [Message] + let sectionId: ItemListSectionId + let style: ItemListStyle + + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, messages: [Message], sectionId: ItemListSectionId, style: ItemListStyle) { + self.theme = theme + self.strings = strings + self.dateTimeFormat = dateTimeFormat + self.messages = messages + self.sectionId = sectionId + self.style = style + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + async { + let node = ItemListCallListItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? ItemListCallListItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { + apply() + }) + } + } + } + } + } +} + +private let titleFont = Font.regular(15.0) +private let font = Font.regular(14.0) +private let typeFont = Font.medium(14.0) + +private func stringForCallType(message: Message, strings: PresentationStrings) -> String { + var string = "" + for media in message.media { + switch media { + case let action as TelegramMediaAction: + switch action.action { + case let .phoneCall(_, discardReason, _): + let incoming = message.flags.contains(.Incoming) + if let discardReason = discardReason { + switch discardReason { + case .busy, .disconnect: + string = strings.Notification_CallCanceled + case .missed: + string = incoming ? strings.Notification_CallMissed : strings.Notification_CallCanceled + case .hangup: + break + } + } + + if string.isEmpty { + if incoming { + string = strings.Notification_CallIncoming + } else { + string = strings.Notification_CallOutgoing + } + } + default: + break + } + + default: + break + } + } + return string +} + +class ItemListCallListItemNode: ListViewItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + + let titleNode: TextNode + var callNodes: [(TextNode, TextNode)] + + private var item: ItemListCallListItem? + + override var canBeSelected: Bool { + return false + } + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.backgroundNode.backgroundColor = .white + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.titleNode = TextNode() + self.titleNode.isLayerBacked = true + + self.callNodes = [] + + super.init(layerBacked: false, dynamicBounce: false) + + self.addSubnode(self.titleNode) + } + + func asyncLayout() -> (_ item: ItemListCallListItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + let makeTitleLayout = TextNode.asyncLayout(self.titleNode) + let currentItem = self.item + + return { item, params, neighbors in + if self.callNodes.count != item.messages.count { + for pair in self.callNodes { + pair.0.removeFromSupernode() + pair.1.removeFromSupernode() + } + + self.callNodes = [] + + for _ in item.messages { + let timeNode = TextNode() + timeNode.isLayerBacked = true + self.addSubnode(timeNode) + + let typeNode = TextNode() + typeNode.isLayerBacked = true + self.addSubnode(typeNode) + + self.callNodes.append((timeNode, typeNode)) + } + } + + var makeNodesLayout: [((TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode), (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode))] = [] + for nodes in self.callNodes { + let makeTimeLayout = TextNode.asyncLayout(nodes.0) + let makeTypeLayout = TextNode.asyncLayout(nodes.1) + makeNodesLayout.append((makeTimeLayout, makeTypeLayout)) + } + + var updatedTheme: PresentationTheme? + + if currentItem?.theme !== item.theme { + updatedTheme = item.theme + } + + let contentSize: CGSize + var contentHeight: CGFloat = 0.0 + let insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + let itemBackgroundColor: UIColor + let itemSeparatorColor: UIColor + + let leftInset = 16.0 + params.leftInset + + switch item.style { + case .plain: + itemBackgroundColor = item.theme.list.plainBackgroundColor + itemSeparatorColor = item.theme.list.itemPlainSeparatorColor + insets = itemListNeighborsPlainInsets(neighbors) + case .blocks: + itemBackgroundColor = item.theme.list.itemBlocksBackgroundColor + itemSeparatorColor = item.theme.list.itemBlocksSeparatorColor + insets = itemListNeighborsGroupedInsets(neighbors) + } + + let earliestMessage = item.messages.sorted(by: {$0.timestamp < $1.timestamp}).first! + let titleText = stringForDate(timestamp: earliestMessage.timestamp, strings: item.strings) + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleText, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + contentHeight += titleLayout.size.height + 18.0 + + var index = 0 + var nodesLayout: [(TextNodeLayout, TextNodeLayout)] = [] + var nodesApply: [(() -> TextNode, () -> TextNode)] = [] + for message in item.messages { + let makeTimeLayout = makeNodesLayout[index].0 + let time = stringForMessageTimestamp(timestamp: message.timestamp, dateTimeFormat: item.dateTimeFormat) + let (timeLayout, timeApply) = makeTimeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: time, font: font, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let makeTypeLayout = makeNodesLayout[index].1 + let type = stringForCallType(message: message, strings: item.strings) + let (typeLayout, typeApply) = makeTypeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: type, font: typeFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + nodesLayout.append((timeLayout, typeLayout)) + nodesApply.append((timeApply, typeApply)) + + contentHeight += timeLayout.size.height + 12.0 + + index += 1 + } + + contentSize = CGSize(width: params.width, height: contentHeight) + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + + return (layout, { [weak self] in + if let strongSelf = self { + strongSelf.item = item + + if let _ = updatedTheme { + strongSelf.topStripeNode.backgroundColor = itemSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor + strongSelf.backgroundNode.backgroundColor = itemBackgroundColor + } + + let _ = titleApply() + + for apply in nodesApply { + let _ = apply.0() + let _ = apply.1() + } + + switch item.style { + case .plain: + if strongSelf.backgroundNode.supernode != nil { + strongSelf.backgroundNode.removeFromSupernode() + } + if strongSelf.topStripeNode.supernode != nil { + strongSelf.topStripeNode.removeFromSupernode() + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) + } + + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) + case .blocks: + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + strongSelf.topStripeNode.isHidden = false + } + let bottomStripeInset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = leftInset + default: + bottomStripeInset = 0.0 + } + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) + } + + strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: titleLayout.size) + + var index = 0 + var yOffset = strongSelf.titleNode.frame.maxY + 10.0 + for nodes in strongSelf.callNodes { + let layout = nodesLayout[index] + nodes.0.frame = CGRect(origin: CGPoint(x: leftInset, y: yOffset), size: layout.0.size) + nodes.1.frame = CGRect(origin: CGPoint(x: leftInset + 75.0, y: yOffset), size: layout.1.size) + + yOffset += layout.0.size.height + 12.0 + index += 1 + } + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateAdded(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} + diff --git a/TelegramUI/ItemListPeerItem.swift b/TelegramUI/ItemListPeerItem.swift index a63d725c39..0fa3622b66 100644 --- a/TelegramUI/ItemListPeerItem.swift +++ b/TelegramUI/ItemListPeerItem.swift @@ -62,6 +62,7 @@ struct ItemListPeerItemRevealOptions { final class ItemListPeerItem: ListViewItem, ItemListItem { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let account: Account let peer: Peer let aliasHandling: ItemListPeerItemAliasHandling @@ -79,9 +80,10 @@ final class ItemListPeerItem: ListViewItem, ItemListItem { let removePeer: (PeerId) -> Void let toggleUpdated: ((Bool) -> Void)? - init(theme: PresentationTheme, strings: PresentationStrings, account: Account, peer: Peer, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, account: Account, peer: Peer, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.account = account self.peer = peer self.aliasHandling = aliasHandling @@ -349,7 +351,7 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode { statusAttributedString = NSAttributedString(string: item.strings.Bot_GenericBotStatus, font: statusFont, textColor: item.theme.list.itemSecondaryTextColor) } else if let presence = item.presence as? TelegramUserPresence { let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: .regular, presence: presence, relativeTo: Int32(timestamp)) + let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, dateTimeFormat: item.dateTimeFormat, presence: presence, relativeTo: Int32(timestamp)) statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.theme.list.itemAccentColor : item.theme.list.itemSecondaryTextColor) } else { statusAttributedString = NSAttributedString(string: item.strings.LastSeen_ALongTimeAgo, font: statusFont, textColor: item.theme.list.itemSecondaryTextColor) diff --git a/TelegramUI/ItemListRecentSessionItem.swift b/TelegramUI/ItemListRecentSessionItem.swift index 2ad944668d..ed4b8ad306 100644 --- a/TelegramUI/ItemListRecentSessionItem.swift +++ b/TelegramUI/ItemListRecentSessionItem.swift @@ -33,6 +33,7 @@ enum ItemListRecentSessionItemText { final class ItemListRecentSessionItem: ListViewItem, ItemListItem { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let session: RecentAccountSession let enabled: Bool let editable: Bool @@ -42,9 +43,10 @@ final class ItemListRecentSessionItem: ListViewItem, ItemListItem { let setSessionIdWithRevealedOptions: (Int64?, Int64?) -> Void let removeSession: (Int64) -> Void - init(theme: PresentationTheme, strings: PresentationStrings, session: RecentAccountSession, enabled: Bool, editable: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editable: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.session = session self.enabled = enabled self.editable = editable @@ -213,7 +215,7 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode { labelAttributedString = NSAttributedString(string: item.strings.Presence_online, font: textFont, textColor: item.theme.list.itemAccentColor) } else { let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - let dateText = stringForRelativeTimestamp(strings: item.strings, relativeTimestamp: item.session.activityDate, relativeTo: timestamp, timeFormat: .regular) + let dateText = stringForRelativeTimestamp(strings: item.strings, relativeTimestamp: item.session.activityDate, relativeTo: timestamp, dateTimeFormat: item.dateTimeFormat) labelAttributedString = NSAttributedString(string: dateText, font: textFont, textColor: item.theme.list.itemSecondaryTextColor) } diff --git a/TelegramUI/ItemListWebsiteItem.swift b/TelegramUI/ItemListWebsiteItem.swift index 74bddb9af0..6f5e1eed8e 100644 --- a/TelegramUI/ItemListWebsiteItem.swift +++ b/TelegramUI/ItemListWebsiteItem.swift @@ -23,6 +23,7 @@ struct ItemListWebsiteItemEditing: Equatable { final class ItemListWebsiteItem: ListViewItem, ItemListItem { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let website: WebAuthorization let peer: Peer? let enabled: Bool @@ -32,9 +33,10 @@ final class ItemListWebsiteItem: ListViewItem, ItemListItem { let setSessionIdWithRevealedOptions: (Int64?, Int64?) -> Void let removeSession: (Int64) -> Void - init(theme: PresentationTheme, strings: PresentationStrings, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.website = website self.peer = peer self.enabled = enabled @@ -195,7 +197,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { locationAttributedString = NSAttributedString(string: "\(item.website.ip) — \(item.website.region)", font: textFont, textColor: item.theme.list.itemSecondaryTextColor) let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - let dateText = stringForRelativeTimestamp(strings: item.strings, relativeTimestamp: item.website.dateActive, relativeTo: timestamp, timeFormat: .regular) + let dateText = stringForRelativeTimestamp(strings: item.strings, relativeTimestamp: item.website.dateActive, relativeTo: timestamp, dateTimeFormat: item.dateTimeFormat) labelAttributedString = NSAttributedString(string: dateText, font: textFont, textColor: item.theme.list.itemSecondaryTextColor) let leftInset: CGFloat = 15.0 + params.leftInset diff --git a/TelegramUI/ListMessageFileItemNode.swift b/TelegramUI/ListMessageFileItemNode.swift index c789d70eb4..2e616d2ce9 100644 --- a/TelegramUI/ListMessageFileItemNode.swift +++ b/TelegramUI/ListMessageFileItemNode.swift @@ -343,7 +343,7 @@ final class ListMessageFileItemNode: ListMessageNode { iconImage = .imageRepresentation(file, representation) } - let dateString = stringForFullDate(timestamp: item.message.timestamp, strings: item.strings, timeFormat: .regular) + let dateString = stringForFullDate(timestamp: item.message.timestamp, strings: item.strings, dateTimeFormat: item.dateTimeFormat) let descriptionString: String if let size = file.size { diff --git a/TelegramUI/ListMessageItem.swift b/TelegramUI/ListMessageItem.swift index aea42999ea..8aa2758844 100644 --- a/TelegramUI/ListMessageItem.swift +++ b/TelegramUI/ListMessageItem.swift @@ -8,6 +8,7 @@ import Postbox final class ListMessageItem: ListViewItem { let theme: PresentationTheme let strings: PresentationStrings + let dateTimeFormat: PresentationDateTimeFormat let account: Account let chatLocation: ChatLocation let controllerInteraction: ChatControllerInteraction @@ -18,9 +19,10 @@ final class ListMessageItem: ListViewItem { let selectable: Bool = true - public init(theme: PresentationTheme, strings: PresentationStrings, account: Account, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, message: Message, selection: ChatHistoryMessageSelection, displayHeader: Bool) { + public init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, account: Account, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, message: Message, selection: ChatHistoryMessageSelection, displayHeader: Bool) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.account = account self.chatLocation = chatLocation self.controllerInteraction = controllerInteraction diff --git a/TelegramUI/MediaNavigationAccessoryContainerNode.swift b/TelegramUI/MediaNavigationAccessoryContainerNode.swift index 80c30d7385..db6c8f168c 100644 --- a/TelegramUI/MediaNavigationAccessoryContainerNode.swift +++ b/TelegramUI/MediaNavigationAccessoryContainerNode.swift @@ -15,7 +15,7 @@ final class MediaNavigationAccessoryContainerNode: ASDisplayNode, UIGestureRecog self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } self.backgroundNode = ASDisplayNode() - self.headerNode = MediaNavigationAccessoryHeaderNode(theme: self.presentationData.theme, strings: self.presentationData.strings) + self.headerNode = MediaNavigationAccessoryHeaderNode(presentationData: self.presentationData) super.init() diff --git a/TelegramUI/MediaNavigationAccessoryHeaderNode.swift b/TelegramUI/MediaNavigationAccessoryHeaderNode.swift index b7489b8694..3515aff0f6 100644 --- a/TelegramUI/MediaNavigationAccessoryHeaderNode.swift +++ b/TelegramUI/MediaNavigationAccessoryHeaderNode.swift @@ -12,6 +12,7 @@ final class MediaNavigationAccessoryHeaderNode: ASDisplayNode { private var theme: PresentationTheme private var strings: PresentationStrings + private var dateTimeFormat: PresentationDateTimeFormat private let titleNode: TextNode private let subtitleNode: TextNode @@ -67,9 +68,10 @@ final class MediaNavigationAccessoryHeaderNode: ASDisplayNode { } } - init(theme: PresentationTheme, strings: PresentationStrings) { - self.theme = theme - self.strings = strings + init(presentationData: PresentationData) { + self.theme = presentationData.theme + self.strings = presentationData.strings + self.dateTimeFormat = presentationData.dateTimeFormat self.titleNode = TextNode() self.titleNode.isLayerBacked = true @@ -194,6 +196,7 @@ final class MediaNavigationAccessoryHeaderNode: ASDisplayNode { func updatePresentationData(_ presentationData: PresentationData) { self.theme = presentationData.theme self.strings = presentationData.strings + self.dateTimeFormat = presentationData.dateTimeFormat self.closeButton.setImage(PresentationResourcesRootController.navigationPlayerCloseButton(self.theme), for: []) self.actionPlayNode.image = PresentationResourcesRootController.navigationPlayerPlayIcon(self.theme) @@ -248,7 +251,7 @@ final class MediaNavigationAccessoryHeaderNode: ASDisplayNode { } if titleText == subtitleText { - subtitleText = humanReadableStringForTimestamp(strings: self.strings, timeFormat: .military, timestamp: timestamp) + subtitleText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: timestamp) } titleString = NSAttributedString(string: titleText, font: titleFont, textColor: self.theme.rootController.navigationBar.primaryTextColor) diff --git a/TelegramUI/PeerMediaCollectionControllerNode.swift b/TelegramUI/PeerMediaCollectionControllerNode.swift index 58deb12761..102ac669d2 100644 --- a/TelegramUI/PeerMediaCollectionControllerNode.swift +++ b/TelegramUI/PeerMediaCollectionControllerNode.swift @@ -138,7 +138,7 @@ class PeerMediaCollectionControllerNode: ASDisplayNode { self.historyEmptyNode = PeerMediaCollectionEmptyNode(mode: self.mediaCollectionInterfaceState.mode, theme: self.presentationData.theme, strings: self.presentationData.strings) self.historyEmptyNode.isHidden = true - self.chatPresentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, fontSize: self.presentationData.fontSize, accountPeerId: account.peerId, mode: .standard(previewing: false), chatLocation: .peer(self.peerId)) + self.chatPresentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, fontSize: self.presentationData.fontSize, accountPeerId: account.peerId, mode: .standard(previewing: false), chatLocation: .peer(self.peerId)) super.init() diff --git a/TelegramUI/PeerSelectionControllerNode.swift b/TelegramUI/PeerSelectionControllerNode.swift index 660a6e7f40..4b3c77d38e 100644 --- a/TelegramUI/PeerSelectionControllerNode.swift +++ b/TelegramUI/PeerSelectionControllerNode.swift @@ -62,7 +62,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor self.segmentedControl.selectedSegmentIndex = 0 - self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, timeFormat: presentationData.timeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder) + self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder) super.init() @@ -107,7 +107,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { private func updateThemeAndStrings() { self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings) - self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) + self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { diff --git a/TelegramUI/PresenceStrings.swift b/TelegramUI/PresenceStrings.swift index 640e5b1d72..d42dcbdd92 100644 --- a/TelegramUI/PresenceStrings.swift +++ b/TelegramUI/PresenceStrings.swift @@ -2,12 +2,24 @@ import Foundation import Postbox import TelegramCore -func stringForTimestamp(day: Int32, month: Int32, year: Int32) -> String { - return String(format: "%d.%02d.%02d", day, month, year - 100) +func stringForTimestamp(day: Int32, month: Int32, year: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String { + let separator = dateTimeFormat.dateSeparator + switch dateTimeFormat.dateFormat { + case .monthFirst: + return String(format: "%d%@%d%@%02d", month, separator, day, separator, year - 100) + case .dayFirst: + return String(format: "%d%@%02d%@%02d", day, separator, month, separator, year - 100) + } } -func stringForTimestamp(day: Int32, month: Int32) -> String { - return String(format: "%d.%02d", day, month) +func stringForTimestamp(day: Int32, month: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String { + let separator = dateTimeFormat.dateSeparator + switch dateTimeFormat.dateFormat { + case .monthFirst: + return String(format: "%d%@%d", month, separator, day) + case .dayFirst: + return String(format: "%d%@%02d", day, separator, month) + } } func shortStringForDayOfWeek(strings: PresentationStrings, day: Int32) -> String { @@ -71,29 +83,29 @@ enum RelativeTimestampFormatDay { case yesterday } -func stringForUserPresence(strings: PresentationStrings, day: RelativeTimestampFormatDay, timeFormat: PresentationTimeFormat, hours: Int32, minutes: Int32) -> String { +func stringForUserPresence(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String { let dayString: String switch day { case .today: - dayString = strings.LastSeen_AtDate(strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, timeFormat: timeFormat)).0).0 + dayString = strings.LastSeen_AtDate(strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0).0 case .yesterday: - dayString = strings.LastSeen_AtDate(strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, timeFormat: timeFormat)).0).0 + dayString = strings.LastSeen_AtDate(strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0).0 } return dayString } -private func humanReadableStringForTimestamp(strings: PresentationStrings, day: RelativeTimestampFormatDay, timeFormat: PresentationTimeFormat, hours: Int32, minutes: Int32) -> String { +private func humanReadableStringForTimestamp(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String { let dayString: String switch day { case .today: - dayString = strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, timeFormat: timeFormat)).0 + dayString = strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 case .yesterday: - dayString = strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, timeFormat: timeFormat)).0 + dayString = strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 } return dayString } -func humanReadableStringForTimestamp(strings: PresentationStrings, timeFormat: PresentationTimeFormat, timestamp: Int32) -> String { +func humanReadableStringForTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, timestamp: Int32) -> String { var t: time_t = time_t(timestamp) var timeinfo: tm = tm() localtime_r(&t, &timeinfo) @@ -104,7 +116,7 @@ func humanReadableStringForTimestamp(strings: PresentationStrings, timeFormat: P localtime_r(&now, &timeinfoNow) if timeinfo.tm_year != timeinfoNow.tm_year { - return "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year))" + return "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat))" } let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday @@ -115,9 +127,9 @@ func humanReadableStringForTimestamp(strings: PresentationStrings, timeFormat: P } else { day = .yesterday } - return humanReadableStringForTimestamp(strings: strings, day: day, timeFormat: timeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min) + return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min) } else { - return "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year))" + return "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat))" } } @@ -159,7 +171,7 @@ func relativeUserPresenceStatus(_ presence: TelegramUserPresence, relativeTo tim } } -func stringForRelativeTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, timeFormat: PresentationTimeFormat) -> String { +func stringForRelativeTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String { var t: time_t = time_t(relativeTimestamp) var timeinfo: tm = tm() localtime_r(&t, &timeinfo) @@ -169,22 +181,22 @@ func stringForRelativeTimestamp(strings: PresentationStrings, relativeTimestamp: localtime_r(&now, &timeinfoNow) if timeinfo.tm_year != timeinfoNow.tm_year { - return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year) + return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat) } let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday if dayDifference > -7 { if dayDifference == 0 { - return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, timeFormat: timeFormat) + return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat) } else { return shortStringForDayOfWeek(strings: strings, day: timeinfo.tm_wday) } } else { - return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1) + return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, dateTimeFormat: dateTimeFormat) } } -func stringForRelativeLiveLocationTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, timeFormat: PresentationTimeFormat) -> String { +func stringForRelativeLiveLocationTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String { let difference = timestamp - relativeTimestamp if difference < 60 { return strings.LiveLocationUpdated_JustNow @@ -206,14 +218,14 @@ func stringForRelativeLiveLocationTimestamp(strings: PresentationStrings, relati let minutes = timeinfo.tm_min if dayDifference == 0 { - return strings.LiveLocationUpdated_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, timeFormat: timeFormat)).0 + return strings.LiveLocationUpdated_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 } else { - return stringForFullDate(timestamp: relativeTimestamp, strings: strings, timeFormat: timeFormat) + return stringForFullDate(timestamp: relativeTimestamp, strings: strings, dateTimeFormat: dateTimeFormat) } } } -func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, timeFormat: PresentationTimeFormat) -> String { +func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String { var t: time_t = time_t(relativeTimestamp) var timeinfo: tm = tm() localtime_r(&t, &timeinfo) @@ -223,22 +235,22 @@ func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationStrings, localtime_r(&now, &timeinfoNow) if timeinfo.tm_year != timeinfoNow.tm_year { - return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year) + return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat) } let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday if dayDifference > -7 { if dayDifference == 0 { - return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, timeFormat: timeFormat) + return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat) } else { return shortStringForDayOfWeek(strings: strings, day: timeinfo.tm_wday) } } else { - return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1) + return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, dateTimeFormat: dateTimeFormat) } } -func stringAndActivityForUserPresence(strings: PresentationStrings, timeFormat: PresentationTimeFormat, presence: TelegramUserPresence, relativeTo timestamp: Int32) -> (String, Bool) { +func stringAndActivityForUserPresence(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, presence: TelegramUserPresence, relativeTo timestamp: Int32) -> (String, Bool) { switch presence.status { case .none: return (strings.LastSeen_ALongTimeAgo, false) @@ -262,7 +274,7 @@ func stringAndActivityForUserPresence(strings: PresentationStrings, timeFormat: localtime_r(&now, &timeinfoNow) if timeinfo.tm_year != timeinfoNow.tm_year { - return (strings.LastSeen_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year)).0, false) + return (strings.LastSeen_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).0, false) } let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday @@ -273,9 +285,9 @@ func stringAndActivityForUserPresence(strings: PresentationStrings, timeFormat: } else { day = .yesterday } - return (stringForUserPresence(strings: strings, day: day, timeFormat: timeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min), false) + return (stringForUserPresence(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min), false) } else { - return (strings.LastSeen_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year)).0, false) + return (strings.LastSeen_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).0, false) } } } diff --git a/TelegramUI/PresentationData.swift b/TelegramUI/PresentationData.swift index 10e149eee5..476dcf4db7 100644 --- a/TelegramUI/PresentationData.swift +++ b/TelegramUI/PresentationData.swift @@ -5,11 +5,22 @@ import TelegramCore import Contacts import AddressBook +public struct PresentationDateTimeFormat: Equatable { + let timeFormat: PresentationTimeFormat + let dateFormat: PresentationDateFormat + let dateSeparator: String +} + public enum PresentationTimeFormat { case regular case military } +public enum PresentationDateFormat { + case monthFirst + case dayFirst +} + public enum PresentationPersonNameOrder { case firstLast case lastFirst @@ -20,22 +31,22 @@ public final class PresentationData: Equatable { public let theme: PresentationTheme public let chatWallpaper: TelegramWallpaper public let fontSize: PresentationFontSize - public let timeFormat: PresentationTimeFormat + public let dateTimeFormat: PresentationDateTimeFormat public let nameDisplayOrder: PresentationPersonNameOrder public let nameSortOrder: PresentationPersonNameOrder - public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, timeFormat: PresentationTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder) { + public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder) { self.strings = strings self.theme = theme self.chatWallpaper = chatWallpaper self.fontSize = fontSize - self.timeFormat = timeFormat + self.dateTimeFormat = dateTimeFormat self.nameDisplayOrder = nameDisplayOrder self.nameSortOrder = nameSortOrder } public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool { - return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.chatWallpaper == rhs.chatWallpaper && lhs.fontSize == rhs.fontSize && lhs.timeFormat == rhs.timeFormat + return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.chatWallpaper == rhs.chatWallpaper && lhs.fontSize == rhs.fontSize && lhs.dateTimeFormat == rhs.dateTimeFormat } } @@ -67,19 +78,46 @@ func dictFromLocalization(_ value: Localization) -> [String: String] { return dict } -private func currentTimeFormat() -> PresentationTimeFormat { +private func currentDateTimeFormat() -> PresentationDateTimeFormat { + let locale = Locale.current let dateFormatter = DateFormatter() - dateFormatter.locale = Locale.current + dateFormatter.locale = locale dateFormatter.dateStyle = .none dateFormatter.timeStyle = .medium dateFormatter.timeZone = TimeZone.current let dateString = dateFormatter.string(from: Date()) + let timeFormat: PresentationTimeFormat if dateString.contains(dateFormatter.amSymbol) || dateString.contains(dateFormatter.pmSymbol) { - return .regular + timeFormat = .regular } else { - return .military + timeFormat = .military } + + let dateFormat: PresentationDateFormat + let dateSeparator: String + if let dateString = DateFormatter.dateFormat(fromTemplate: "MdY", options: 0, locale: locale) { + if dateString.contains(".") { + dateSeparator = "." + } else if dateString.contains("/") { + dateSeparator = "/" + } else if dateString.contains("-") { + dateSeparator = "-" + } else { + dateSeparator = "/" + } + + if dateString.contains("M\(dateSeparator)d") { + dateFormat = .monthFirst + } else { + dateFormat = .dayFirst + } + } else { + dateSeparator = "/" + dateFormat = .dayFirst + } + + return PresentationDateTimeFormat(timeFormat: timeFormat, dateFormat: dateFormat, dateSeparator: dateSeparator) } private func currentPersonNameSortOrder() -> PresentationPersonNameOrder { @@ -230,10 +268,10 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal Signal PresentationData { - let timeFormat = currentTimeFormat() + let dateTimeFormat = currentDateTimeFormat() let nameDisplayOrder = currentPersonNameDisplayOrder() let nameSortOrder = currentPersonNameSortOrder() let themeSettings = PresentationThemeSettings.defaultSettings - return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, fontSize: themeSettings.fontSize, timeFormat: timeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder) + return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder) } diff --git a/TelegramUI/RecentSessionsController.swift b/TelegramUI/RecentSessionsController.swift index ece704095e..3b39454ddc 100644 --- a/TelegramUI/RecentSessionsController.swift +++ b/TelegramUI/RecentSessionsController.swift @@ -68,14 +68,14 @@ private enum RecentSessionsEntryStableId: Hashable { private enum RecentSessionsEntry: ItemListNodeEntry { case currentSessionHeader(PresentationTheme, String) - case currentSession(PresentationTheme, PresentationStrings, RecentAccountSession) + case currentSession(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, RecentAccountSession) case terminateOtherSessions(PresentationTheme, String) case terminateAllWebSessions(PresentationTheme, String) case currentSessionInfo(PresentationTheme, String) case otherSessionsHeader(PresentationTheme, String) - case session(index: Int32, theme: PresentationTheme, strings: PresentationStrings, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool) - case website(index: Int32, theme: PresentationTheme, strings: PresentationStrings, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool) + case session(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool) + case website(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool) var section: ItemListSectionId { switch self { @@ -100,9 +100,9 @@ private enum RecentSessionsEntry: ItemListNodeEntry { return .index(4) case .otherSessionsHeader: return .index(5) - case let .session(_, _, _, session, _, _, _): + case let .session(_, _, _, _, session, _, _, _): return .session(session.hash) - case let .website(_, _, _, website, _, _, _, _): + case let .website(_, _, _, _, website, _, _, _, _): return .session(website.hash) } } @@ -139,20 +139,20 @@ private enum RecentSessionsEntry: ItemListNodeEntry { } else { return false } - case let .currentSession(lhsTheme, lhsStrings, lhsSession): - if case let .currentSession(rhsTheme, rhsStrings, rhsSession) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsSession == rhsSession { + case let .currentSession(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession): + if case let .currentSession(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession { return true } else { return false } - case let .session(lhsIndex, lhsTheme, lhsStrings, lhsSession, lhsEnabled, lhsEditing, lhsRevealed): - if case let .session(rhsIndex, rhsTheme, rhsStrings, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { + case let .session(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed): + if case let .session(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { return true } else { return false } - case let .website(lhsIndex, lhsTheme, lhsStrings, lhsWebsite, lhsPeer, lhsEnabled, lhsEditing, lhsRevealed): - if case let .website(rhsIndex, rhsTheme, rhsStrings, rhsWebsite, rhsPeer, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsWebsite == rhsWebsite, arePeersEqual(lhsPeer, rhsPeer), lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { + case let .website(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsWebsite, lhsPeer, lhsEnabled, lhsEditing, lhsRevealed): + if case let .website(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsWebsite, rhsPeer, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsWebsite == rhsWebsite, arePeersEqual(lhsPeer, rhsPeer), lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { return true } else { return false @@ -170,14 +170,14 @@ private enum RecentSessionsEntry: ItemListNodeEntry { } case .session: switch lhs { - case let .session(lhsIndex, _, _, _, _, _, _): - if case let .session(rhsIndex, _, _, _, _, _, _) = rhs { + case let .session(lhsIndex, _, _, _, _, _, _, _): + if case let .session(rhsIndex, _, _, _, _, _, _, _) = rhs { return lhsIndex <= rhsIndex } else { return false } - case let .website(lhsIndex, _, _, _, _, _, _, _): - if case let .website(rhsIndex, _, _, _, _, _, _, _) = rhs { + case let .website(lhsIndex, _, _, _, _, _, _, _, _): + if case let .website(rhsIndex, _, _, _, _, _, _, _, _) = rhs { return lhsIndex <= rhsIndex } else { return false @@ -192,8 +192,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry { switch self { case let .currentSessionHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) - case let .currentSession(theme, strings, session): - return ItemListRecentSessionItem(theme: theme, strings: strings, session: session, enabled: true, editable: false, editing: false, revealed: false, sectionId: self.section, setSessionIdWithRevealedOptions: { _, _ in + case let .currentSession(theme, strings, dateTimeFormat, session): + return ItemListRecentSessionItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, session: session, enabled: true, editable: false, editing: false, revealed: false, sectionId: self.section, setSessionIdWithRevealedOptions: { _, _ in }, removeSession: { _ in }) case let .terminateOtherSessions(theme, text): @@ -208,14 +208,14 @@ private enum RecentSessionsEntry: ItemListNodeEntry { return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) case let .otherSessionsHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) - case let .session(_, theme, strings, session, enabled, editing, revealed): - return ItemListRecentSessionItem(theme: theme, strings: strings, session: session, enabled: enabled, editable: true, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in + case let .session(_, theme, strings, dateTimeFormat, session, enabled, editing, revealed): + return ItemListRecentSessionItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, session: session, enabled: enabled, editable: true, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in arguments.setSessionIdWithRevealedOptions(previousId, id) }, removeSession: { id in arguments.removeSession(id) }) - case let .website(_, theme, strings, website, peer, enabled, editing, revealed): - return ItemListWebsiteItem(theme: theme, strings: strings, website: website, peer: peer, enabled: enabled, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in + case let .website(_, theme, strings, dateTimeFormat, website, peer, enabled, editing, revealed): + return ItemListWebsiteItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, website: website, peer: peer, enabled: enabled, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in arguments.setSessionIdWithRevealedOptions(previousId, id) }, removeSession: { id in arguments.removeWebSession(id) @@ -286,7 +286,7 @@ private func recentSessionsControllerEntries(presentationData: PresentationData, entries.append(.currentSessionHeader(presentationData.theme, presentationData.strings.AuthSessions_CurrentSession)) if let index = sessions.index(where: { $0.hash == 0 }) { existingSessionIds.insert(sessions[index].hash) - entries.append(.currentSession(presentationData.theme, presentationData.strings, sessions[index])) + entries.append(.currentSession(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, sessions[index])) } if sessions.count > 1 { @@ -302,7 +302,7 @@ private func recentSessionsControllerEntries(presentationData: PresentationData, for i in 0 ..< filteredSessions.count { if !existingSessionIds.contains(sessions[i].hash) { existingSessionIds.insert(sessions[i].hash) - entries.append(.session(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, session: sessions[i], enabled: state.removingSessionId != sessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == sessions[i].hash)) + entries.append(.session(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, session: sessions[i], enabled: state.removingSessionId != sessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == sessions[i].hash)) } } } @@ -330,7 +330,7 @@ private func recentSessionsControllerEntries(presentationData: PresentationData, let website = websites[i] if !existingSessionIds.contains(website.hash) { existingSessionIds.insert(website.hash) - entries.append(.website(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, website: website, peer: peers[website.botId], enabled: state.removingSessionId != website.hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == website.hash)) + entries.append(.website(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, website: website, peer: peers[website.botId], enabled: state.removingSessionId != website.hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == website.hash)) } } } diff --git a/TelegramUI/SecretMediaPreviewController.swift b/TelegramUI/SecretMediaPreviewController.swift index 89386999fd..db8fb19ab5 100644 --- a/TelegramUI/SecretMediaPreviewController.swift +++ b/TelegramUI/SecretMediaPreviewController.swift @@ -379,7 +379,7 @@ public final class SecretMediaPreviewController: ViewController { if let message = message { if self.currentNodeMessageId != message.id { self.currentNodeMessageId = message.id - guard let item = galleryItemForEntry(account: account, theme: self.presentationData.theme, strings: self.presentationData.strings, entry: .MessageEntry(message, false, nil, nil), streamVideos: false, hideControls: true, playbackCompleted: { [weak self] in + guard let item = galleryItemForEntry(account: account, presentationData: self.presentationData, entry: .MessageEntry(message, false, nil, nil), streamVideos: false, hideControls: true, playbackCompleted: { [weak self] in self?.dismiss(forceAway: false) }) else { self._ready.set(.single(true)) @@ -424,7 +424,7 @@ public final class SecretMediaPreviewController: ViewController { self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition) } - override open func dismiss(completion: (() -> Void)? = nil) { + override public func dismiss(completion: (() -> Void)? = nil) { self.presentingViewController?.dismiss(animated: false, completion: completion) } } diff --git a/TelegramUI/SecureIdAuthControllerNode.swift b/TelegramUI/SecureIdAuthControllerNode.swift index 854cc37db5..fa7134b82a 100644 --- a/TelegramUI/SecureIdAuthControllerNode.swift +++ b/TelegramUI/SecureIdAuthControllerNode.swift @@ -363,7 +363,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { current.updateValues(values) contentNode = current } else { - let current = SecureIdAuthListContentNode(theme: self.presentationData.theme, strings: self.presentationData.strings, openField: { [weak self] field in + let current = SecureIdAuthListContentNode(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, openField: { [weak self] field in self?.openListField(field) }, deleteAll: { [weak self] in self?.deleteAllValues() @@ -584,30 +584,63 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { } let completionImpl: (SecureIdDocumentFormRequestedData) -> Void = { [weak self] requestedData in - guard let strongSelf = self, let state = strongSelf.state, let verificationState = state.verificationState, case let .verified(context) = verificationState, let formData = form.formData else { + guard let strongSelf = self, let state = strongSelf.state, let verificationState = state.verificationState, case let .verified(context) = verificationState, let formData = form.formData, let validLayout = strongSelf.validLayout?.0 else { return } - strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: requestedData, primaryLanguageByCountry: encryptedFormData.primaryLanguageByCountry, values: formData.values, updatedValues: { values in + var attachmentType: SecureIdAttachmentMenuType? = nil + var attachmentTarget: SecureIdAddFileTarget? = nil + switch requestedData { + case let .identity(_, document, _, _): + if let document = document { + switch document { + case .idCard, .driversLicense: + attachmentType = .idCard + default: + attachmentType = .generic + } + attachmentTarget = .frontSide(document) + } + case .address: + attachmentType = .multiple + attachmentTarget = .scan + } + + let controller = SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: requestedData, primaryLanguageByCountry: encryptedFormData.primaryLanguageByCountry, values: formData.values, updatedValues: { values in var keys: [SecureIdValueKey] = [] switch requestedData { - case let .identity(details, document, _, _): - if details != nil { - keys.append(.personalDetails) - } - if let document = document { - keys.append(document.valueKey) - } - case let .address(details, document, _): - if details { - keys.append(.address) - } - if let document = document { - keys.append(document.valueKey) - } + case let .identity(details, document, _, _): + if details != nil { + keys.append(.personalDetails) + } + if let document = document { + keys.append(document.valueKey) + } + case let .address(details, document, _): + if details { + keys.append(.address) + } + if let document = document { + keys.append(document.valueKey) + } } updatedValues(keys, values) - }), nil) + }) + + if let attachmentType = attachmentType, let type = attachmentTarget { + presentLegacySecureIdAttachmentMenu(account: strongSelf.account, present: { [weak self] c in + self?.interaction.present(c, nil) + }, validLayout: validLayout, type: attachmentType, recognizeDocumentData: true, completion: { [weak self] resources, recognizedData in + guard let strongSelf = self else { + return + } + + strongSelf.interaction.present(controller, nil) + controller.addDocuments(type: type, resources: resources, recognizedData: recognizedData, removeDocumentId: nil) + }) + } else { + strongSelf.interaction.present(controller, nil) + } } let itemsForField = documentSelectionItemsForField(field: field, strings: self.presentationData.strings) diff --git a/TelegramUI/SecureIdAuthFormFieldNode.swift b/TelegramUI/SecureIdAuthFormFieldNode.swift index 428441b687..36cc2cde98 100644 --- a/TelegramUI/SecureIdAuthFormFieldNode.swift +++ b/TelegramUI/SecureIdAuthFormFieldNode.swift @@ -707,8 +707,10 @@ private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [Se if let value = findValue(values, key: type.valueKey)?.1 { if let error = value.errors[.value(type.valueKey)] { return error - } else if let error = value.errors.first?.value { - return error + } else if let error = value.errors.first { + if case .value = error.key {} else { + return error.value + } } } case let .oneOf(types): @@ -716,8 +718,10 @@ private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [Se if let value = findValue(values, key: type.valueKey)?.1 { if let error = value.errors[.value(type.valueKey)] { return error - } else if let error = value.errors.first?.value { - return error + } else if let error = value.errors.first { + if case .value = error.key {} else { + return error.value + } } } } @@ -737,8 +741,10 @@ private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [Se if let value = findValue(values, key: type.valueKey)?.1 { if let error = value.errors[.value(type.valueKey)] { return error - } else if let error = value.errors.first?.value { - return error + } else if let error = value.errors.first { + if case .value = error.key {} else { + return error.value + } } } case let .oneOf(types): @@ -746,8 +752,10 @@ private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [Se if let value = findValue(values, key: type.valueKey)?.1 { if let error = value.errors[.value(type.valueKey)] { return error - } else if let error = value.errors.first?.value { - return error + } else if let error = value.errors.first { + if case .value = error.key {} else { + return error.value + } } } } diff --git a/TelegramUI/SecureIdAuthListContentNode.swift b/TelegramUI/SecureIdAuthListContentNode.swift index a9102d0d03..07c63cb992 100644 --- a/TelegramUI/SecureIdAuthListContentNode.swift +++ b/TelegramUI/SecureIdAuthListContentNode.swift @@ -7,6 +7,7 @@ import TelegramCore final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode, UITextFieldDelegate { private let theme: PresentationTheme private let strings: PresentationStrings + private let dateTimeFormat: PresentationDateTimeFormat private let fieldBackgroundNode: ASDisplayNode private let fieldNodes: [SecureIdAuthListFieldNode] @@ -18,9 +19,10 @@ final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode, private let requestLayout: () -> Void private var validLayout: CGFloat? - init(theme: PresentationTheme, strings: PresentationStrings, openField: @escaping (SecureIdAuthListContentField) -> Void, deleteAll: @escaping () -> Void, requestLayout: @escaping () -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, openField: @escaping (SecureIdAuthListContentField) -> Void, deleteAll: @escaping () -> Void, requestLayout: @escaping () -> Void) { self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.fieldBackgroundNode = ASDisplayNode() self.fieldBackgroundNode.isLayerBacked = true @@ -96,7 +98,7 @@ final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode, let deleteSpacing: CGFloat = 32.0 contentHeight += deleteSpacing - let (preLayout, apply) = self.deleteItem.update(node: self.deleteNode, theme: self.theme, strings: self.strings, width: width, previousNeighbor: .spacer, nextNeighbor: .spacer, transition: transition) + let (preLayout, apply) = self.deleteItem.update(node: self.deleteNode, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, width: width, previousNeighbor: .spacer, nextNeighbor: .spacer, transition: transition) let deleteHeight = apply(FormControllerItemLayoutParams(maxAligningInset: preLayout.aligningInset)) transition.updateFrame(node: self.deleteNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: deleteHeight))) diff --git a/TelegramUI/SecureIdDocumentFormController.swift b/TelegramUI/SecureIdDocumentFormController.swift index b028a7f554..034985e947 100644 --- a/TelegramUI/SecureIdDocumentFormController.swift +++ b/TelegramUI/SecureIdDocumentFormController.swift @@ -136,4 +136,8 @@ final class SecureIdDocumentFormController: FormController Void + fileprivate let addFile: (SecureIdAddFileTarget) -> Void fileprivate let openDocument: (SecureIdVerificationDocument) -> Void fileprivate let updateText: (SecureIdDocumentFormTextField, String) -> Void fileprivate let selectNextInputItem: (SecureIdDocumentFormEntry) -> Void @@ -56,7 +56,7 @@ final class SecureIdDocumentFormParams { fileprivate let scanPassport: () -> Void fileprivate let deleteValue: () -> Void - fileprivate init(account: Account, context: SecureIdAccessContext, addFile: @escaping (AddFileTarget) -> Void, openDocument: @escaping (SecureIdVerificationDocument) -> Void, updateText: @escaping (SecureIdDocumentFormTextField, String) -> Void, selectNextInputItem: @escaping (SecureIdDocumentFormEntry) -> Void, endEditing: @escaping () -> Void, activateSelection: @escaping (SecureIdDocumentFormSelectionField) -> Void, scanPassport: @escaping () -> Void, deleteValue: @escaping () -> Void) { + fileprivate init(account: Account, context: SecureIdAccessContext, addFile: @escaping (SecureIdAddFileTarget) -> Void, openDocument: @escaping (SecureIdVerificationDocument) -> Void, updateText: @escaping (SecureIdDocumentFormTextField, String) -> Void, selectNextInputItem: @escaping (SecureIdDocumentFormEntry) -> Void, endEditing: @escaping () -> Void, activateSelection: @escaping (SecureIdDocumentFormSelectionField) -> Void, scanPassport: @escaping () -> Void, deleteValue: @escaping () -> Void) { self.account = account self.context = context self.addFile = addFile @@ -397,6 +397,7 @@ extension SecureIdDocumentFormDocumentState { } state.document = document } + self = .identity(state) } } } @@ -948,7 +949,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState { for value in self.previousValues { for error in value.value.errors { switch error.key { - case .value, .field: + case .value(value.key), .field: return .saveNotAvailable case let .file(hash), let .selfie(hash), let .frontSide(hash), let .backSide(hash), let .translationFile(hash): badHashes.insert(hash) @@ -956,6 +957,8 @@ struct SecureIdDocumentFormState: FormControllerInnerState { badFileHashes = hashes case let .translationFiles(hashes): badTranslationHashes = hashes + default: + break } } } @@ -2103,9 +2106,9 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode Void = { [weak controller] in controller?.dismissAnimated() } @@ -2373,11 +2376,11 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { guard let node = node as? SecureIdValueFormFileItemNode else { assertionFailure() return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in return 0.0 }) } - return node.updateInternal(item: self, theme: theme, strings: strings, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) + return node.updateInternal(item: self, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) } } @@ -86,7 +86,7 @@ final class SecureIdValueFormFileItemNode: FormBlockItemNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + override func update(item: SecureIdValueFormFileItem, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { var resourceUpdated = false if let previousItem = self.item { if let previousDocument = previousItem.document, let document = item.document { @@ -152,7 +152,7 @@ final class SecureIdValueFormFileItemNode: FormBlockItemNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + func update(node: ASDisplayNode & FormControllerItemNode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { guard let node = node as? SecureIdValueFormPhoneItemNode else { assertionFailure() return (FormControllerItemPreLayout(aligningInset: 0.0), { _ in return 0.0 }) } - return node.updateInternal(item: self, theme: theme, strings: strings, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) + return node.updateInternal(item: self, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, width: width, previousNeighbor: previousNeighbor, nextNeighbor: nextNeighbor, transition: transition) } } @@ -111,7 +111,7 @@ final class SecureIdValueFormPhoneItemNode: FormBlockItemNode (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { + override func update(item: SecureIdValueFormPhoneItem, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, width: CGFloat, previousNeighbor: FormControllerItemNeighbor, nextNeighbor: FormControllerItemNeighbor, transition: ContainedViewLayoutTransition) -> (FormControllerItemPreLayout, (FormControllerItemLayoutParams) -> CGFloat) { if self.theme !== theme { self.countryButton.setBackgroundImage(countryButtonBackground(color: theme.list.itemBlocksBackgroundColor, separatorColor: theme.list.itemBlocksSeparatorColor), for: []) self.countryButton.setBackgroundImage(countryButtonHighlightedBackground(fillColor: theme.list.itemHighlightedBackgroundColor), for: .highlighted) diff --git a/TelegramUI/SelectivePrivacySettingsPeersController.swift b/TelegramUI/SelectivePrivacySettingsPeersController.swift index 39f990c77b..14a9228529 100644 --- a/TelegramUI/SelectivePrivacySettingsPeersController.swift +++ b/TelegramUI/SelectivePrivacySettingsPeersController.swift @@ -56,7 +56,7 @@ private enum SelectivePrivacyPeersEntryStableId: Hashable { } private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { - case peerItem(Int32, PresentationTheme, PresentationStrings, Peer, ItemListPeerItemEditing, Bool) + case peerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, ItemListPeerItemEditing, Bool) case addItem(PresentationTheme, String, Bool) var section: ItemListSectionId { @@ -70,7 +70,7 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { var stableId: SelectivePrivacyPeersEntryStableId { switch self { - case let .peerItem(_, _, _, peer, _, _): + case let .peerItem(_, _, _, _, peer, _, _): return .peer(peer.id) case .addItem: return .add @@ -79,8 +79,8 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { static func ==(lhs: SelectivePrivacyPeersEntry, rhs: SelectivePrivacyPeersEntry) -> Bool { switch lhs { - case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsEditing, lhsEnabled): - if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsEditing, rhsEnabled) = rhs { + case let .peerItem(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsEditing, lhsEnabled): + if case let .peerItem(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsEditing, rhsEnabled) = rhs { if lhsIndex != rhsIndex { return false } @@ -93,6 +93,9 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if lhsEditing != rhsEditing { return false } @@ -114,9 +117,9 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { static func <(lhs: SelectivePrivacyPeersEntry, rhs: SelectivePrivacyPeersEntry) -> Bool { switch lhs { - case let .peerItem(index, _, _, _, _, _): + case let .peerItem(index, _, _, _, _, _, _): switch rhs { - case let .peerItem(rhsIndex, _, _, _, _, _): + case let .peerItem(rhsIndex, _, _, _, _, _, _): return index < rhsIndex case .addItem: return true @@ -128,8 +131,8 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { func item(_ arguments: SelectivePrivacyPeersControllerArguments) -> ListViewItem { switch self { - case let .peerItem(_, theme, strings, peer, editing, enabled): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { previousId, id in + case let .peerItem(_, theme, strings, dateTimeFormat, peer, editing, enabled): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) }, removePeer: { peerId in arguments.removePeer(peerId) @@ -180,7 +183,7 @@ private func selectivePrivacyPeersControllerEntries(presentationData: Presentati var index: Int32 = 0 for peer in peers { - entries.append(.peerItem(index, presentationData.theme, presentationData.strings, peer, ItemListPeerItemEditing(editable: true, editing: state.editing, revealed: peer.id == state.peerIdWithRevealedOptions), true)) + entries.append(.peerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, ItemListPeerItemEditing(editable: true, editing: state.editing, revealed: peer.id == state.peerIdWithRevealedOptions), true)) index += 1 } diff --git a/TelegramUI/SettingsController.swift b/TelegramUI/SettingsController.swift index 8c5d3e1252..09a0b70a5c 100644 --- a/TelegramUI/SettingsController.swift +++ b/TelegramUI/SettingsController.swift @@ -59,7 +59,7 @@ private enum SettingsSection: Int32 { } private enum SettingsEntry: ItemListNodeEntry { - case userInfo(PresentationTheme, PresentationStrings, Peer?, CachedPeerData?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) + case userInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, CachedPeerData?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?) case setProfilePhoto(PresentationTheme, String) case setUsername(PresentationTheme, String) @@ -133,14 +133,17 @@ private enum SettingsEntry: ItemListNodeEntry { static func ==(lhs: SettingsEntry, rhs: SettingsEntry) -> Bool { switch lhs { - case let .userInfo(lhsTheme, lhsStrings, lhsPeer, lhsCachedData, lhsEditingState, lhsUpdatingImage): - if case let .userInfo(rhsTheme, rhsStrings, rhsPeer, rhsCachedData, rhsEditingState, rhsUpdatingImage) = rhs { + case let .userInfo(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsEditingState, lhsUpdatingImage): + if case let .userInfo(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsEditingState, rhsUpdatingImage) = rhs { if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -258,8 +261,8 @@ private enum SettingsEntry: ItemListNodeEntry { func item(_ arguments: SettingsItemArguments) -> ListViewItem { switch self { - case let .userInfo(theme, strings, peer, cachedData, state, updatingImage): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .settings, peer: peer, presence: TelegramUserPresence(status: .present(until: Int32.max)), cachedData: cachedData, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { _ in + case let .userInfo(theme, strings, dateTimeFormat, peer, cachedData, state, updatingImage): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .settings, peer: peer, presence: TelegramUserPresence(status: .present(until: Int32.max)), cachedData: cachedData, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false), editingNameUpdated: { _ in }, avatarTapped: { arguments.avatarTapAction() }, context: arguments.avatarAndNameInfoContext, updatingImage: updatingImage, action: { @@ -353,7 +356,7 @@ private func settingsEntries(presentationData: PresentationData, state: Settings if let peer = peerViewMainPeer(view) as? TelegramUser { let userInfoState = ItemListAvatarAndNameInfoItemState(editingName: nil, updatingName: nil) - entries.append(.userInfo(presentationData.theme, presentationData.strings, peer, view.cachedData, userInfoState, state.updatingAvatar)) + entries.append(.userInfo(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, view.cachedData, userInfoState, state.updatingAvatar)) if peer.photo.isEmpty { entries.append(.setProfilePhoto(presentationData.theme, presentationData.strings.Settings_SetProfilePhoto)) } diff --git a/TelegramUI/ShareSearchContainerNode.swift b/TelegramUI/ShareSearchContainerNode.swift index c055fa90a9..7597e99ec1 100644 --- a/TelegramUI/ShareSearchContainerNode.swift +++ b/TelegramUI/ShareSearchContainerNode.swift @@ -263,7 +263,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { for renderedPeer in foundLocalPeers { if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != accountPeer.id, peer.id.namespace != Namespaces.Peer.SecretChat { - if !existingPeerIds.contains(peer.id) { + if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) { existingPeerIds.insert(peer.id) var associatedPeer: Peer? if let associatedPeerId = peer.associatedPeerId { @@ -277,7 +277,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { for foundPeer in foundRemotePeers.0 { let peer = foundPeer.peer - if !existingPeerIds.contains(peer.id) { + if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) { existingPeerIds.insert(peer.id) entries.append(ShareSearchPeerEntry(index: index, peer: foundPeer.peer, theme: theme, strings: strings)) index += 1 @@ -286,7 +286,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { for foundPeer in foundRemotePeers.1 { let peer = foundPeer.peer - if !existingPeerIds.contains(peer.id) { + if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) { existingPeerIds.insert(peer.id) entries.append(ShareSearchPeerEntry(index: index, peer: peer, theme: theme, strings: strings)) index += 1 diff --git a/TelegramUI/StorageUsageController.swift b/TelegramUI/StorageUsageController.swift index 4dc54883c9..a148b77313 100644 --- a/TelegramUI/StorageUsageController.swift +++ b/TelegramUI/StorageUsageController.swift @@ -33,7 +33,7 @@ private enum StorageUsageEntry: ItemListNodeEntry { case clearAll(PresentationTheme, String, String, Bool) case peersHeader(PresentationTheme, String) - case peer(Int32, PresentationTheme, PresentationStrings, Peer, Peer?, String) + case peer(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, Peer?, String) var section: ItemListSectionId { switch self { @@ -58,7 +58,7 @@ private enum StorageUsageEntry: ItemListNodeEntry { return 3 case .peersHeader: return 4 - case let .peer(index, _, _, _, _, _): + case let .peer(index, _, _, _, _, _, _): return 5 + index } } @@ -95,8 +95,8 @@ private enum StorageUsageEntry: ItemListNodeEntry { } else { return false } - case let .peer(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsChatPeer, lhsValue): - if case let .peer(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsChatPeer, rhsValue) = rhs { + case let .peer(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsChatPeer, lhsValue): + if case let .peer(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsChatPeer, rhsValue) = rhs { if lhsIndex != rhsIndex { return false } @@ -106,6 +106,9 @@ private enum StorageUsageEntry: ItemListNodeEntry { if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if !arePeersEqual(lhsPeer, rhsPeer) { return false } @@ -142,8 +145,8 @@ private enum StorageUsageEntry: ItemListNodeEntry { return ItemListDisclosureItem(theme: theme, icon: nil, title: text, kind: enabled ? .generic : .disabled, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { arguments.openClearAll() }) - case let .peer(_, theme, strings, peer, chatPeer, value): - return ItemListPeerItem(theme: theme, strings: strings, account: arguments.account, peer: peer, aliasHandling: .threatSelfAsSaved, nameColor: chatPeer == nil ? .primary : .secret, presence: nil, text: .none, label: .disclosure(value), editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: { + case let .peer(_, theme, strings, dateTimeFormat, peer, chatPeer, value): + return ItemListPeerItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, account: arguments.account, peer: peer, aliasHandling: .threatSelfAsSaved, nameColor: chatPeer == nil ? .primary : .secret, presence: nil, text: .none, label: .disclosure(value), editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: { let resolvedPeer = chatPeer ?? peer arguments.openPeerMedia(resolvedPeer.id) }, setPeerIdWithRevealedOptions: { previousId, id in @@ -203,7 +206,7 @@ private func storageUsageControllerEntries(presentationData: PresentationData, c chatPeer = mainPeer mainPeer = associatedPeer } - entries.append(.peer(index, presentationData.theme, presentationData.strings, mainPeer, chatPeer, dataSizeString(Int(size)))) + entries.append(.peer(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, mainPeer, chatPeer, dataSizeString(Int(size)))) index += 1 } } diff --git a/TelegramUI/StringForMessageTimestampStatus.swift b/TelegramUI/StringForMessageTimestampStatus.swift index 0b491cc716..fcebfcb945 100644 --- a/TelegramUI/StringForMessageTimestampStatus.swift +++ b/TelegramUI/StringForMessageTimestampStatus.swift @@ -7,8 +7,8 @@ enum MessageTimestampStatusFormat { case minimal } -func stringForMessageTimestampStatus(message: Message, timeFormat: PresentationTimeFormat, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular) -> String { - var dateText = stringForMessageTimestamp(timestamp: message.timestamp, timeFormat: timeFormat) +func stringForMessageTimestampStatus(message: Message, dateTimeFormat: PresentationDateTimeFormat, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular) -> String { + var dateText = stringForMessageTimestamp(timestamp: message.timestamp, dateTimeFormat: dateTimeFormat) var authorTitle: String? if let author = message.author as? TelegramUser { diff --git a/TelegramUI/ThemeAutoNightSettingsController.swift b/TelegramUI/ThemeAutoNightSettingsController.swift index faddbe2088..58b456a10e 100644 --- a/TelegramUI/ThemeAutoNightSettingsController.swift +++ b/TelegramUI/ThemeAutoNightSettingsController.swift @@ -256,7 +256,7 @@ private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry { } } -private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, strings: PresentationStrings, switchSetting: AutomaticThemeSwitchSetting, timeFormat: PresentationTimeFormat) -> [ThemeAutoNightSettingsControllerEntry] { +private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, strings: PresentationStrings, switchSetting: AutomaticThemeSwitchSetting, dateTimeFormat: PresentationDateTimeFormat) -> [ThemeAutoNightSettingsControllerEntry] { var entries: [ThemeAutoNightSettingsControllerEntry] = [] let activeTriggerMode: TriggerMode @@ -287,11 +287,11 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s case let .automatic(_, _, sunset, sunrise, localizedName): entries.append(.timeBasedAutomaticLocationValue(theme, strings.AutoNightTheme_UpdateLocation, localizedName)) if sunset != 0 || sunrise != 0 { - entries.append(.settingInfo(theme, strings.AutoNightTheme_LocationHelp(stringForMessageTimestamp(timestamp: sunset, timeFormat: timeFormat, local: false), stringForMessageTimestamp(timestamp: sunrise, timeFormat: timeFormat, local: false)).0)) + entries.append(.settingInfo(theme, strings.AutoNightTheme_LocationHelp(stringForMessageTimestamp(timestamp: sunset, dateTimeFormat: dateTimeFormat, local: false), stringForMessageTimestamp(timestamp: sunrise, dateTimeFormat: dateTimeFormat, local: false)).0)) } case let .manual(fromSeconds, toSeconds): - entries.append(.timeBasedManualFrom(theme, strings.AutoNightTheme_ScheduledFrom, stringForMessageTimestamp(timestamp: fromSeconds, timeFormat: timeFormat, local: false))) - entries.append(.timeBasedManualTo(theme, strings.AutoNightTheme_ScheduledTo, stringForMessageTimestamp(timestamp: toSeconds, timeFormat: timeFormat, local: false))) + entries.append(.timeBasedManualFrom(theme, strings.AutoNightTheme_ScheduledFrom, stringForMessageTimestamp(timestamp: fromSeconds, dateTimeFormat: dateTimeFormat, local: false))) + entries.append(.timeBasedManualTo(theme, strings.AutoNightTheme_ScheduledTo, stringForMessageTimestamp(timestamp: toSeconds, dateTimeFormat: dateTimeFormat, local: false))) } case let .brightness(threshold): entries.append(.settingsHeader(theme, strings.AutoNightTheme_AutomaticSection)) @@ -536,7 +536,7 @@ public func themeAutoNightSettingsController(account: Account) -> ViewController let settings = (preferences.values[themeSettingsKey] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.AutoNightTheme_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) - let listState = ItemListNodeState(entries: themeAutoNightSettingsControllerEntries(theme: presentationData.theme, strings: presentationData.strings, switchSetting: stagingSettings ?? settings.automaticThemeSwitchSetting, timeFormat: presentationData.timeFormat), style: .blocks, animateChanges: false) + let listState = ItemListNodeState(entries: themeAutoNightSettingsControllerEntries(theme: presentationData.theme, strings: presentationData.strings, switchSetting: stagingSettings ?? settings.automaticThemeSwitchSetting, dateTimeFormat: presentationData.dateTimeFormat), style: .blocks, animateChanges: false) return (controllerState, (listState, arguments)) } diff --git a/TelegramUI/ThemeSettingsChatPreviewItem.swift b/TelegramUI/ThemeSettingsChatPreviewItem.swift index d2246f7935..1c4f814aae 100644 --- a/TelegramUI/ThemeSettingsChatPreviewItem.swift +++ b/TelegramUI/ThemeSettingsChatPreviewItem.swift @@ -13,9 +13,9 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem { let sectionId: ItemListSectionId let fontSize: PresentationFontSize let wallpaper: TelegramWallpaper - let timeFormat: PresentationTimeFormat + let dateTimeFormat: PresentationDateTimeFormat - init(account: Account, theme: PresentationTheme, componentTheme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, wallpaper: TelegramWallpaper, timeFormat: PresentationTimeFormat) { + init(account: Account, theme: PresentationTheme, componentTheme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat) { self.account = account self.theme = theme self.componentTheme = componentTheme @@ -23,7 +23,7 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem { self.sectionId = sectionId self.fontSize = fontSize self.wallpaper = wallpaper - self.timeFormat = timeFormat + self.dateTimeFormat = dateTimeFormat } func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { @@ -149,7 +149,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: item.strings.Appearance_PreviewReplyText, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) - let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, timeFormat: item.timeFormat) + let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, dateTimeFormat: item.dateTimeFormat) let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, account: item.account, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true) let item1: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, account: item.account, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true) diff --git a/TelegramUI/ThemeSettingsController.swift b/TelegramUI/ThemeSettingsController.swift index 1462b24681..f10bafe626 100644 --- a/TelegramUI/ThemeSettingsController.swift +++ b/TelegramUI/ThemeSettingsController.swift @@ -32,7 +32,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { case fontSizeHeader(PresentationTheme, String) case fontSize(PresentationTheme, PresentationFontSize) case chatPreviewHeader(PresentationTheme, String) - case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationTimeFormat) + case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat) case wallpaper(PresentationTheme, String) case accentColor(PresentationTheme, String, Int32) case autoNightTheme(PresentationTheme, String, String) @@ -146,8 +146,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { }) case let .chatPreviewHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) - case let .chatPreview(theme, componentTheme, wallpaper, fontSize, strings, timeFormat): - return ThemeSettingsChatPreviewItem(account: arguments.account, theme: theme, componentTheme: componentTheme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, timeFormat: timeFormat) + case let .chatPreview(theme, componentTheme, wallpaper, fontSize, strings, dateTimeFormat): + return ThemeSettingsChatPreviewItem(account: arguments.account, theme: theme, componentTheme: componentTheme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat) case let .wallpaper(theme, text): return ItemListDisclosureItem(theme: theme, title: text, label: "", sectionId: self.section, style: .blocks, action: { arguments.openWallpaperSettings() @@ -170,13 +170,13 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { } } -private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, timeFormat: PresentationTimeFormat) -> [ThemeSettingsControllerEntry] { +private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat) -> [ThemeSettingsControllerEntry] { var entries: [ThemeSettingsControllerEntry] = [] entries.append(.fontSizeHeader(presentationData.theme, strings.Appearance_TextSize)) entries.append(.fontSize(presentationData.theme, fontSize)) entries.append(.chatPreviewHeader(presentationData.theme, strings.Appearance_Preview)) - entries.append(.chatPreview(presentationData.theme, theme, wallpaper, fontSize, presentationData.strings, timeFormat)) + entries.append(.chatPreview(presentationData.theme, theme, wallpaper, fontSize, presentationData.strings, dateTimeFormat)) entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground)) if theme.name == .builtin(.day) { entries.append(.accentColor(presentationData.theme, strings.Appearance_AccentColor, themeAccentColor ?? defaultDayAccentColor)) @@ -255,7 +255,7 @@ public func themeSettingsController(account: Account) -> ViewController { let fontSize: PresentationFontSize let wallpaper: TelegramWallpaper let strings: PresentationStrings - let timeFormat: PresentationTimeFormat + let dateTimeFormat: PresentationDateTimeFormat let settings = (preferences.values[themeSettingsKey] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings switch settings.theme { @@ -280,10 +280,10 @@ public func themeSettingsController(account: Account) -> ViewController { strings = defaultPresentationStrings } - timeFormat = .regular + dateTimeFormat = presentationData.dateTimeFormat let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: strings.Common_Back)) - let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeAccentColor: settings.themeAccentColor, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, timeFormat: timeFormat), style: .blocks, animateChanges: false) + let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeAccentColor: settings.themeAccentColor, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat), style: .blocks, animateChanges: false) if previousTheme.swap(theme)?.name != theme.name { presentControllerImpl?(ThemeSettingsCrossfadeController()) diff --git a/TelegramUI/UniversalVideoCalleryItem.swift b/TelegramUI/UniversalVideoCalleryItem.swift index 5a8199fff3..0962ceacfb 100644 --- a/TelegramUI/UniversalVideoCalleryItem.swift +++ b/TelegramUI/UniversalVideoCalleryItem.swift @@ -13,8 +13,7 @@ enum UniversalVideoGalleryItemContentInfo { class UniversalVideoGalleryItem: GalleryItem { let account: Account - let theme: PresentationTheme - let strings: PresentationStrings + let presentationData: PresentationData let content: UniversalVideoContent let originData: GalleryItemOriginData? let indexData: GalleryItemIndexData? @@ -23,10 +22,9 @@ class UniversalVideoGalleryItem: GalleryItem { let hideControls: Bool let playbackCompleted: () -> Void - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, content: UniversalVideoContent, originData: GalleryItemOriginData?, indexData: GalleryItemIndexData?, contentInfo: UniversalVideoGalleryItemContentInfo?, caption: String, hideControls: Bool = false, playbackCompleted: @escaping () -> Void = {}) { + init(account: Account, presentationData: PresentationData, content: UniversalVideoContent, originData: GalleryItemOriginData?, indexData: GalleryItemIndexData?, contentInfo: UniversalVideoGalleryItemContentInfo?, caption: String, hideControls: Bool = false, playbackCompleted: @escaping () -> Void = {}) { self.account = account - self.theme = theme - self.strings = strings + self.presentationData = presentationData self.content = content self.originData = originData self.indexData = indexData @@ -37,10 +35,10 @@ class UniversalVideoGalleryItem: GalleryItem { } func node() -> GalleryItemNode { - let node = UniversalVideoGalleryItemNode(account: self.account, theme: self.theme, strings: self.strings) + let node = UniversalVideoGalleryItemNode(account: self.account, presentationData: self.presentationData) if let indexData = self.indexData { - node._title.set(.single("\(indexData.position + 1) \(self.strings.Common_of) \(indexData.totalCount)")) + node._title.set(.single("\(indexData.position + 1) \(self.presentationData.strings.Common_of) \(indexData.totalCount)")) } node.setupItem(self) @@ -51,7 +49,7 @@ class UniversalVideoGalleryItem: GalleryItem { func updateNode(node: GalleryItemNode) { if let node = node as? UniversalVideoGalleryItemNode { if let indexData = self.indexData { - node._title.set(.single("\(indexData.position + 1) \(self.strings.Common_of) \(indexData.totalCount)")) + node._title.set(.single("\(indexData.position + 1) \(self.presentationData.strings.Common_of) \(indexData.totalCount)")) } node.setupItem(self) @@ -164,12 +162,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { var playbackCompleted: (() -> Void)? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + init(account: Account, presentationData: PresentationData) { self.account = account - self.strings = strings + self.strings = presentationData.strings self.scrubberView = ChatVideoGalleryItemScrubberView() - self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, theme: theme, strings: strings) + self.footerContentNode = ChatItemGalleryFooterContentNode(account: account, presentationData: presentationData) self.footerContentNode.scrubberView = self.scrubberView self.statusButtonNode = HighlightableButtonNode() @@ -254,7 +252,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if let content = item.content as? NativeVideoContent { isAnimated = content.fileReference.media.isAnimated } else if let _ = item.content as? SystemVideoContent { - self._title.set(.single(item.strings.Message_Video)) + self._title.set(.single(item.presentationData.strings.Message_Video)) } if let videoNode = self.videoNode { diff --git a/TelegramUI/UserInfoController.swift b/TelegramUI/UserInfoController.swift index a71c0a26d6..6535ab0777 100644 --- a/TelegramUI/UserInfoController.swift +++ b/TelegramUI/UserInfoController.swift @@ -78,8 +78,19 @@ private enum UserInfoEntryTag { case username } +private func areMessagesEqual(_ lhsMessage: Message, _ rhsMessage: Message) -> Bool { + if lhsMessage.stableVersion != rhsMessage.stableVersion { + return false + } + if lhsMessage.id != rhsMessage.id || lhsMessage.flags != rhsMessage.flags { + return false + } + return true +} + private enum UserInfoEntry: ItemListNodeEntry { - case info(PresentationTheme, PresentationStrings, peer: Peer?, presence: PeerPresence?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, displayCall: Bool) + case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer?, presence: PeerPresence?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, displayCall: Bool) + case calls(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, messages: [Message]) case about(PresentationTheme, String, String) case phoneNumber(PresentationTheme, Int, String, String, Bool) case userName(PresentationTheme, String, String) @@ -103,7 +114,7 @@ private enum UserInfoEntry: ItemListNodeEntry { var section: ItemListSectionId { switch self { - case .info, .about, .phoneNumber, .userName: + case .info, .calls, .about, .phoneNumber, .userName: return UserInfoSection.info.rawValue case .sendMessage, .addContact, .shareContact, .shareMyContact, .startSecretChat, .botAddToGroup, .botShare: return UserInfoSection.actions.rawValue @@ -122,15 +133,18 @@ private enum UserInfoEntry: ItemListNodeEntry { static func ==(lhs: UserInfoEntry, rhs: UserInfoEntry) -> Bool { switch lhs { - case let .info(lhsTheme, lhsStrings, lhsPeer, lhsPresence, lhsCachedData, lhsState, lhsDisplayCall): + case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsPresence, lhsCachedData, lhsState, lhsDisplayCall): switch rhs { - case let .info(rhsTheme, rhsStrings, rhsPeer, rhsPresence, rhsCachedData, rhsState, rhsDisplayCall): + case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsPresence, rhsCachedData, rhsState, rhsDisplayCall): if lhsTheme !== rhsTheme { return false } if lhsStrings !== rhsStrings { return false } + if lhsDateTimeFormat != rhsDateTimeFormat { + return false + } if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { if !lhsPeer.isEqual(rhsPeer) { return false @@ -162,6 +176,20 @@ private enum UserInfoEntry: ItemListNodeEntry { default: return false } + case let .calls(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsMessages): + if case let .calls(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsMessages) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat { + if lhsMessages.count != rhsMessages.count { + return false + } + for i in 0 ..< lhsMessages.count { + if !areMessagesEqual(lhsMessages[i], rhsMessages[i]) { + return false + } + } + return true + } else { + return false + } case let .about(lhsTheme, lhsText, lhsValue): if case let .about(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { return true @@ -289,8 +317,10 @@ private enum UserInfoEntry: ItemListNodeEntry { switch self { case .info: return 0 + case .calls: + return 1 case let .phoneNumber(_, index, _, _, _): - return 1 + index + return 2 + index case .about: return 999 case .userName: @@ -338,14 +368,16 @@ private enum UserInfoEntry: ItemListNodeEntry { func item(_ arguments: UserInfoControllerArguments) -> ListViewItem { switch self { - case let .info(theme, strings, peer, presence, cachedData, state, displayCall): - return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: presence, cachedData: cachedData, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in + case let .info(theme, strings, dateTimeFormat, peer, presence, cachedData, state, displayCall): + return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, cachedData: cachedData, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { arguments.tapAvatarAction() }, context: arguments.avatarAndNameInfoContext, call: displayCall ? { arguments.call() } : nil) + case let .calls(theme, strings, dateTimeFormat, messages): + return ItemListCallListItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, messages: messages, sectionId: self.section, style: .plain) case let .about(theme, text, value): return ItemListTextWithLabelItem(theme: theme, label: text, text: value, enabledEntitiyTypes: [], multiline: true, sectionId: self.section, action: { arguments.displayAboutContextMenu(value) @@ -510,7 +542,7 @@ private func stringForBlockAction(strings: PresentationStrings, action: Destruct } } -private func userInfoEntries(account: Account, presentationData: PresentationData, view: PeerView, deviceContacts: [(DeviceContactStableId, DeviceContactBasicData)], state: UserInfoState, peerChatState: PostboxCoding?, globalNotificationSettings: GlobalNotificationSettings) -> [UserInfoEntry] { +private func userInfoEntries(account: Account, presentationData: PresentationData, view: PeerView, deviceContacts: [(DeviceContactStableId, DeviceContactBasicData)], mode: UserInfoControllerMode, state: UserInfoState, peerChatState: PostboxCoding?, globalNotificationSettings: GlobalNotificationSettings) -> [UserInfoEntry] { var entries: [UserInfoEntry] = [] guard let peer = view.peers[view.peerId], let user = peerViewMainPeer(view) as? TelegramUser else { @@ -533,7 +565,11 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat callsAvailable = cachedUserData.callsAvailable } - entries.append(UserInfoEntry.info(presentationData.theme, presentationData.strings, peer: user, presence: view.peerPresences[user.id], cachedData: view.cachedData, state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), displayCall: user.botInfo == nil && callsAvailable)) + entries.append(UserInfoEntry.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: user, presence: view.peerPresences[user.id], cachedData: view.cachedData, state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), displayCall: user.botInfo == nil && callsAvailable)) + + if case let .calls(messages) = mode, !isEditing { + entries.append(UserInfoEntry.calls(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, messages: messages)) + } if let phoneNumber = user.phone, !phoneNumber.isEmpty { let formattedNumber = formatPhoneNumber(phoneNumber) @@ -682,7 +718,12 @@ private func getUserPeer(postbox: Postbox, peerId: PeerId) -> Signal ViewController { +public enum UserInfoControllerMode { + case generic + case calls(messages: [Message]) +} + +public func userInfoController(account: Account, peerId: PeerId, mode: UserInfoControllerMode = .generic) -> ViewController { let statePromise = ValuePromise(UserInfoState(), ignoreRepeated: true) let stateValue = Atomic(value: UserInfoState()) let updateState: ((UserInfoState) -> UserInfoState) -> Void = { f in @@ -1112,7 +1153,7 @@ public func userInfoController(account: Account, peerId: PeerId) -> ViewControll } let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.UserInfo_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: nil) - let listState = ItemListNodeState(entries: userInfoEntries(account: account, presentationData: presentationData, view: view, deviceContacts: deviceContacts, state: state, peerChatState: (combinedView.views[.peerChatState(peerId: peerId)] as? PeerChatStateView)?.chatState, globalNotificationSettings: globalNotificationSettings), style: .plain) + let listState = ItemListNodeState(entries: userInfoEntries(account: account, presentationData: presentationData, view: view, deviceContacts: deviceContacts, mode: mode, state: state, peerChatState: (combinedView.views[.peerChatState(peerId: peerId)] as? PeerChatStateView)?.chatState, globalNotificationSettings: globalNotificationSettings), style: .plain) return (controllerState, (listState, arguments)) } |> afterDisposed { diff --git a/TelegramUI/WebEmbedPlayerNode.swift b/TelegramUI/WebEmbedPlayerNode.swift index b83fc20ebb..6a1a177b9b 100644 --- a/TelegramUI/WebEmbedPlayerNode.swift +++ b/TelegramUI/WebEmbedPlayerNode.swift @@ -32,6 +32,12 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate { return self.statusValue.get() } + private var readyValue: ValuePromise = ValuePromise(false) + + var ready: Signal { + return self.readyValue.get() + } + private let impl: WebEmbedImplementation private let intrinsicDimensions: CGSize @@ -84,9 +90,11 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate { }, updateStatus: { [weak self] status in if let strongSelf = self { strongSelf.statusValue.set(status) - } + } }, onPlaybackStarted: { [weak self] in - + if let strongSelf = self { + strongSelf.readyValue.set(true) + } }) } diff --git a/TelegramUI/WebEmbedVideoContent.swift b/TelegramUI/WebEmbedVideoContent.swift index 0b058e1b4c..8a140b5a27 100644 --- a/TelegramUI/WebEmbedVideoContent.swift +++ b/TelegramUI/WebEmbedVideoContent.swift @@ -35,9 +35,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte private let intrinsicDimensions: CGSize private let approximateDuration: Int32 - private let audioSessionDisposable = MetaDisposable() - private var hasAudioSession = false - private let playbackCompletedListeners = Bag<() -> Void>() private var initializedStatus = false @@ -66,8 +63,7 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte private let imageNode: TransformImageNode private let playerNode: WebEmbedPlayerNode - private var loadProgressDisposable: Disposable? - private var statusDisposable: Disposable? + private var readyDisposable = MetaDisposable() init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent) { self.webpageContent = webpageContent @@ -81,12 +77,13 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte self.imageNode = TransformImageNode() + let embedImpl: WebEmbedImplementation if let embedUrl = webpageContent.embedUrl { - let impl = webEmbedImplementation(embedUrl: embedUrl, url: webpageContent.url) - self.playerNode = WebEmbedPlayerNode(impl: impl, intrinsicDimensions: self.intrinsicDimensions) + embedImpl = webEmbedImplementation(embedUrl: embedUrl, url: webpageContent.url) + self.playerNode = WebEmbedPlayerNode(impl: embedImpl, intrinsicDimensions: self.intrinsicDimensions) } else { - let impl = GenericEmbedImplementation(url: webpageContent.url) - self.playerNode = WebEmbedPlayerNode(impl: impl, intrinsicDimensions: self.intrinsicDimensions) + embedImpl = GenericEmbedImplementation(url: webpageContent.url) + self.playerNode = WebEmbedPlayerNode(impl: embedImpl, intrinsicDimensions: self.intrinsicDimensions) } super.init() @@ -105,48 +102,17 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte self._ready.set(.single(Void())) } self._status.set(self.playerNode.status) - -// -// self._status.set(MediaPlayerStatus(generationTimestamp: 0.0, duration: Double(self.approximateDuration), dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: self.seekId, status: .buffering(initial: true, whilePlaying: true))) -// -// let stateSignal = self.playerView.stateSignal()! -// self.statusDisposable = (Signal { subscriber in -// let innerDisposable = stateSignal.start(next: { next in -// if let next = next as? TGEmbedPlayerState { -// let status: MediaPlayerPlaybackStatus -// if next.playing { -// status = .playing -// } else if next.buffering { -// status = .buffering(initial: false, whilePlaying: next.playing) -// } else { -// status = .paused -// } -// subscriber.putNext(MediaPlayerStatus(generationTimestamp: 0.0, duration: next.duration, dimensions: CGSize(), timestamp: max(0.0, next.position), baseRate: 1.0, seekId: 0, status: status)) -// } -// }) -// return ActionDisposable { -// innerDisposable?.dispose() -// } -// } |> deliverOnMainQueue).start(next: { [weak self] value in -// if let strongSelf = self { -// if !strongSelf.initializedStatus { -// if case .paused = value.status { -// return -// } -// } -// strongSelf.initializedStatus = true -// strongSelf._status.set(MediaPlayerStatus(generationTimestamp: value.generationTimestamp, duration: value.duration, dimensions: CGSize(), timestamp: value.timestamp, baseRate: 1.0, seekId: strongSelf.seekId, status: value.status)) -// } -// }) -// -//>>>>>>> 368a96b2910b01bf361ed88aefd8662804f55f0a self._bufferingStatus.set(.single(nil)) + + self.readyDisposable.set(self.playerNode.ready.start(next: { [weak self] ready in + if ready { + self?.imageNode.isHidden = true + } + }, error: { _ in }, completed: {})) } deinit { - self.audioSessionDisposable.dispose() - self.loadProgressDisposable?.dispose() - self.statusDisposable?.dispose() + self.readyDisposable.dispose() } func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { diff --git a/TelegramUI/YoutubeEmbedImplementation.swift b/TelegramUI/YoutubeEmbedImplementation.swift index 43b75835c8..59769fa3ad 100644 --- a/TelegramUI/YoutubeEmbedImplementation.swift +++ b/TelegramUI/YoutubeEmbedImplementation.swift @@ -94,11 +94,11 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { private var started: Bool = false private var ignorePosition: Int? - enum PlaybackDelay { - case None - case AfterPositionUpdates(count: Int) + private enum PlaybackDelay { + case none + case afterPositionUpdates(count: Int) } - private var playbackDelay = PlaybackDelay.None + private var playbackDelay = PlaybackDelay.none init(videoId: String, timestamp: Int = 0) { self.videoId = videoId @@ -162,7 +162,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { func play() { guard ready else { - self.playbackDelay = .AfterPositionUpdates(count: 2) + self.playbackDelay = .afterPositionUpdates(count: 2) return } @@ -270,20 +270,20 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { } } - if case let .AfterPositionUpdates(count) = self.playbackDelay { + if case let .afterPositionUpdates(count) = self.playbackDelay { if count == 1 { self.ready = true - self.playbackDelay = .None + self.playbackDelay = .none self.play() } else { - self.playbackDelay = .AfterPositionUpdates(count: count - 1) + self.playbackDelay = .afterPositionUpdates(count: count - 1) } } case "onReady": self.ready = true - if case .AfterPositionUpdates(_) = self.playbackDelay { - self.playbackDelay = .None + if case .afterPositionUpdates(_) = self.playbackDelay { + self.playbackDelay = .none self.play() } @@ -294,6 +294,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { if !self.started { self.play() } + self.onPlaybackStarted?() }) } default: