mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit '555b1d8ede' [skip ci]
This commit is contained in:
commit
aa366dee27
129 changed files with 5118 additions and 4369 deletions
|
|
@ -31,7 +31,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
|||
}
|
||||
|
||||
if !isMuted && hasUnread {
|
||||
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(index.messageIndex.id.peerId), anchor: .upperBound, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, orderStatistics: .combinedLocation)
|
||||
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(index.messageIndex.id.peerId), anchor: .upperBound, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, excludeNamespaces: [Namespaces.Message.CloudScheduled], orderStatistics: .combinedLocation)
|
||||
|> take(1)
|
||||
|> map { view -> [INMessage] in
|
||||
var messages: [INMessage] = []
|
||||
|
|
|
|||
22
Telegram-iOS.xcworkspace/contents.xcworkspacedata
generated
22
Telegram-iOS.xcworkspace/contents.xcworkspacedata
generated
|
|
@ -38,10 +38,10 @@
|
|||
location = "group:submodules/SaveToCameraRoll/SaveToCameraRoll_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TelegramNotices/TelegramNotices_Xcode.xcodeproj">
|
||||
location = "group:submodules/TelegramNotices/TelegramNotices_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TelegramPermissions/TelegramPermissions_Xcode.xcodeproj">
|
||||
location = "group:submodules/TelegramPermissions/TelegramPermissions_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<Group
|
||||
location = "container:"
|
||||
|
|
@ -50,10 +50,10 @@
|
|||
location = "group:submodules/ImageBlur/ImageBlur_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TinyThumbnail/TinyThumbnail_Xcode.xcodeproj">
|
||||
location = "group:submodules/TinyThumbnail/TinyThumbnail_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/ImageTransparency/ImageTransparency_Xcode.xcodeproj">
|
||||
location = "group:submodules/ImageTransparency/ImageTransparency_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
</Group>
|
||||
</Group>
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
location = "group:submodules/MediaResources/MediaResources_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/PhotoResources/PhotoResources_Xcode.xcodeproj">
|
||||
location = "group:submodules/PhotoResources/PhotoResources_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/StickerResources/StickerResources_Xcode.xcodeproj">
|
||||
|
|
@ -123,13 +123,13 @@
|
|||
location = "container:"
|
||||
name = "Gestures">
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TouchDownGesture/TouchDownGesture_Xcode.xcodeproj">
|
||||
location = "group:submodules/TouchDownGesture/TouchDownGesture_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/SwipeToDismissGesture/SwipeToDismissGesture_Xcode.xcodeproj">
|
||||
location = "group:submodules/SwipeToDismissGesture/SwipeToDismissGesture_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/DirectionalPanGesture/DirectionalPanGesture_Xcode.xcodeproj">
|
||||
location = "group:submodules/DirectionalPanGesture/DirectionalPanGesture_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
</Group>
|
||||
<Group
|
||||
|
|
@ -176,7 +176,7 @@
|
|||
</FileRef>
|
||||
</Group>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/AlertUI/AlertUI_Xcode.xcodeproj">
|
||||
location = "group:submodules/AlertUI/AlertUI_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/RadialStatusNode/RadialStatusNode_Xcode.xcodeproj">
|
||||
|
|
@ -239,10 +239,10 @@
|
|||
location = "group:submodules/ContextUI/ContextUI_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/ComposePollUI/ComposePollUI_Xcode.xcodeproj">
|
||||
location = "group:submodules/ComposePollUI/ComposePollUI_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/UndoUI/UndoUI_Xcode.xcodeproj">
|
||||
location = "group:submodules/UndoUI/UndoUI_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
</Group>
|
||||
<FileRef
|
||||
|
|
|
|||
|
|
@ -4,5 +4,7 @@
|
|||
<dict>
|
||||
<key>BuildSystemType</key>
|
||||
<string>Latest</string>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -33,5 +33,7 @@
|
|||
<string>merchant.privatbank.test.telergramios</string>
|
||||
<string>merchant.privatbank.prod.telergram</string>
|
||||
</array>
|
||||
<key>com.apple.developer.carplay-messaging</key><true/>
|
||||
<key>com.apple.developer.carplay-calling</key><true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -4497,6 +4497,7 @@ Any member of this group will be able to see messages in the channel.";
|
|||
"Group.EditAdmin.RankAdminPlaceholder" = "admin";
|
||||
|
||||
"Conversation.SendMessage.SendSilently" = "Send Without Sound";
|
||||
"Conversation.SendMessage.ScheduleMessage" = "Schedule Message";
|
||||
|
||||
"Appearance.ThemeCarouselTintedNight" = "Tinted Night";
|
||||
"Appearance.ThemeCarouselNewNight" = "Night";
|
||||
|
|
@ -4590,3 +4591,30 @@ Any member of this group will be able to see messages in the channel.";
|
|||
"VoiceOver.MessageContextOpenMessageMenu" = "Open message menu";
|
||||
|
||||
"ProxyServer.VoiceOver.Active" = "Active";
|
||||
|
||||
"Conversation.ScheduleMessage.Title" = "Schedule Message";
|
||||
"Conversation.ScheduleMessage.SendToday" = "Send today at %@";
|
||||
"Conversation.ScheduleMessage.SendTomorrow" = "Send tomorrow at %@";
|
||||
"Conversation.ScheduleMessage.SendOn" = "Send on %@ at %@";
|
||||
|
||||
"Conversation.SetReminder.Title" = "Set a Reminder";
|
||||
"Conversation.SetReminder.RemindToday" = "Remind today at %@";
|
||||
"Conversation.SetReminder.RemindTomorrow" = "Remind tomorrow at %@";
|
||||
"Conversation.SetReminder.RemindOn" = "Remind on %@ at %@";
|
||||
|
||||
"ScheduledMessages.Title" = "Scheduled Messages";
|
||||
"ScheduledMessages.RemindersTitle" = "Reminders";
|
||||
"ScheduledMessages.ScheduledDate" = "Scheduled for %@";
|
||||
"ScheduledMessages.SendNow" = "Send Now";
|
||||
"ScheduledMessages.EditTime" = "Reschedule";
|
||||
"ScheduledMessages.ClearAll" = "Clear All";
|
||||
"ScheduledMessages.Delete" = "Delete";
|
||||
|
||||
"Conversation.SendMessage.SetReminder" = "Set a Reminder";
|
||||
|
||||
"Conversation.SelectedMessages_1" = "%@ Message Selected";
|
||||
"Conversation.SelectedMessages_2" = "%@ Messages Selected";
|
||||
"Conversation.SelectedMessages_3_10" = "%@ Messages Selected";
|
||||
"Conversation.SelectedMessages_any" = "%@ Messages Selected";
|
||||
"Conversation.SelectedMessages_many" = "%@ Messages Selected";
|
||||
"Conversation.SelectedMessages_0" = "%@ Messages Selected";
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
D0879A4A22F6584B00C4D6B3 /* SharedMediaPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879A4922F6584B00C4D6B3 /* SharedMediaPlayer.swift */; };
|
||||
D0879A4C22F65A7A00C4D6B3 /* UniversalMediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0879A4B22F65A7A00C4D6B3 /* UniversalMediaPlayer.framework */; };
|
||||
D0879A4E22F65B2A00C4D6B3 /* MediaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879A4D22F65B2A00C4D6B3 /* MediaManager.swift */; };
|
||||
D0879A5022F65D4D00C4D6B3 /* ChatHistroyLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879A4F22F65D4D00C4D6B3 /* ChatHistroyLocation.swift */; };
|
||||
D0879A5022F65D4D00C4D6B3 /* ChatHistoryLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879A4F22F65D4D00C4D6B3 /* ChatHistoryLocation.swift */; };
|
||||
D0879AA222F6FEC800C4D6B3 /* OverlayAudioPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879AA122F6FEC800C4D6B3 /* OverlayAudioPlayerController.swift */; };
|
||||
D0879B1922F70C7400C4D6B3 /* OpenChatMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879B1822F70C7400C4D6B3 /* OpenChatMessage.swift */; };
|
||||
D0879B1B22F70CF400C4D6B3 /* ChatController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0879B1A22F70CF400C4D6B3 /* ChatController.swift */; };
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
D0879A4922F6584B00C4D6B3 /* SharedMediaPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedMediaPlayer.swift; sourceTree = "<group>"; };
|
||||
D0879A4B22F65A7A00C4D6B3 /* UniversalMediaPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = UniversalMediaPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D0879A4D22F65B2A00C4D6B3 /* MediaManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaManager.swift; sourceTree = "<group>"; };
|
||||
D0879A4F22F65D4D00C4D6B3 /* ChatHistroyLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHistroyLocation.swift; sourceTree = "<group>"; };
|
||||
D0879A4F22F65D4D00C4D6B3 /* ChatHistoryLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHistoryLocation.swift; sourceTree = "<group>"; };
|
||||
D0879AA122F6FEC800C4D6B3 /* OverlayAudioPlayerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlayAudioPlayerController.swift; sourceTree = "<group>"; };
|
||||
D0879B1822F70C7400C4D6B3 /* OpenChatMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenChatMessage.swift; sourceTree = "<group>"; };
|
||||
D0879B1A22F70CF400C4D6B3 /* ChatController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatController.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -130,7 +130,7 @@
|
|||
D0879B6422F7AC8700C4D6B3 /* OverlayMediaManager.swift */,
|
||||
D0879B6022F7A7A600C4D6B3 /* UniversalVideoNode.swift */,
|
||||
D0879B6222F7A97F00C4D6B3 /* OverlayMediaItemNode.swift */,
|
||||
D0879A4F22F65D4D00C4D6B3 /* ChatHistroyLocation.swift */,
|
||||
D0879A4F22F65D4D00C4D6B3 /* ChatHistoryLocation.swift */,
|
||||
D0879AA122F6FEC800C4D6B3 /* OverlayAudioPlayerController.swift */,
|
||||
D0879B1822F70C7400C4D6B3 /* OpenChatMessage.swift */,
|
||||
D0879B1A22F70CF400C4D6B3 /* ChatController.swift */,
|
||||
|
|
@ -262,7 +262,7 @@
|
|||
D0879B1922F70C7400C4D6B3 /* OpenChatMessage.swift in Sources */,
|
||||
D0879B1D22F7112E00C4D6B3 /* GalleryController.swift in Sources */,
|
||||
D0879B1B22F70CF400C4D6B3 /* ChatController.swift in Sources */,
|
||||
D0879A5022F65D4D00C4D6B3 /* ChatHistroyLocation.swift in Sources */,
|
||||
D0879A5022F65D4D00C4D6B3 /* ChatHistoryLocation.swift in Sources */,
|
||||
D0879A4622F651D400C4D6B3 /* LiveLocationManager.swift in Sources */,
|
||||
D0879AA222F6FEC800C4D6B3 /* OverlayAudioPlayerController.swift in Sources */,
|
||||
D0D3285F22F335B000D07EE2 /* AccountContext.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ public enum ChatHistoryLocation: Equatable {
|
|||
case InitialSearch(location: ChatHistoryInitialSearchLocation, count: Int)
|
||||
case Navigation(index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int)
|
||||
case Scroll(index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, sourceIndex: MessageHistoryAnchorIndex, scrollPosition: ListViewScrollPosition, animated: Bool)
|
||||
case Scheduled
|
||||
}
|
||||
|
||||
public struct ChatHistoryLocationInput: Equatable {
|
||||
|
|
@ -75,7 +75,7 @@ public final class ContextMenuContainerNode: ASDisplayNode {
|
|||
path.addLine(to: CGPoint(x: arrowPosition - arrowWidth / 2.0, y: maskParams.size.height - verticalInset))
|
||||
}
|
||||
path.addLine(to: CGPoint(x: cornerRadius, y: maskParams.size.height - verticalInset))
|
||||
path.addArc(withCenter: CGPoint(x: cornerRadius, y: maskParams.size.height - cornerRadius - verticalInset), radius: cornerRadius, startAngle: CGFloat(CGFloat.pi / 2.0), endAngle: CGFloat(M_PI), clockwise: true)
|
||||
path.addArc(withCenter: CGPoint(x: cornerRadius, y: maskParams.size.height - cornerRadius - verticalInset), radius: cornerRadius, startAngle: CGFloat(CGFloat.pi / 2.0), endAngle: CGFloat.pi, clockwise: true)
|
||||
path.close()
|
||||
|
||||
self.cachedMaskParams = maskParams
|
||||
|
|
|
|||
|
|
@ -275,7 +275,14 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||
return (CGRect(origin: CGPoint(), size: detailFrame.size), ContainerViewLayout(size: CGSize(width: detailWidth, height: layout.size.height), metrics: LayoutMetrics(widthClass: .regular, heightClass: .regular), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
|
||||
}
|
||||
case .single:
|
||||
return (CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)), ContainerViewLayout(size: CGSize(width: layout.size.width, height: layout.size.height), metrics: LayoutMetrics(widthClass: .compact, heightClass: layout.size.height > 900.0 ? .regular : .compact), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
|
||||
var heightClass: ContainerViewLayoutSizeClass
|
||||
if (layout.size.width < 375.0 && layout.size.height > 700.0) || layout.size.height > 900.0 {
|
||||
heightClass = .regular
|
||||
} else {
|
||||
heightClass = .compact
|
||||
}
|
||||
|
||||
return (CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)), ContainerViewLayout(size: CGSize(width: layout.size.width, height: layout.size.height), metrics: LayoutMetrics(widthClass: .compact, heightClass: heightClass), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -296,58 +303,54 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||
self.controllerView.addSubview(self.controllerView.separatorView)
|
||||
}
|
||||
|
||||
//let navigationBackgroundFrame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: CGSize(width: lastControllerFrameAndLayout.0.width, height: (layout.statusBarHeight ?? 0.0) + 44.0))
|
||||
|
||||
if let backgroundDetailsMode = self.backgroundDetailsMode {
|
||||
|
||||
switch backgroundDetailsMode {
|
||||
case let .image(image):
|
||||
if let detailsBackground = self.controllerView.detailsBackground {
|
||||
self.controllerView.detailsBackground = nil
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 0.0, completion: { [weak detailsBackground] _ in
|
||||
detailsBackground?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
let emptyDetailView: UIImageView
|
||||
if let emptyView = self.controllerView.emptyDetailView {
|
||||
emptyDetailView = emptyView
|
||||
} else {
|
||||
emptyDetailView = UIImageView()
|
||||
emptyDetailView.alpha = 0.0
|
||||
self.controllerView.emptyDetailView = emptyDetailView
|
||||
}
|
||||
emptyDetailView.image = image
|
||||
if emptyDetailView.superview == nil {
|
||||
self.controllerView.insertSubview(emptyDetailView, at: 0)
|
||||
}
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 1.0)
|
||||
|
||||
emptyDetailView.frame = CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size)
|
||||
case let .image(image):
|
||||
if let detailsBackground = self.controllerView.detailsBackground {
|
||||
self.controllerView.detailsBackground = nil
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 0.0, completion: { [weak detailsBackground] _ in
|
||||
detailsBackground?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
let emptyDetailView: UIImageView
|
||||
if let emptyView = self.controllerView.emptyDetailView {
|
||||
emptyDetailView = emptyView
|
||||
} else {
|
||||
emptyDetailView = UIImageView()
|
||||
emptyDetailView.alpha = 0.0
|
||||
self.controllerView.emptyDetailView = emptyDetailView
|
||||
}
|
||||
emptyDetailView.image = image
|
||||
if emptyDetailView.superview == nil {
|
||||
self.controllerView.insertSubview(emptyDetailView, at: 0)
|
||||
}
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 1.0)
|
||||
|
||||
emptyDetailView.frame = CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size)
|
||||
|
||||
|
||||
case let .wallpaper(image):
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
self.controllerView.emptyDetailView = nil
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 0.0, completion: { [weak emptyDetailView] _ in
|
||||
emptyDetailView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
let detailsBackground: WallpaperbackgroundNode
|
||||
if let background = self.controllerView.detailsBackground {
|
||||
detailsBackground = background
|
||||
} else {
|
||||
detailsBackground = WallpaperbackgroundNode()
|
||||
detailsBackground.alpha = 0.0
|
||||
self.controllerView.detailsBackground = detailsBackground
|
||||
}
|
||||
detailsBackground.image = image
|
||||
if detailsBackground.supernode == nil {
|
||||
self.controllerView.insertSubview(detailsBackground.view, at: 0)
|
||||
}
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 1.0)
|
||||
detailsBackground.frame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: lastControllerFrameAndLayout.0.size)
|
||||
case let .wallpaper(image):
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
self.controllerView.emptyDetailView = nil
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 0.0, completion: { [weak emptyDetailView] _ in
|
||||
emptyDetailView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
let detailsBackground: WallpaperbackgroundNode
|
||||
if let background = self.controllerView.detailsBackground {
|
||||
detailsBackground = background
|
||||
} else {
|
||||
detailsBackground = WallpaperbackgroundNode()
|
||||
detailsBackground.alpha = 0.0
|
||||
self.controllerView.detailsBackground = detailsBackground
|
||||
}
|
||||
detailsBackground.image = image
|
||||
if detailsBackground.supernode == nil {
|
||||
self.controllerView.insertSubview(detailsBackground.view, at: 0)
|
||||
}
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 1.0)
|
||||
detailsBackground.frame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: lastControllerFrameAndLayout.0.size)
|
||||
}
|
||||
|
||||
} else {
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
self.controllerView.emptyDetailView = nil
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@ public protocol ItemListItem {
|
|||
}
|
||||
|
||||
public extension ItemListItem {
|
||||
public var isAlwaysPlain: Bool {
|
||||
var isAlwaysPlain: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public var tag: ItemListItemTag? {
|
||||
var tag: ItemListItemTag? {
|
||||
return nil
|
||||
}
|
||||
|
||||
public var requestsNoInset: Bool {
|
||||
var requestsNoInset: Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ final class MessageHistoryTable: Table {
|
|||
|
||||
func topMessage(_ peerId: PeerId) -> IntermediateMessage? {
|
||||
var topIndex: MessageIndex?
|
||||
for namespace in self.messageHistoryIndexTable.existingNamespaces(peerId: peerId) {
|
||||
for namespace in self.messageHistoryIndexTable.existingNamespaces(peerId: peerId) where self.seedConfiguration.chatMessagesNamespaces.contains(namespace) {
|
||||
self.valueBox.range(self.table, start: self.upperBound(peerId: peerId, namespace: namespace), end: self.lowerBound(peerId: peerId, namespace: namespace), keys: { key in
|
||||
let index = extractKey(key)
|
||||
if let topIndexValue = topIndex {
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ public enum HistoryViewInputAnchor: Equatable {
|
|||
final class MutableMessageHistoryView {
|
||||
private(set) var peerIds: MessageHistoryViewPeerIds
|
||||
let tag: MessageTags?
|
||||
let excludeNamespaces: [MessageId.Namespace]
|
||||
private let orderStatistics: MessageHistoryViewOrderStatistics
|
||||
private let anchor: HistoryViewInputAnchor
|
||||
|
||||
|
|
@ -241,7 +242,7 @@ final class MutableMessageHistoryView {
|
|||
|
||||
fileprivate(set) var sampledState: HistoryViewSample
|
||||
|
||||
init(postbox: Postbox, orderStatistics: MessageHistoryViewOrderStatistics, peerIds: MessageHistoryViewPeerIds, anchor inputAnchor: HistoryViewInputAnchor, combinedReadStates: MessageHistoryViewReadState?, transientReadStates: MessageHistoryViewReadState?, tag: MessageTags?, count: Int, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?], additionalDatas: [AdditionalMessageHistoryViewDataEntry], getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32) {
|
||||
init(postbox: Postbox, orderStatistics: MessageHistoryViewOrderStatistics, peerIds: MessageHistoryViewPeerIds, anchor inputAnchor: HistoryViewInputAnchor, combinedReadStates: MessageHistoryViewReadState?, transientReadStates: MessageHistoryViewReadState?, tag: MessageTags?, excludeNamespaces: [MessageId.Namespace], count: Int, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?], additionalDatas: [AdditionalMessageHistoryViewDataEntry], getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32) {
|
||||
self.anchor = inputAnchor
|
||||
|
||||
self.orderStatistics = orderStatistics
|
||||
|
|
@ -249,16 +250,17 @@ final class MutableMessageHistoryView {
|
|||
self.combinedReadStates = combinedReadStates
|
||||
self.transientReadStates = transientReadStates
|
||||
self.tag = tag
|
||||
self.excludeNamespaces = excludeNamespaces
|
||||
self.fillCount = count
|
||||
self.topTaggedMessages = topTaggedMessages
|
||||
self.additionalDatas = additionalDatas
|
||||
|
||||
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds)
|
||||
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, excludeNamespaces: excludeNamespaces, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds)
|
||||
if case let .loading(loadingState) = self.state {
|
||||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||
switch sampledState {
|
||||
case let .ready(anchor, holes):
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds, postbox: postbox, holes: holes))
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, excludeNamespaces: excludeNamespaces, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds, postbox: postbox, holes: holes))
|
||||
self.sampledState = self.state.sample(postbox: postbox)
|
||||
case .loadHole:
|
||||
break
|
||||
|
|
@ -270,12 +272,12 @@ final class MutableMessageHistoryView {
|
|||
}
|
||||
|
||||
private func reset(postbox: Postbox) {
|
||||
self.state = HistoryViewState(postbox: postbox, inputAnchor: self.anchor, tag: self.tag, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds)
|
||||
self.state = HistoryViewState(postbox: postbox, inputAnchor: self.anchor, tag: self.tag, excludeNamespaces: self.excludeNamespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds)
|
||||
if case let .loading(loadingState) = self.state {
|
||||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||
switch sampledState {
|
||||
case let .ready(anchor, holes):
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, excludeNamespaces: self.excludeNamespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||
case .loadHole:
|
||||
break
|
||||
}
|
||||
|
|
@ -284,7 +286,7 @@ final class MutableMessageHistoryView {
|
|||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||
switch sampledState {
|
||||
case let .ready(anchor, holes):
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, excludeNamespaces: self.excludeNamespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||
case .loadHole:
|
||||
break
|
||||
}
|
||||
|
|
@ -470,7 +472,7 @@ final class MutableMessageHistoryView {
|
|||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||
switch sampledState {
|
||||
case let .ready(anchor, holes):
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, excludeNamespaces: self.excludeNamespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||
case .loadHole:
|
||||
break
|
||||
}
|
||||
|
|
@ -712,19 +714,23 @@ public final class MessageHistoryView {
|
|||
entries = []
|
||||
if let transientReadStates = mutableView.transientReadStates, case let .peer(states) = transientReadStates {
|
||||
for entry in state.entries {
|
||||
let read: Bool
|
||||
if entry.message.flags.contains(.Incoming) {
|
||||
read = false
|
||||
} else if let readState = states[entry.message.id.peerId] {
|
||||
read = readState.isOutgoingMessageIndexRead(entry.message.index)
|
||||
} else {
|
||||
read = false
|
||||
if !mutableView.excludeNamespaces.contains(entry.message.id.namespace) {
|
||||
let read: Bool
|
||||
if entry.message.flags.contains(.Incoming) {
|
||||
read = false
|
||||
} else if let readState = states[entry.message.id.peerId] {
|
||||
read = readState.isOutgoingMessageIndexRead(entry.message.index)
|
||||
} else {
|
||||
read = false
|
||||
}
|
||||
entries.append(MessageHistoryEntry(message: entry.message, isRead: read, location: entry.location, monthLocation: entry.monthLocation, attributes: entry.attributes))
|
||||
}
|
||||
entries.append(MessageHistoryEntry(message: entry.message, isRead: read, location: entry.location, monthLocation: entry.monthLocation, attributes: entry.attributes))
|
||||
}
|
||||
} else {
|
||||
for entry in state.entries {
|
||||
entries.append(MessageHistoryEntry(message: entry.message, isRead: false, location: entry.location, monthLocation: entry.monthLocation, attributes: entry.attributes))
|
||||
if !mutableView.excludeNamespaces.contains(entry.message.id.namespace) {
|
||||
entries.append(MessageHistoryEntry(message: entry.message, isRead: false, location: entry.location, monthLocation: entry.monthLocation, attributes: entry.attributes))
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(Set(entries.map({ $0.message.stableId })).count == entries.count)
|
||||
|
|
|
|||
|
|
@ -748,6 +748,7 @@ struct HistoryViewLoadedSample {
|
|||
final class HistoryViewLoadedState {
|
||||
let anchor: HistoryViewAnchor
|
||||
let tag: MessageTags?
|
||||
let excludeNamespaces: [MessageId.Namespace]
|
||||
let statistics: MessageHistoryViewOrderStatistics
|
||||
let halfLimit: Int
|
||||
let seedConfiguration: SeedConfiguration
|
||||
|
|
@ -755,10 +756,11 @@ final class HistoryViewLoadedState {
|
|||
var holes: HistoryViewHoles
|
||||
var spacesWithRemovals = Set<PeerIdAndNamespace>()
|
||||
|
||||
init(anchor: HistoryViewAnchor, tag: MessageTags?, statistics: MessageHistoryViewOrderStatistics, halfLimit: Int, locations: MessageHistoryViewPeerIds, postbox: Postbox, holes: HistoryViewHoles) {
|
||||
init(anchor: HistoryViewAnchor, tag: MessageTags?, excludeNamespaces: [MessageId.Namespace], statistics: MessageHistoryViewOrderStatistics, halfLimit: Int, locations: MessageHistoryViewPeerIds, postbox: Postbox, holes: HistoryViewHoles) {
|
||||
precondition(halfLimit >= 3)
|
||||
self.anchor = anchor
|
||||
self.tag = tag
|
||||
self.excludeNamespaces = excludeNamespaces
|
||||
self.statistics = statistics
|
||||
self.halfLimit = halfLimit
|
||||
self.seedConfiguration = postbox.seedConfiguration
|
||||
|
|
@ -779,7 +781,9 @@ final class HistoryViewLoadedState {
|
|||
var spaces: [PeerIdAndNamespace] = []
|
||||
for peerId in peerIds {
|
||||
for namespace in postbox.messageHistoryIndexTable.existingNamespaces(peerId: peerId) {
|
||||
spaces.append(PeerIdAndNamespace(peerId: peerId, namespace: namespace))
|
||||
if !excludeNamespaces.contains(namespace) {
|
||||
spaces.append(PeerIdAndNamespace(peerId: peerId, namespace: namespace))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1174,7 +1178,7 @@ final class HistoryViewLoadedState {
|
|||
}
|
||||
}
|
||||
|
||||
private func fetchHoles(postbox: Postbox, locations: MessageHistoryViewPeerIds, tag: MessageTags?) -> [PeerIdAndNamespace: IndexSet] {
|
||||
private func fetchHoles(postbox: Postbox, locations: MessageHistoryViewPeerIds, tag: MessageTags?, excludeNamespaces: [MessageId.Namespace]) -> [PeerIdAndNamespace: IndexSet] {
|
||||
var holesBySpace: [PeerIdAndNamespace: IndexSet] = [:]
|
||||
var peerIds: [PeerId] = []
|
||||
switch locations {
|
||||
|
|
@ -1189,11 +1193,13 @@ private func fetchHoles(postbox: Postbox, locations: MessageHistoryViewPeerIds,
|
|||
let holeSpace = tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
||||
for peerId in peerIds {
|
||||
for namespace in postbox.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: holeSpace) {
|
||||
let indices = postbox.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
|
||||
if !indices.isEmpty {
|
||||
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
|
||||
assert(canContainHoles(peerIdAndNamespace, seedConfiguration: postbox.seedConfiguration))
|
||||
holesBySpace[peerIdAndNamespace] = indices
|
||||
if !excludeNamespaces.contains(namespace) {
|
||||
let indices = postbox.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
|
||||
if !indices.isEmpty {
|
||||
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
|
||||
assert(canContainHoles(peerIdAndNamespace, seedConfiguration: postbox.seedConfiguration))
|
||||
holesBySpace[peerIdAndNamespace] = indices
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1211,11 +1217,11 @@ final class HistoryViewLoadingState {
|
|||
let halfLimit: Int
|
||||
var holes: HistoryViewHoles
|
||||
|
||||
init(postbox: Postbox, locations: MessageHistoryViewPeerIds, tag: MessageTags?, messageId: MessageId, halfLimit: Int) {
|
||||
init(postbox: Postbox, locations: MessageHistoryViewPeerIds, tag: MessageTags?, excludeNamespaces: [MessageId.Namespace], messageId: MessageId, halfLimit: Int) {
|
||||
self.messageId = messageId
|
||||
self.tag = tag
|
||||
self.halfLimit = halfLimit
|
||||
self.holes = HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))
|
||||
self.holes = HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces))
|
||||
}
|
||||
|
||||
func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||
|
|
@ -1255,14 +1261,14 @@ enum HistoryViewState {
|
|||
case loaded(HistoryViewLoadedState)
|
||||
case loading(HistoryViewLoadingState)
|
||||
|
||||
init(postbox: Postbox, inputAnchor: HistoryViewInputAnchor, tag: MessageTags?, statistics: MessageHistoryViewOrderStatistics, halfLimit: Int, locations: MessageHistoryViewPeerIds) {
|
||||
init(postbox: Postbox, inputAnchor: HistoryViewInputAnchor, tag: MessageTags?, excludeNamespaces: [MessageId.Namespace], statistics: MessageHistoryViewOrderStatistics, halfLimit: Int, locations: MessageHistoryViewPeerIds) {
|
||||
switch inputAnchor {
|
||||
case let .index(index):
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .index(index), tag: tag, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))))
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .index(index), tag: tag, excludeNamespaces: excludeNamespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces))))
|
||||
case .lowerBound:
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .lowerBound, tag: tag, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))))
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .lowerBound, tag: tag, excludeNamespaces: excludeNamespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces))))
|
||||
case .upperBound:
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))))
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, excludeNamespaces: excludeNamespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces))))
|
||||
case .unread:
|
||||
let anchorPeerId: PeerId
|
||||
switch locations {
|
||||
|
|
@ -1295,26 +1301,26 @@ enum HistoryViewState {
|
|||
}
|
||||
}
|
||||
if let messageId = messageId {
|
||||
let loadingState = HistoryViewLoadingState(postbox: postbox, locations: locations, tag: tag, messageId: messageId, halfLimit: halfLimit)
|
||||
let loadingState = HistoryViewLoadingState(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces, messageId: messageId, halfLimit: halfLimit)
|
||||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||
switch sampledState {
|
||||
case let .ready(anchor, holes):
|
||||
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
|
||||
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, excludeNamespaces: excludeNamespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
|
||||
case .loadHole:
|
||||
self = .loading(loadingState)
|
||||
}
|
||||
} else {
|
||||
self = .loaded(HistoryViewLoadedState(anchor: anchor ?? .upperBound, tag: tag, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))))
|
||||
self = .loaded(HistoryViewLoadedState(anchor: anchor ?? .upperBound, tag: tag, excludeNamespaces: excludeNamespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces))))
|
||||
}
|
||||
} else {
|
||||
preconditionFailure()
|
||||
}
|
||||
case let .message(messageId):
|
||||
let loadingState = HistoryViewLoadingState(postbox: postbox, locations: locations, tag: tag, messageId: messageId, halfLimit: halfLimit)
|
||||
let loadingState = HistoryViewLoadingState(postbox: postbox, locations: locations, tag: tag, excludeNamespaces: excludeNamespaces, messageId: messageId, halfLimit: halfLimit)
|
||||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||
switch sampledState {
|
||||
case let .ready(anchor, holes):
|
||||
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
|
||||
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, excludeNamespaces: excludeNamespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
|
||||
case .loadHole:
|
||||
self = .loading(loadingState)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||
}
|
||||
}
|
||||
self.anchor = anchor
|
||||
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], peerIds: .single(peerId), anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
|
||||
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], peerIds: .single(peerId), anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, excludeNamespaces: [], count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
|
||||
let _ = self.updateFromView()
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||
|
||||
if self.anchor != anchor {
|
||||
self.anchor = anchor
|
||||
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], peerIds: .single(peerId), anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
|
||||
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], peerIds: .single(peerId), anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, excludeNamespaces: [], count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
|
||||
return self.updateFromView()
|
||||
} else if self.wrappedView.replay(postbox: postbox, transaction: transaction) {
|
||||
return self.updateFromView()
|
||||
|
|
|
|||
|
|
@ -1788,13 +1788,14 @@ public final class Postbox {
|
|||
|
||||
fileprivate func getTopPeerMessageIndex(peerId: PeerId) -> MessageIndex? {
|
||||
var indices: [MessageIndex] = []
|
||||
for namespace in self.messageHistoryIndexTable.existingNamespaces(peerId: peerId) {
|
||||
for namespace in self.messageHistoryIndexTable.existingNamespaces(peerId: peerId) where self.seedConfiguration.chatMessagesNamespaces.contains(namespace) {
|
||||
if let index = self.messageHistoryTable.topIndexEntry(peerId: peerId, namespace: namespace) {
|
||||
indices.append(index)
|
||||
}
|
||||
}
|
||||
return indices.max()
|
||||
}
|
||||
|
||||
fileprivate func getPeerChatListInclusion(_ id: PeerId) -> PeerChatListInclusion {
|
||||
if let inclusion = self.currentUpdatedChatListInclusions[id] {
|
||||
return inclusion
|
||||
|
|
@ -2218,7 +2219,7 @@ public final class Postbox {
|
|||
return peerIds
|
||||
}
|
||||
|
||||
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocation, count: Int, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocation, count: Int, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, excludeNamespaces: [MessageId.Namespace], orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
return self.transactionSignal(userInteractive: true, { subscriber, transaction in
|
||||
let peerIds = self.peerIdsForLocation(chatLocation, tagMask: tagMask)
|
||||
|
||||
|
|
@ -2262,26 +2263,26 @@ public final class Postbox {
|
|||
}
|
||||
}
|
||||
}
|
||||
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, anchor: anchor, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData)
|
||||
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, anchor: anchor, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, excludeNamespaces: excludeNamespaces, orderStatistics: orderStatistics, additionalData: additionalData)
|
||||
})
|
||||
}
|
||||
|
||||
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, messageId: MessageId, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, messageId: MessageId, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, excludeNamespaces: [MessageId.Namespace], orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
return self.transactionSignal { subscriber, transaction in
|
||||
let peerIds = self.peerIdsForLocation(chatLocation, tagMask: tagMask)
|
||||
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, anchor: .message(messageId), fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData)
|
||||
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, anchor: .message(messageId), fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, excludeNamespaces: excludeNamespaces, orderStatistics: orderStatistics, additionalData: additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, anchor: HistoryViewInputAnchor, count: Int, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, anchor: HistoryViewInputAnchor, count: Int, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, excludeNamespaces: [MessageId.Namespace], orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
return self.transactionSignal { subscriber, transaction in
|
||||
let peerIds = self.peerIdsForLocation(chatLocation, tagMask: tagMask)
|
||||
|
||||
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, anchor: anchor, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData)
|
||||
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, anchor: anchor, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, excludeNamespaces: excludeNamespaces, orderStatistics: orderStatistics, additionalData: additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
private func syncAroundMessageHistoryViewForPeerId(subscriber: Subscriber<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>, peerIds: MessageHistoryViewPeerIds, count: Int, anchor: HistoryViewInputAnchor, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Disposable {
|
||||
private func syncAroundMessageHistoryViewForPeerId(subscriber: Subscriber<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>, peerIds: MessageHistoryViewPeerIds, count: Int, anchor: HistoryViewInputAnchor, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, excludeNamespaces: [MessageId.Namespace], orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Disposable {
|
||||
var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:]
|
||||
var mainPeerId: PeerId?
|
||||
switch peerIds {
|
||||
|
|
@ -2370,7 +2371,7 @@ public final class Postbox {
|
|||
readStates = transientReadStates
|
||||
}
|
||||
|
||||
let mutableView = MutableMessageHistoryView(postbox: self, orderStatistics: orderStatistics, peerIds: peerIds, anchor: anchor, combinedReadStates: readStates, transientReadStates: transientReadStates, tag: tagMask, count: count, topTaggedMessages: topTaggedMessages, additionalDatas: additionalDataEntries, getMessageCountInRange: { lowerBound, upperBound in
|
||||
let mutableView = MutableMessageHistoryView(postbox: self, orderStatistics: orderStatistics, peerIds: peerIds, anchor: anchor, combinedReadStates: readStates, transientReadStates: transientReadStates, tag: tagMask, excludeNamespaces: excludeNamespaces, count: count, topTaggedMessages: topTaggedMessages, additionalDatas: additionalDataEntries, getMessageCountInRange: { lowerBound, upperBound in
|
||||
if let tagMask = tagMask {
|
||||
return Int32(self.messageHistoryTable.getMessageCountInRange(peerId: lowerBound.id.peerId, namespace: lowerBound.id.namespace, tag: tagMask, lowerBound: lowerBound, upperBound: upperBound))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ public final class SeedConfiguration {
|
|||
public let additionalChatListIndexNamespace: MessageId.Namespace?
|
||||
public let messageNamespacesRequiringGroupStatsValidation: Set<MessageId.Namespace>
|
||||
public let defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState]
|
||||
public let chatMessagesNamespaces: Set<MessageId.Namespace>
|
||||
|
||||
public init(globalMessageIdsPeerIdNamespaces: Set<GlobalMessageIdsNamespace>, initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?), messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]], existingMessageTags: MessageTags, messageTagsWithSummary: MessageTags, existingGlobalMessageTags: GlobalMessageTags, peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], peerSummaryCounterTags: @escaping (Peer) -> PeerSummaryCounterTags, additionalChatListIndexNamespace: MessageId.Namespace?, messageNamespacesRequiringGroupStatsValidation: Set<MessageId.Namespace>, defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState]) {
|
||||
public init(globalMessageIdsPeerIdNamespaces: Set<GlobalMessageIdsNamespace>, initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?), messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]], existingMessageTags: MessageTags, messageTagsWithSummary: MessageTags, existingGlobalMessageTags: GlobalMessageTags, peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], peerSummaryCounterTags: @escaping (Peer) -> PeerSummaryCounterTags, additionalChatListIndexNamespace: MessageId.Namespace?, messageNamespacesRequiringGroupStatsValidation: Set<MessageId.Namespace>, defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState], chatMessagesNamespaces: Set<MessageId.Namespace>) {
|
||||
self.globalMessageIdsPeerIdNamespaces = globalMessageIdsPeerIdNamespaces
|
||||
self.initializeChatListWithHole = initializeChatListWithHole
|
||||
self.messageHoles = messageHoles
|
||||
|
|
@ -33,5 +34,6 @@ public final class SeedConfiguration {
|
|||
self.additionalChatListIndexNamespace = additionalChatListIndexNamespace
|
||||
self.messageNamespacesRequiringGroupStatsValidation = messageNamespacesRequiringGroupStatsValidation
|
||||
self.defaultMessageNamespaceReadStates = defaultMessageNamespaceReadStates
|
||||
self.chatMessagesNamespaces = chatMessagesNamespaces
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class ChatListTableTests: XCTestCase {
|
|||
path = NSTemporaryDirectory() + "\(randomId)"
|
||||
self.valueBox = SqliteValueBox(basePath: path!, queue: Queue.mainQueue())
|
||||
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil)
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, chatMessagesNamespaces: Set())
|
||||
|
||||
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox!, table: GlobalMessageIdsTable.tableSpec(7), namespace: namespace)
|
||||
self.historyMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox!, table: MessageHistoryMetadataTable.tableSpec(8))
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class MessageHistoryIndexTableTests: XCTestCase {
|
|||
]
|
||||
]
|
||||
|
||||
let seedConfiguration = SeedConfiguration(globalMessageIdsPeerIdNamespaces: Set(), initializeChatListWithHole: (topLevel: nil, groups: nil), messageHoles: messageHoles, existingMessageTags: [.media], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, messageNamespacesRequiringGroupStatsValidation: Set())
|
||||
let seedConfiguration = SeedConfiguration(globalMessageIdsPeerIdNamespaces: Set(), initializeChatListWithHole: (topLevel: nil, groups: nil), messageHoles: messageHoles, existingMessageTags: [.media], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, messageNamespacesRequiringGroupStatsValidation: Set(), chatMessagesNamespaces: Set())
|
||||
|
||||
self.postbox = Postbox(queue: Queue.mainQueue(), basePath: path!, seedConfiguration: seedConfiguration, valueBox: self.valueBox!)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ class MessageHistoryTableTests: XCTestCase {
|
|||
path = NSTemporaryDirectory() + "\(randomId)"
|
||||
self.valueBox = SqliteValueBox(basePath: path!, queue: Queue.mainQueue())
|
||||
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second, .Summary], messageTagsWithSummary: [.Summary], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], additionalChatListIndexNamespace: nil)
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second, .Summary], messageTagsWithSummary: [.Summary], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], additionalChatListIndexNamespace: nil, chatMessagesNamespaces: Set())
|
||||
|
||||
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox!, table: GlobalMessageIdsTable.tableSpec(5), namespace: namespace)
|
||||
self.historyMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox!, table: MessageHistoryMetadataTable.tableSpec(7))
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class MessageHistoryViewTests: XCTestCase {
|
|||
]
|
||||
]
|
||||
|
||||
let seedConfiguration = SeedConfiguration(globalMessageIdsPeerIdNamespaces: Set(), initializeChatListWithHole: (topLevel: nil, groups: nil), messageHoles: messageHoles, existingMessageTags: [], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, messageNamespacesRequiringGroupStatsValidation: Set())
|
||||
let seedConfiguration = SeedConfiguration(globalMessageIdsPeerIdNamespaces: Set(), initializeChatListWithHole: (topLevel: nil, groups: nil), messageHoles: messageHoles, existingMessageTags: [], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, messageNamespacesRequiringGroupStatsValidation: Set(), chatMessagesNamespaces: Set())
|
||||
|
||||
self.postbox = Postbox(queue: Queue.mainQueue(), basePath: path!, seedConfiguration: seedConfiguration, valueBox: self.valueBox!)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class OrderStatisticTreeTests: XCTestCase {
|
|||
path = NSTemporaryDirectory() + "\(randomId)"
|
||||
self.valueBox = SqliteValueBox(basePath: path!, queue: Queue.mainQueue())
|
||||
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil)
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, chatMessagesNamespaces: Set())
|
||||
|
||||
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox!, table: GlobalMessageIdsTable.tableSpec(5), namespace: namespace)
|
||||
self.historyMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox!, table: MessageHistoryMetadataTable.tableSpec(7))
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class ReadStateTableTests: XCTestCase {
|
|||
path = NSTemporaryDirectory() + "\(randomId)"
|
||||
self.valueBox = SqliteValueBox(basePath: path!, queue: Queue.mainQueue())
|
||||
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil)
|
||||
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second], messageTagsWithSummary: [], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], peerSummaryCounterTags: { _ in PeerSummaryCounterTags(rawValue: 0) }, additionalChatListIndexNamespace: nil, chatMessagesNamespaces: Set())
|
||||
|
||||
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox!, table: GlobalMessageIdsTable.tableSpec(5), namespace: namespace)
|
||||
self.historyMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox!, table: MessageHistoryMetadataTable.tableSpec(7))
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ private func chatMessageStickerThumbnailData(postbox: Postbox, file: TelegramMed
|
|||
|
||||
return Signal { subscriber in
|
||||
let fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start()
|
||||
|
||||
|
||||
let disposable = (thumbnailData
|
||||
|> map { thumbnailData -> Data? in
|
||||
return thumbnailData.complete ? try? Data(contentsOf: URL(fileURLWithPath: thumbnailData.path)) : nil
|
||||
|
|
@ -231,7 +231,7 @@ private func chatMessageStickerPackThumbnailData(postbox: Postbox, resource: Med
|
|||
public func chatMessageAnimationData(postbox: Postbox, resource: MediaResource, fitzModifier: EmojiFitzModifier? = nil, width: Int, height: Int, synchronousLoad: Bool) -> Signal<MediaResourceData, NoError> {
|
||||
let representation = CachedAnimatedStickerRepresentation(width: Int32(width), height: Int32(height), fitzModifier: fitzModifier)
|
||||
let maybeFetched = postbox.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: false, fetch: false, attemptSynchronously: synchronousLoad)
|
||||
|
||||
|
||||
return maybeFetched
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeData in
|
||||
|
|
@ -245,9 +245,7 @@ public func chatMessageAnimationData(postbox: Postbox, resource: MediaResource,
|
|||
|
||||
public func chatMessageAnimatedStickerBackingData(postbox: Postbox, fileReference: FileMediaReference, synchronousLoad: Bool) -> Signal<Tuple2<Data?, Bool>, NoError> {
|
||||
let resource = fileReference.media.resource
|
||||
|
||||
let maybeFetched = postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad)
|
||||
|
||||
return maybeFetched
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeData in
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
|||
})
|
||||
}
|
||||
|
||||
if let liveLocationManager = context.liveLocationManager {
|
||||
if false, let liveLocationManager = context.liveLocationManager {
|
||||
switch locationBroadcastPanelSource {
|
||||
case .none:
|
||||
self.locationBroadcastMode = nil
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
|||
} else {
|
||||
return [.regularChatsAndPrivateGroups]
|
||||
}
|
||||
}, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)])
|
||||
}, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)], chatMessagesNamespaces: Set([Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]))
|
||||
}()
|
||||
|
||||
public enum AccountPreferenceEntriesResult {
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ private var declaredEncodables: Void = {
|
|||
declareEncodable(CloudStickerPackThumbnailMediaResource.self, f: { CloudStickerPackThumbnailMediaResource(decoder: $0) })
|
||||
declareEncodable(AccountBackupDataAttribute.self, f: { AccountBackupDataAttribute(decoder: $0) })
|
||||
declareEncodable(ContentRequiresValidationMessageAttribute.self, f: { ContentRequiresValidationMessageAttribute(decoder: $0) })
|
||||
declareEncodable(OutgoingScheduleInfoMessageAttribute.self, f: { OutgoingScheduleInfoMessageAttribute(decoder: $0) })
|
||||
declareEncodable(UpdateMessageReactionsAction.self, f: { UpdateMessageReactionsAction(decoder: $0) })
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.upda
|
|||
switch difference {
|
||||
case let .difference(newMessages, _, otherUpdates, _, _, _):
|
||||
for message in newMessages {
|
||||
if let messageId = message.id {
|
||||
if let messageId = message.id() {
|
||||
peerIds.insert(messageId.peerId)
|
||||
}
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.upda
|
|||
break
|
||||
case let .differenceSlice(newMessages, _, otherUpdates, _, _, _):
|
||||
for message in newMessages {
|
||||
if let messageId = message.id {
|
||||
if let messageId = message.id() {
|
||||
peerIds.insert(messageId.peerId)
|
||||
}
|
||||
}
|
||||
|
|
@ -1304,6 +1304,16 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
|||
peersNearby.append(PeerNearby(id: peer.peerId, expires: expires, distance: distance))
|
||||
}
|
||||
updatedState.updatePeersNearby(peersNearby)
|
||||
case let .updateNewScheduledMessage(apiMessage):
|
||||
if let message = StoreMessage(apiMessage: apiMessage, namespace: Namespaces.Message.CloudScheduled) {
|
||||
updatedState.addMessages([message], location: .Random)
|
||||
}
|
||||
case let .updateDeleteScheduledMessages(peer, messages):
|
||||
var messageIds: [MessageId] = []
|
||||
for message in messages {
|
||||
messageIds.append(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.CloudScheduled, id: message))
|
||||
}
|
||||
updatedState.deleteMessages(messageIds)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -914,25 +914,25 @@ public final class AccountViewTracker {
|
|||
}
|
||||
}
|
||||
|
||||
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, tagMask: MessageTags? = nil, excludeNamespaces: [MessageId.Namespace] = [Namespaces.Message.CloudScheduled], orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
if let account = self.account {
|
||||
let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, excludeNamespaces: excludeNamespaces, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal)
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
}
|
||||
|
||||
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, messageId: MessageId, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, messageId: MessageId, tagMask: MessageTags? = nil, excludeNamespaces: [MessageId.Namespace] = [Namespaces.Message.CloudScheduled], orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
if let account = self.account {
|
||||
let signal = account.postbox.aroundIdMessageHistoryViewForLocation(chatLocation, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
let signal = account.postbox.aroundIdMessageHistoryViewForLocation(chatLocation, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, excludeNamespaces: excludeNamespaces, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal)
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
}
|
||||
|
||||
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, excludeNamespaces: [MessageId.Namespace] = [Namespaces.Message.CloudScheduled], orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
if let account = self.account {
|
||||
let inputAnchor: HistoryViewInputAnchor
|
||||
switch index {
|
||||
|
|
@ -943,7 +943,7 @@ public final class AccountViewTracker {
|
|||
case let .message(index):
|
||||
inputAnchor = .index(index)
|
||||
}
|
||||
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, count: count, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, count: count, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, excludeNamespaces: excludeNamespaces, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal)
|
||||
} else {
|
||||
return .never()
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
var apiMessage: Api.Message?
|
||||
|
||||
for resultMessage in result.messages {
|
||||
if let id = resultMessage.id {
|
||||
if let id = resultMessage.id(namespace: message.scheduleTime != nil ? Namespaces.Message.CloudScheduled : Namespaces.Message.Cloud) {
|
||||
if id.peerId == message.id.peerId {
|
||||
apiMessage = resultMessage
|
||||
break
|
||||
|
|
@ -48,7 +48,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
}
|
||||
}
|
||||
|
||||
if let apiMessage = apiMessage, let id = apiMessage.id {
|
||||
if let apiMessage = apiMessage, let id = apiMessage.id(namespace: message.scheduleTime != nil ? Namespaces.Message.CloudScheduled : Namespaces.Message.Cloud) {
|
||||
messageId = id.id
|
||||
} else {
|
||||
messageId = result.rawMessageIds.first
|
||||
|
|
@ -85,7 +85,8 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
transaction.updateMessage(message.id, update: { currentMessage in
|
||||
let updatedId: MessageId
|
||||
if let messageId = messageId {
|
||||
updatedId = MessageId(peerId: currentMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: messageId)
|
||||
let namespace = message.scheduleTime != nil ? Namespaces.Message.CloudScheduled : Namespaces.Message.Cloud
|
||||
updatedId = MessageId(peerId: currentMessage.id.peerId, namespace: namespace, id: messageId)
|
||||
} else {
|
||||
updatedId = currentMessage.id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class AutoremoveTimeoutMessageAttribute: MessageAttribute {
|
|||
}
|
||||
|
||||
public extension Message {
|
||||
public var containsSecretMedia: Bool {
|
||||
var containsSecretMedia: Bool {
|
||||
var found = false
|
||||
for attribute in self.attributes {
|
||||
if let attribute = attribute as? AutoremoveTimeoutMessageAttribute {
|
||||
|
|
@ -72,10 +72,10 @@ public extension Message {
|
|||
return false
|
||||
}
|
||||
|
||||
public var secretMediaDuration: Int32? {
|
||||
var secretMediaDuration: Int32? {
|
||||
var found = false
|
||||
for attribute in self.attributes {
|
||||
if let attribute = attribute as? AutoremoveTimeoutMessageAttribute {
|
||||
if let _ = attribute as? AutoremoveTimeoutMessageAttribute {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt
|
|||
return true
|
||||
case _ as NotificationInfoMessageAttribute:
|
||||
return true
|
||||
case _ as OutgoingScheduleInfoMessageAttribute:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,57 +150,17 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||
let request: Signal<Api.messages.Messages, MTRpcError>
|
||||
var implicitelyFillHole = false
|
||||
let minMaxRange: ClosedRange<MessageId.Id>
|
||||
switch space {
|
||||
case .everywhere:
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
let selectedLimit = limit
|
||||
let maxId: Int32
|
||||
let minId: Int32
|
||||
|
||||
switch direction {
|
||||
case let .range(start, end):
|
||||
if start.id <= end.id {
|
||||
offsetId = start.id <= 1 ? 1 : (start.id - 1)
|
||||
addOffset = Int32(-selectedLimit)
|
||||
maxId = end.id
|
||||
minId = start.id - 1
|
||||
|
||||
let rangeStartId = start.id
|
||||
let rangeEndId = min(end.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
} else {
|
||||
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
addOffset = 0
|
||||
maxId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
minId = end.id
|
||||
|
||||
let rangeStartId = end.id
|
||||
let rangeEndId = min(start.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
case let .aroundId(id):
|
||||
offsetId = id.id
|
||||
addOffset = Int32(-selectedLimit / 2)
|
||||
maxId = Int32.max
|
||||
minId = 1
|
||||
minMaxRange = 1 ... Int32.max - 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
case let .tag(tag):
|
||||
assert(tag.containsSingleElement)
|
||||
if tag == .unseenPersonalMessage {
|
||||
|
||||
if namespace == Namespaces.Message.CloudScheduled {
|
||||
switch direction {
|
||||
case .aroundId, .range:
|
||||
implicitelyFillHole = true
|
||||
}
|
||||
minMaxRange = 1 ... (Int32.max - 1)
|
||||
request = source.request(Api.functions.messages.getScheduledHistory(peer: inputPeer, hash: 0))
|
||||
} else {
|
||||
switch space {
|
||||
case .everywhere:
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
let selectedLimit = limit
|
||||
|
|
@ -243,72 +203,122 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||
addOffset = Int32(-selectedLimit / 2)
|
||||
maxId = Int32.max
|
||||
minId = 1
|
||||
|
||||
minMaxRange = 1 ... Int32.max - 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
} else if tag == .liveLocation {
|
||||
let selectedLimit = limit
|
||||
|
||||
switch direction {
|
||||
case .aroundId, .range:
|
||||
implicitelyFillHole = true
|
||||
}
|
||||
minMaxRange = 1 ... (Int32.max - 1)
|
||||
request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0))
|
||||
} else if let filter = messageFilterForTagMask(tag) {
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
let selectedLimit = limit
|
||||
let maxId: Int32
|
||||
let minId: Int32
|
||||
|
||||
switch direction {
|
||||
case let .range(start, end):
|
||||
if start.id <= end.id {
|
||||
offsetId = start.id <= 1 ? 1 : (start.id - 1)
|
||||
addOffset = Int32(-selectedLimit)
|
||||
maxId = end.id
|
||||
minId = start.id - 1
|
||||
|
||||
let rangeStartId = start.id
|
||||
let rangeEndId = min(end.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
} else {
|
||||
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
addOffset = 0
|
||||
maxId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
minId = end.id
|
||||
|
||||
let rangeStartId = end.id
|
||||
let rangeEndId = min(start.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
case let .aroundId(id):
|
||||
offsetId = id.id
|
||||
addOffset = Int32(-selectedLimit / 2)
|
||||
maxId = Int32.max
|
||||
minId = 1
|
||||
request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
case let .tag(tag):
|
||||
assert(tag.containsSingleElement)
|
||||
if tag == .unseenPersonalMessage {
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
let selectedLimit = limit
|
||||
let maxId: Int32
|
||||
let minId: Int32
|
||||
|
||||
minMaxRange = 1 ... (Int32.max - 1)
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
} else {
|
||||
assertionFailure()
|
||||
minMaxRange = 1 ... 1
|
||||
request = .never()
|
||||
switch direction {
|
||||
case let .range(start, end):
|
||||
if start.id <= end.id {
|
||||
offsetId = start.id <= 1 ? 1 : (start.id - 1)
|
||||
addOffset = Int32(-selectedLimit)
|
||||
maxId = end.id
|
||||
minId = start.id - 1
|
||||
|
||||
let rangeStartId = start.id
|
||||
let rangeEndId = min(end.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
} else {
|
||||
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
addOffset = 0
|
||||
maxId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
minId = end.id
|
||||
|
||||
let rangeStartId = end.id
|
||||
let rangeEndId = min(start.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
case let .aroundId(id):
|
||||
offsetId = id.id
|
||||
addOffset = Int32(-selectedLimit / 2)
|
||||
maxId = Int32.max
|
||||
minId = 1
|
||||
|
||||
minMaxRange = 1 ... Int32.max - 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
} else if tag == .liveLocation {
|
||||
let selectedLimit = limit
|
||||
|
||||
switch direction {
|
||||
case .aroundId, .range:
|
||||
implicitelyFillHole = true
|
||||
}
|
||||
minMaxRange = 1 ... (Int32.max - 1)
|
||||
request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0))
|
||||
} else if let filter = messageFilterForTagMask(tag) {
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
let selectedLimit = limit
|
||||
let maxId: Int32
|
||||
let minId: Int32
|
||||
|
||||
switch direction {
|
||||
case let .range(start, end):
|
||||
if start.id <= end.id {
|
||||
offsetId = start.id <= 1 ? 1 : (start.id - 1)
|
||||
addOffset = Int32(-selectedLimit)
|
||||
maxId = end.id
|
||||
minId = start.id - 1
|
||||
|
||||
let rangeStartId = start.id
|
||||
let rangeEndId = min(end.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
} else {
|
||||
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
addOffset = 0
|
||||
maxId = start.id == Int32.max ? start.id : (start.id + 1)
|
||||
minId = end.id
|
||||
|
||||
let rangeStartId = end.id
|
||||
let rangeEndId = min(start.id, Int32.max - 1)
|
||||
if rangeStartId <= rangeEndId {
|
||||
minMaxRange = rangeStartId ... rangeEndId
|
||||
} else {
|
||||
minMaxRange = rangeStartId ... rangeStartId
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
case let .aroundId(id):
|
||||
offsetId = id.id
|
||||
addOffset = Int32(-selectedLimit / 2)
|
||||
maxId = Int32.max
|
||||
minId = 1
|
||||
|
||||
minMaxRange = 1 ... (Int32.max - 1)
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
} else {
|
||||
assertionFailure()
|
||||
minMaxRange = 1 ... 1
|
||||
request = .never()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +367,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||
var storeMessages: [StoreMessage] = []
|
||||
|
||||
for message in messages {
|
||||
if let storeMessage = StoreMessage(apiMessage: message) {
|
||||
if let storeMessage = StoreMessage(apiMessage: message, namespace: namespace) {
|
||||
if let channelPts = channelPts {
|
||||
var attributes = storeMessage.attributes
|
||||
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
|
||||
|
|
@ -372,7 +382,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||
let _ = transaction.addMessages(storeMessages, location: .Random)
|
||||
let _ = transaction.addMessages(additionalMessages, location: .Random)
|
||||
let filledRange: ClosedRange<MessageId.Id>
|
||||
let ids = messages.compactMap({ $0.id?.id })
|
||||
let ids = messages.compactMap({ $0.id()?.id })
|
||||
if ids.count == 0 || implicitelyFillHole {
|
||||
filledRange = minMaxRange
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -165,38 +165,73 @@ private func removeMessages(postbox: Postbox, network: Network, stateManager: Ac
|
|||
return .complete()
|
||||
}
|
||||
} else {
|
||||
var flags: Int32
|
||||
switch operation.type {
|
||||
case .forEveryone:
|
||||
flags = (1 << 0)
|
||||
default:
|
||||
flags = 0
|
||||
var isScheduled = false
|
||||
for id in operation.messageIds {
|
||||
if id.namespace == Namespaces.Message.CloudScheduled {
|
||||
isScheduled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var signal: Signal<Void, NoError> = .complete()
|
||||
for s in stride(from: 0, to: operation.messageIds.count, by: 100) {
|
||||
let ids = Array(operation.messageIds[s ..< min(s + 100, operation.messageIds.count)])
|
||||
let partSignal = network.request(Api.functions.messages.deleteMessages(flags: flags, id: ids.map { $0.id }))
|
||||
|> map { result -> Api.messages.AffectedMessages? in
|
||||
return result
|
||||
}
|
||||
|> `catch` { _ in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .affectedMessages(pts, ptsCount):
|
||||
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
|
||||
if isScheduled {
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
var signal: Signal<Void, NoError> = .complete()
|
||||
for s in stride(from: 0, to: operation.messageIds.count, by: 100) {
|
||||
let ids = Array(operation.messageIds[s ..< min(s + 100, operation.messageIds.count)])
|
||||
let partSignal = network.request(Api.functions.messages.deleteScheduledMessages(peer: inputPeer, id: ids.map { $0.id }))
|
||||
|> map { result -> Api.Updates? in
|
||||
return result
|
||||
}
|
||||
|> `catch` { _ in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Void, NoError> in
|
||||
if let updates = updates {
|
||||
stateManager.addUpdates(updates)
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|
||||
signal = signal
|
||||
|> then(partSignal)
|
||||
}
|
||||
return signal
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
var flags: Int32
|
||||
switch operation.type {
|
||||
case .forEveryone:
|
||||
flags = (1 << 0)
|
||||
default:
|
||||
flags = 0
|
||||
}
|
||||
|
||||
signal = signal
|
||||
|> then(partSignal)
|
||||
var signal: Signal<Void, NoError> = .complete()
|
||||
for s in stride(from: 0, to: operation.messageIds.count, by: 100) {
|
||||
let ids = Array(operation.messageIds[s ..< min(s + 100, operation.messageIds.count)])
|
||||
let partSignal = network.request(Api.functions.messages.deleteMessages(flags: flags, id: ids.map { $0.id }))
|
||||
|> map { result -> Api.messages.AffectedMessages? in
|
||||
return result
|
||||
}
|
||||
|> `catch` { _ in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .affectedMessages(pts, ptsCount):
|
||||
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
|
||||
}
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|
||||
signal = signal
|
||||
|> then(partSignal)
|
||||
}
|
||||
return signal
|
||||
}
|
||||
return signal
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,9 +251,9 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
|
|||
let reportSignal: Signal<Api.Bool, NoError>
|
||||
if let inputPeer = apiInputPeer(peer), operation.reportChatSpam {
|
||||
reportSignal = network.request(Api.functions.messages.reportSpam(peer: inputPeer))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
} else {
|
||||
reportSignal = .single(.boolTrue)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,13 +137,13 @@ private func synchronizeMarkAllUnseen(transaction: Transaction, postbox: Postbox
|
|||
|> mapToSignal { result -> Signal<[MessageId], MTRpcError> in
|
||||
switch result {
|
||||
case let .messages(messages, _, _):
|
||||
return .single(messages.compactMap({ $0.id }))
|
||||
return .single(messages.compactMap({ $0.id() }))
|
||||
case let .channelMessages(channelMessages):
|
||||
return .single(channelMessages.messages.compactMap({ $0.id }))
|
||||
return .single(channelMessages.messages.compactMap({ $0.id() }))
|
||||
case .messagesNotModified:
|
||||
return .single([])
|
||||
case let .messagesSlice(messagesSlice):
|
||||
return .single(messagesSlice.messages.compactMap({ $0.id }))
|
||||
return .single(messagesSlice.messages.compactMap({ $0.id() }))
|
||||
}
|
||||
}
|
||||
|> mapToSignal { ids -> Signal<Int32?, MTRpcError> in
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public struct Namespaces {
|
|||
public static let Cloud: Int32 = 0
|
||||
public static let Local: Int32 = 1
|
||||
public static let SecretIncoming: Int32 = 2
|
||||
public static let CloudScheduled: Int32 = 3
|
||||
}
|
||||
|
||||
public struct Media {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class OutgoingMessageInfoAttribute: MessageAttribute {
|
|||
}
|
||||
|
||||
public extension Message {
|
||||
public var isSentOrAcknowledged: Bool {
|
||||
var isSentOrAcknowledged: Bool {
|
||||
if self.flags.contains(.Failed) {
|
||||
return false
|
||||
} else if self.flags.isSending {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
#else
|
||||
import Postbox
|
||||
#endif
|
||||
|
||||
public class OutgoingScheduleInfoMessageAttribute: MessageAttribute {
|
||||
public let scheduleTime: Int32
|
||||
|
||||
public init(scheduleTime: Int32) {
|
||||
self.scheduleTime = scheduleTime
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.scheduleTime = decoder.decodeInt32ForKey("t", orElse: 0)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(scheduleTime, forKey: "t")
|
||||
}
|
||||
|
||||
public func withUpdatedScheduleTime(_ scheduleTime: Int32) -> OutgoingScheduleInfoMessageAttribute {
|
||||
return OutgoingScheduleInfoMessageAttribute(scheduleTime: scheduleTime)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Message {
|
||||
var scheduleTime: Int32? {
|
||||
for attribute in self.attributes {
|
||||
if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute {
|
||||
return attribute.scheduleTime
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -877,6 +877,7 @@ public final class PendingMessageManager {
|
|||
var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
|
||||
var messageEntities: [Api.MessageEntity]?
|
||||
var replyMessageId: Int32?
|
||||
var scheduleTime: Int32?
|
||||
|
||||
var flags: Int32 = 0
|
||||
|
||||
|
|
@ -897,6 +898,9 @@ public final class PendingMessageManager {
|
|||
if attribute.flags.contains(.muted) {
|
||||
flags |= Int32(1 << 5)
|
||||
}
|
||||
} else if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute {
|
||||
flags |= Int32(1 << 10)
|
||||
scheduleTime = attribute.scheduleTime
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -917,9 +921,9 @@ public final class PendingMessageManager {
|
|||
let sendMessageRequest: Signal<NetworkRequestResult<Api.Updates>, MTRpcError>
|
||||
switch content.content {
|
||||
case .text:
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: nil), info: .acknowledgement, tag: dependencyTag)
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime), info: .acknowledgement, tag: dependencyTag)
|
||||
case let .media(inputMedia, text):
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: nil), tag: dependencyTag)
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime), tag: dependencyTag)
|
||||
|> map(NetworkRequestResult.result)
|
||||
case let .forward(sourceInfo):
|
||||
if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) {
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans
|
|||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: nil)
|
||||
}
|
||||
var updatedAttributes = currentMessage.attributes
|
||||
if let index = updatedAttributes.index(where: { $0 is OutgoingMessageInfoAttribute }){
|
||||
if let index = updatedAttributes.firstIndex(where: { $0 is OutgoingMessageInfoAttribute }){
|
||||
let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute
|
||||
updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia]))
|
||||
} else {
|
||||
|
|
@ -566,7 +566,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
|||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: nil)
|
||||
}
|
||||
var updatedAttributes = currentMessage.attributes
|
||||
if let index = updatedAttributes.index(where: { $0 is OutgoingMessageInfoAttribute }){
|
||||
if let index = updatedAttributes.firstIndex(where: { $0 is OutgoingMessageInfoAttribute }){
|
||||
let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute
|
||||
updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia]))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ public enum RequestEditMessageError {
|
|||
case restricted
|
||||
}
|
||||
|
||||
public func requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute? = nil, disableUrlPreview: Bool = false) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
|
||||
return requestEditMessageInternal(account: account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, forceReupload: false)
|
||||
public func requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute? = nil, disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
|
||||
return requestEditMessageInternal(account: account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: false)
|
||||
|> `catch` { error -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in
|
||||
if case .invalidReference = error {
|
||||
return requestEditMessageInternal(account: account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, forceReupload: true)
|
||||
return requestEditMessageInternal(account: account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: true)
|
||||
} else {
|
||||
return .fail(error)
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ public func requestEditMessage(account: Account, messageId: MessageId, text: Str
|
|||
}
|
||||
}
|
||||
|
||||
private func requestEditMessageInternal(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, forceReupload: Bool) -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> {
|
||||
private func requestEditMessageInternal(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> {
|
||||
let uploadedMedia: Signal<PendingMessageUploadedContentResult?, NoError>
|
||||
switch media {
|
||||
case .keep:
|
||||
|
|
@ -95,9 +95,9 @@ private func requestEditMessageInternal(account: Account, messageId: MessageId,
|
|||
pendingMediaContent = content.content
|
||||
}
|
||||
}
|
||||
return account.postbox.transaction { transaction -> (Peer?, SimpleDictionary<PeerId, Peer>) in
|
||||
return account.postbox.transaction { transaction -> (Peer?, Message?, SimpleDictionary<PeerId, Peer>) in
|
||||
guard let message = transaction.getMessage(messageId) else {
|
||||
return (nil, SimpleDictionary())
|
||||
return (nil, nil, SimpleDictionary())
|
||||
}
|
||||
|
||||
if text.isEmpty {
|
||||
|
|
@ -106,7 +106,7 @@ private func requestEditMessageInternal(account: Account, messageId: MessageId,
|
|||
case _ as TelegramMediaImage, _ as TelegramMediaFile:
|
||||
break
|
||||
default:
|
||||
return (nil, SimpleDictionary())
|
||||
return (nil, nil, SimpleDictionary())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -120,11 +120,11 @@ private func requestEditMessageInternal(account: Account, messageId: MessageId,
|
|||
}
|
||||
}
|
||||
}
|
||||
return (transaction.getPeer(messageId.peerId), peers)
|
||||
return (transaction.getPeer(messageId.peerId), message, peers)
|
||||
}
|
||||
|> mapError { _ -> RequestEditMessageInternalError in return .error(.generic) }
|
||||
|> mapToSignal { peer, associatedPeers -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in
|
||||
if let peer = peer, let inputPeer = apiInputPeer(peer) {
|
||||
|> mapToSignal { peer, message, associatedPeers -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in
|
||||
if let peer = peer, let message = message, let inputPeer = apiInputPeer(peer) {
|
||||
var flags: Int32 = 1 << 11
|
||||
|
||||
var apiEntities: [Api.MessageEntity]?
|
||||
|
|
@ -150,7 +150,17 @@ private func requestEditMessageInternal(account: Account, messageId: MessageId,
|
|||
flags |= Int32(1 << 14)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: text, media: inputMedia, replyMarkup: nil, entities: apiEntities, scheduleDate: nil))
|
||||
var effectiveScheduleTime: Int32?
|
||||
if messageId.namespace == Namespaces.Message.CloudScheduled {
|
||||
if let scheduleTime = scheduleTime {
|
||||
effectiveScheduleTime = scheduleTime
|
||||
} else {
|
||||
effectiveScheduleTime = message.timestamp
|
||||
}
|
||||
flags |= Int32(1 << 15)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: text, media: inputMedia, replyMarkup: nil, entities: apiEntities, scheduleDate: effectiveScheduleTime))
|
||||
|> map { result -> Api.Updates? in
|
||||
return result
|
||||
}
|
||||
|
|
@ -173,7 +183,7 @@ private func requestEditMessageInternal(account: Account, messageId: MessageId,
|
|||
if let result = result {
|
||||
return account.postbox.transaction { transaction -> RequestEditMessageResult in
|
||||
var toMedia: Media?
|
||||
if let message = result.messages.first.flatMap(StoreMessage.init(apiMessage:)) {
|
||||
if let message = result.messages.first.flatMap({ StoreMessage(apiMessage: $0) }) {
|
||||
toMedia = message.media.first
|
||||
}
|
||||
|
||||
|
|
|
|||
29
submodules/TelegramCore/TelegramCore/ScheduledMessages.swift
Normal file
29
submodules/TelegramCore/TelegramCore/ScheduledMessages.swift
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
import SwiftSignalKitMac
|
||||
import TelegramApiMac
|
||||
#else
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
#endif
|
||||
|
||||
public func sendScheduledMessageNow(account: Account, messageId: MessageId) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let _ = transaction.getMessage(messageId), let peer = transaction.getPeer(messageId.peerId), let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.sendScheduledMessages(peer: inputPeer, id: [messageId.id]))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Void, NoError> in
|
||||
if let updates = updates {
|
||||
account.stateManager.addUpdates(updates)
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
return .complete()
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
|||
//var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
|
||||
var messageEntities: [Api.MessageEntity]?
|
||||
var replyMessageId: Int32?
|
||||
var scheduleTime: Int32?
|
||||
|
||||
var flags: Int32 = 0
|
||||
|
||||
|
|
@ -105,6 +106,9 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
|||
if attribute.flags.contains(.disableLinkPreviews) {
|
||||
flags |= Int32(1 << 1)
|
||||
}
|
||||
} else if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute {
|
||||
flags |= Int32(1 << 10)
|
||||
scheduleTime = attribute.scheduleTime
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,12 +122,12 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
|||
let sendMessageRequest: Signal<Api.Updates, NoError>
|
||||
switch content {
|
||||
case let .text(text):
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: nil))
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime))
|
||||
|> `catch` { _ -> Signal<Api.Updates, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
case let .media(inputMedia, text):
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: nil))
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime))
|
||||
|> `catch` { _ -> Signal<Api.Updates, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
|
|||
}
|
||||
|
||||
extension StoreMessage {
|
||||
convenience init?(apiMessage: Api.Message) {
|
||||
convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
|
||||
switch apiMessage {
|
||||
case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, editDate, postAuthor, groupingId, reactions):
|
||||
let peerId: PeerId
|
||||
|
|
@ -572,7 +572,7 @@ extension StoreMessage {
|
|||
|
||||
storeFlags.insert(.CanBeGroupedIntoFeed)
|
||||
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, groupingKey: groupingId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias)
|
||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: groupingId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias)
|
||||
case .messageEmpty:
|
||||
return nil
|
||||
case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action):
|
||||
|
|
@ -636,7 +636,7 @@ extension StoreMessage {
|
|||
|
||||
storeFlags.insert(.CanBeGroupedIntoFeed)
|
||||
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media)
|
||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,19 +109,25 @@ extension Api.Message {
|
|||
}
|
||||
}
|
||||
|
||||
var id: MessageId? {
|
||||
func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? {
|
||||
switch self {
|
||||
case let .message(flags, id, fromId, toId, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
let peerId: PeerId
|
||||
switch toId {
|
||||
case let .peerUser(userId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId))
|
||||
let id: PeerId.Id
|
||||
if namespace == Namespaces.Message.CloudScheduled {
|
||||
id = userId
|
||||
} else {
|
||||
id = (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)
|
||||
}
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
|
||||
case let .peerChat(chatId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
|
||||
case let .peerChannel(channelId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
|
||||
}
|
||||
return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)
|
||||
return MessageId(peerId: peerId, namespace: namespace, id: id)
|
||||
case .messageEmpty:
|
||||
return nil
|
||||
case let .messageService(flags, id, fromId, toId, _, _, _):
|
||||
|
|
@ -134,7 +140,6 @@ extension Api.Message {
|
|||
case let .peerChannel(channelId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
|
||||
}
|
||||
|
||||
return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)
|
||||
}
|
||||
}
|
||||
|
|
@ -238,9 +243,9 @@ extension Api.Update {
|
|||
var messageId: MessageId? {
|
||||
switch self {
|
||||
case let .updateNewMessage(message, _, _):
|
||||
return message.id
|
||||
return message.id()
|
||||
case let .updateNewChannelMessage(message, _, _):
|
||||
return message.id
|
||||
return message.id()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -256,6 +261,8 @@ extension Api.Update {
|
|||
return message
|
||||
case let .updateEditChannelMessage(message, _, _):
|
||||
return message
|
||||
case let .updateNewScheduledMessage(message):
|
||||
return message
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -315,6 +322,8 @@ extension Api.Update {
|
|||
}
|
||||
case let .updateDraftMessage(peer: peer, draft: _):
|
||||
return [peer.peerId]
|
||||
case let .updateNewScheduledMessage(message):
|
||||
return apiMessagePeerIds(message)
|
||||
default:
|
||||
return []
|
||||
}
|
||||
|
|
@ -328,6 +337,8 @@ extension Api.Update {
|
|||
return apiMessageAssociatedMessageIds(message)
|
||||
case let .updateEditChannelMessage(message, _, _):
|
||||
return apiMessageAssociatedMessageIds(message)
|
||||
case let .updateNewScheduledMessage(message):
|
||||
return apiMessageAssociatedMessageIds(message)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
09EC0DE922C6825D00E7185B /* AppUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EC0DE822C6825D00E7185B /* AppUpdate.swift */; };
|
||||
09EDAD382213120C0012A50B /* AutodownloadSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */; };
|
||||
09EDAD3A22131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */; };
|
||||
09FC986B22FD882200915E37 /* OutgoingScheduleInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC986A22FD882200915E37 /* OutgoingScheduleInfoMessageAttribute.swift */; };
|
||||
09FC986D22FD99D400915E37 /* ScheduledMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC986C22FD99D400915E37 /* ScheduledMessages.swift */; };
|
||||
9F06831021A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */; };
|
||||
9F06831121A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */; };
|
||||
9F10CE8C20613CDB002DD61A /* TelegramDeviceContactImportInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F7732052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift */; };
|
||||
|
|
@ -849,6 +851,8 @@
|
|||
09EC0DE822C6825D00E7185B /* AppUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdate.swift; sourceTree = "<group>"; };
|
||||
09EDAD372213120C0012A50B /* AutodownloadSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutodownloadSettings.swift; sourceTree = "<group>"; };
|
||||
09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAutodownloadSettingsUpdates.swift; sourceTree = "<group>"; };
|
||||
09FC986A22FD882200915E37 /* OutgoingScheduleInfoMessageAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingScheduleInfoMessageAttribute.swift; sourceTree = "<group>"; };
|
||||
09FC986C22FD99D400915E37 /* ScheduledMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduledMessages.swift; sourceTree = "<group>"; };
|
||||
9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExceptionsList.swift; sourceTree = "<group>"; };
|
||||
9FC8ADAA206BBFF10094F7B4 /* RecentWebSessions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentWebSessions.swift; sourceTree = "<group>"; };
|
||||
C205FEA71EB3B75900455808 /* ExportMessageLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExportMessageLink.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -1505,6 +1509,7 @@
|
|||
C28725411EF967E700613564 /* NotificationInfoMessageAttribute.swift */,
|
||||
C210DD611FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift */,
|
||||
D0439B5F228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift */,
|
||||
09FC986A22FD882200915E37 /* OutgoingScheduleInfoMessageAttribute.swift */,
|
||||
D0329EA422FC5A9600F9F071 /* ReactionsMessageAttribute.swift */,
|
||||
);
|
||||
name = Attributes;
|
||||
|
|
@ -1708,6 +1713,7 @@
|
|||
D0E8B8B22044706300605593 /* ForwardGame.swift */,
|
||||
D0119CAF20CA9EA800895300 /* MarkAllChatsAsRead.swift */,
|
||||
D023E67721540624008C27D1 /* UpdateMessageMedia.swift */,
|
||||
09FC986C22FD99D400915E37 /* ScheduledMessages.swift */,
|
||||
);
|
||||
name = Messages;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -2232,6 +2238,7 @@
|
|||
D00DBBD71E64E41100DB5485 /* CreateSecretChat.swift in Sources */,
|
||||
C2FD33EB1E696C78008D13D4 /* GroupsInCommon.swift in Sources */,
|
||||
D0FA8BB01E1FEC7E001E855B /* SecretChatEncryptionConfig.swift in Sources */,
|
||||
09FC986B22FD882200915E37 /* OutgoingScheduleInfoMessageAttribute.swift in Sources */,
|
||||
D021E0DF1DB539FC00C6B04F /* StickerPack.swift in Sources */,
|
||||
D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */,
|
||||
D0CA8E4B227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift in Sources */,
|
||||
|
|
@ -2240,6 +2247,7 @@
|
|||
D00D343C1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */,
|
||||
D033FEB01E61EB0200644997 /* PeerContactSettings.swift in Sources */,
|
||||
D050F2511E4A59C200988324 /* JoinLink.swift in Sources */,
|
||||
09FC986D22FD99D400915E37 /* ScheduledMessages.swift in Sources */,
|
||||
D07827C91E02F59C00071108 /* InstantPage.swift in Sources */,
|
||||
D0458C881E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */,
|
||||
D07827CB1E02F5B200071108 /* RichText.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -337,9 +337,13 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
|||
)
|
||||
}
|
||||
|
||||
public let defaultDarkAccentColor = UIColor(rgb: 0x2ea6ff)
|
||||
public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff), baseColor: .blue, preview: false)
|
||||
|
||||
public func makeDarkAccentPresentationTheme(accentColor: UIColor?, baseColor: PresentationThemeBaseColor?, preview: Bool) -> PresentationTheme {
|
||||
let accentColor = accentColor ?? defaultDayAccentColor
|
||||
var accentColor = accentColor ?? defaultDarkAccentColor
|
||||
if accentColor == PresentationThemeBaseColor.blue.color {
|
||||
accentColor = defaultDarkAccentColor
|
||||
}
|
||||
return makeDarkPresentationTheme(accentColor: accentColor, baseColor: baseColor, preview: preview)
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -143,6 +143,7 @@ public enum PresentationResourceKey: Int32 {
|
|||
case chatInputTextFieldClearImage
|
||||
case chatInputPanelSendButtonImage
|
||||
case chatInputPanelApplyButtonImage
|
||||
case chatInputPanelScheduleButtonImage
|
||||
case chatInputPanelVoiceButtonImage
|
||||
case chatInputPanelVideoButtonImage
|
||||
case chatInputPanelExpandButtonImage
|
||||
|
|
@ -159,6 +160,7 @@ public enum PresentationResourceKey: Int32 {
|
|||
case chatInputTextFieldSilentPostOnImage
|
||||
case chatInputTextFieldSilentPostOffImage
|
||||
case chatInputTextFieldTimerImage
|
||||
case chatInputTextFieldScheduleImage
|
||||
|
||||
case chatInputSearchPanelUpImage
|
||||
case chatInputSearchPanelUpDisabledImage
|
||||
|
|
|
|||
|
|
@ -362,6 +362,25 @@ public struct PresentationResourcesChat {
|
|||
})
|
||||
}
|
||||
|
||||
public static func chatInputPanelScheduleButtonImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputPanelScheduleButtonImage.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(theme.chat.inputPanel.actionControlFillColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let imageRect = CGRect(origin: CGPoint(), size: size)
|
||||
context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
||||
context.scaleBy(x: 1.0, y: -1.0)
|
||||
context.translateBy(x: -imageRect.midX, y: -imageRect.midY)
|
||||
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/ScheduleIcon"), color: theme.chat.inputPanel.actionControlForegroundColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - image.size.width) / 2.0), y: floorToScreenPixels((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputPanelVoiceButtonImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputPanelVoiceButtonImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconMicrophone"), color: theme.chat.inputPanel.panelControlColor)
|
||||
|
|
@ -499,6 +518,12 @@ public struct PresentationResourcesChat {
|
|||
})
|
||||
}
|
||||
|
||||
public static func chatInputTextFieldScheduleImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputTextFieldScheduleImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconSchedule"), color: theme.chat.inputPanel.inputControlColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatHistoryNavigationButtonImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatHistoryNavigationButtonImage.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 38.0, height: 38.0), contextGenerator: { size, context in
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "telegram_plane_flat.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
22
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/Contents.json
vendored
Normal file
22
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Schedule@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Schedule@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/Schedule@2x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/Schedule@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1,004 B |
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/Schedule@3x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/Schedule@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
22
submodules/TelegramUI/Images.xcassets/Chat/Input/ScheduleIcon.imageset/Contents.json
vendored
Normal file
22
submodules/TelegramUI/Images.xcassets/Chat/Input/ScheduleIcon.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ScheduleSendButton@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ScheduleSendButton@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/ScheduleIcon.imageset/ScheduleSendButton@2x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/ScheduleIcon.imageset/ScheduleSendButton@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/ScheduleIcon.imageset/ScheduleSendButton@3x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Input/ScheduleIcon.imageset/ScheduleSendButton@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ScheduleInput@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ScheduleInput@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
|
|
@ -404,7 +404,7 @@ final class AnimatedStickerNode: ASDisplayNode {
|
|||
self.renderer?.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
|
||||
self.addSubnode(self.renderer!)
|
||||
}
|
||||
|
||||
|
||||
func setup(account: Account, resource: MediaResource, fitzModifier: EmojiFitzModifier? = nil, width: Int, height: Int, playbackMode: AnimatedStickerPlaybackMode = .loop, mode: AnimatedStickerMode) {
|
||||
if width < 2 || height < 2 {
|
||||
return
|
||||
|
|
@ -566,7 +566,7 @@ final class AnimatedStickerNode: ASDisplayNode {
|
|||
strongSelf.started()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
strongSelf.playbackStatus.set(.single(AnimatedStickerStatus(playing: false, duration: duration, timestamp: 0.0)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,77 +4,18 @@ import SwiftSignalKit
|
|||
import Postbox
|
||||
import Display
|
||||
import TelegramCore
|
||||
import AVFoundation
|
||||
import Lottie
|
||||
import TelegramUIPrivateModule
|
||||
import Compression
|
||||
import GZip
|
||||
import RLottie
|
||||
import MediaResources
|
||||
import MobileCoreServices
|
||||
import MediaResources
|
||||
|
||||
public struct LocalBundleResourceId: MediaResourceId {
|
||||
public let name: String
|
||||
public let ext: String
|
||||
|
||||
public var uniqueId: String {
|
||||
return "local-bundle-\(self.name)-\(self.ext)"
|
||||
}
|
||||
|
||||
public var hashValue: Int {
|
||||
return self.name.hashValue
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResourceId) -> Bool {
|
||||
if let to = to as? LocalBundleResourceId {
|
||||
return self.name == to.name && self.ext == to.ext
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalBundleResource: TelegramMediaResource {
|
||||
public let name: String
|
||||
public let ext: String
|
||||
|
||||
public init(name: String, ext: String) {
|
||||
self.name = name
|
||||
self.ext = ext
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
self.name = decoder.decodeStringForKey("n", orElse: "")
|
||||
self.ext = decoder.decodeStringForKey("e", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.name, forKey: "n")
|
||||
encoder.encodeString(self.ext, forKey: "e")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return LocalBundleResourceId(name: self.name, ext: self.ext)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? LocalBundleResource {
|
||||
return self.name == to.name && self.ext == to.ext
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let colorKeyRegex = try? NSRegularExpression(pattern: "\"k\":\\[[\\d\\.]+\\,[\\d\\.]+\\,[\\d\\.]+\\,[\\d\\.]+\\]")
|
||||
|
||||
private func transformedWithFitzModifier(data: Data, fitzModifier: EmojiFitzModifier?) -> Data {
|
||||
if let fitzModifier = fitzModifier, var string = String(data: data, encoding: .utf8) {
|
||||
let color1: UIColor
|
||||
let color2: UIColor
|
||||
let color3: UIColor
|
||||
let color4: UIColor
|
||||
|
||||
if let fitzModifier = fitzModifier, var string = String(data: data, encoding: .utf8) {
|
||||
var colors: [UIColor] = [0xf77e41, 0xffb139, 0xffd140, 0xffdf79].map { UIColor(rgb: $0) }
|
||||
let replacementColors: [UIColor]
|
||||
switch fitzModifier {
|
||||
|
|
@ -137,7 +78,7 @@ private func transformedWithFitzModifier(data: Data, fitzModifier: EmojiFitzModi
|
|||
string = string.replacingCharacters(in: range, with: text)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return string.data(using: .utf8) ?? data
|
||||
} else {
|
||||
return data
|
||||
|
|
@ -387,28 +328,3 @@ func experimentalConvertCompressedLottieToCombinedMp4(data: Data, size: CGSize,
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
private final class LocalBundleResourceCopyFile : MediaResourceDataFetchCopyLocalItem {
|
||||
let path: String
|
||||
init(path: String) {
|
||||
self.path = path
|
||||
}
|
||||
func copyTo(url: URL) -> Bool {
|
||||
do {
|
||||
try FileManager.default.copyItem(at: URL(fileURLWithPath: self.path), to: url)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchLocalBundleResource(postbox: Postbox, resource: LocalBundleResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
return Signal { subscriber in
|
||||
if let path = frameworkBundle.path(forResource: resource.name, ofType: resource.ext), let _ = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
|
||||
subscriber.putNext(.copyLocalItem(LocalBundleResourceCopyFile(path: path)))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1126,9 +1126,9 @@ final class SharedApplicationContext {
|
|||
})
|
||||
|
||||
if let url = launchOptions?[.url] {
|
||||
if let url = url as? URL, url.scheme == "tg" {
|
||||
if let url = url as? URL, url.scheme == "tg" || url.scheme == buildConfig.appSpecificUrlScheme {
|
||||
self.openUrlWhenReady(url: url.absoluteString)
|
||||
} else if let url = url as? String, url.lowercased().hasPrefix("tg://") {
|
||||
} else if let url = url as? String, url.lowercased().hasPrefix("tg:") || url.lowercased().hasPrefix("\(buildConfig.appSpecificUrlScheme):") {
|
||||
self.openUrlWhenReady(url: url)
|
||||
}
|
||||
}
|
||||
|
|
@ -1849,7 +1849,7 @@ final class SharedApplicationContext {
|
|||
notificationCenter.getNotificationSettings(completionHandler: { settings in
|
||||
switch (settings.authorizationStatus, authorize) {
|
||||
case (.authorized, _), (.notDetermined, true):
|
||||
notificationCenter.requestAuthorization(options: [.badge, .sound, .alert], completionHandler: { result, _ in
|
||||
notificationCenter.requestAuthorization(options: [.badge, .sound, .alert, .carPlay], completionHandler: { result, _ in
|
||||
completion(result)
|
||||
if result {
|
||||
Queue.mainQueue().async {
|
||||
|
|
@ -1871,7 +1871,7 @@ final class SharedApplicationContext {
|
|||
}
|
||||
|
||||
var carPlayOptions = options
|
||||
//carPlayOptions.insert(.allowInCarPlay)
|
||||
carPlayOptions.insert(.allowInCarPlay)
|
||||
|
||||
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
|
|
@ -1882,7 +1882,7 @@ final class SharedApplicationContext {
|
|||
muteMessageCategory = UNNotificationCategory(identifier: "withMute", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
muteMediaMessageCategory = UNNotificationCategory(identifier: "withMuteMedia", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
} else {
|
||||
let carPlayOptions: UNNotificationCategoryOptions = [] //[.allowInCarPlay]
|
||||
let carPlayOptions: UNNotificationCategoryOptions = [.allowInCarPlay]
|
||||
|
||||
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], options: [])
|
||||
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], options: carPlayOptions)
|
||||
|
|
|
|||
|
|
@ -490,7 +490,7 @@ final class AuthorizedApplicationContext {
|
|||
if let strongSelf = self, let botName = botName {
|
||||
strongSelf.termsOfServiceProceedToBotDisposable.set((resolvePeerByName(account: strongSelf.context.account, name: botName, ageLimit: 10) |> take(1) |> deliverOnMainQueue).start(next: { peerId in
|
||||
if let strongSelf = self, let peerId = peerId {
|
||||
self?.rootController.pushViewController(ChatController(context: strongSelf.context, chatLocation: .peer(peerId), messageId: nil))
|
||||
self?.rootController.pushViewController(ChatController(context: strongSelf.context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import SwiftSignalKit
|
|||
import TelegramPresentationData
|
||||
|
||||
private func timerValueString(days: Int32, hours: Int32, minutes: Int32, color: UIColor, strings: PresentationStrings) -> NSAttributedString {
|
||||
var string = NSMutableAttributedString()
|
||||
|
||||
var daysString = ""
|
||||
if days > 0 {
|
||||
daysString = strings.MessageTimer_Days(days) + " "
|
||||
|
|
|
|||
82
submodules/TelegramUI/TelegramUI/BundleResource.swift
Normal file
82
submodules/TelegramUI/TelegramUI/BundleResource.swift
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
|
||||
public struct LocalBundleResourceId: MediaResourceId {
|
||||
public let name: String
|
||||
public let ext: String
|
||||
|
||||
public var uniqueId: String {
|
||||
return "local-bundle-\(self.name)-\(self.ext)"
|
||||
}
|
||||
|
||||
public var hashValue: Int {
|
||||
return self.name.hashValue
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResourceId) -> Bool {
|
||||
if let to = to as? LocalBundleResourceId {
|
||||
return self.name == to.name && self.ext == to.ext
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalBundleResource: TelegramMediaResource {
|
||||
public let name: String
|
||||
public let ext: String
|
||||
|
||||
public init(name: String, ext: String) {
|
||||
self.name = name
|
||||
self.ext = ext
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
self.name = decoder.decodeStringForKey("n", orElse: "")
|
||||
self.ext = decoder.decodeStringForKey("e", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.name, forKey: "n")
|
||||
encoder.encodeString(self.ext, forKey: "e")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return LocalBundleResourceId(name: self.name, ext: self.ext)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? LocalBundleResource {
|
||||
return self.name == to.name && self.ext == to.ext
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LocalBundleResourceCopyFile : MediaResourceDataFetchCopyLocalItem {
|
||||
let path: String
|
||||
init(path: String) {
|
||||
self.path = path
|
||||
}
|
||||
func copyTo(url: URL) -> Bool {
|
||||
do {
|
||||
try FileManager.default.copyItem(at: URL(fileURLWithPath: self.path), to: url)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchLocalBundleResource(postbox: Postbox, resource: LocalBundleResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
return Signal { subscriber in
|
||||
if let path = frameworkBundle.path(forResource: resource.name, ofType: resource.ext), let _ = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
|
||||
subscriber.putNext(.copyLocalItem(LocalBundleResourceCopyFile(path: path)))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
|
@ -114,6 +114,11 @@ private func calculateSlowmodeActiveUntilTimestamp(account: Account, untilTimest
|
|||
|
||||
let ChatControllerCount = Atomic<Int32>(value: 0)
|
||||
|
||||
public enum ChatControllerSubject: Equatable {
|
||||
case message(MessageId)
|
||||
case scheduledMessages
|
||||
}
|
||||
|
||||
public final class ChatController: TelegramBaseController, GalleryHiddenMediaTarget, UIDropInteractionDelegate {
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
|
|
@ -124,7 +129,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
|
||||
private let context: AccountContext
|
||||
public let chatLocation: ChatLocation
|
||||
private let messageId: MessageId?
|
||||
public let subject: ChatControllerSubject?
|
||||
private let botStart: ChatControllerInitialBotStart?
|
||||
|
||||
private let peerDisposable = MetaDisposable()
|
||||
|
|
@ -263,6 +268,8 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
private var reportIrrelvantGeoNotice: Bool?
|
||||
private var reportIrrelvantGeoDisposable: Disposable?
|
||||
|
||||
private var hasScheduledMessages: Bool = false
|
||||
|
||||
private var volumeButtonsListener: VolumeButtonsListener?
|
||||
|
||||
private var beginMediaRecordingRequestId: Int = 0
|
||||
|
|
@ -277,14 +284,14 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
|
||||
var purposefulAction: (() -> Void)?
|
||||
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, messageId: MessageId? = nil, botStart: ChatControllerInitialBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false)) {
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false)) {
|
||||
let _ = ChatControllerCount.modify { value in
|
||||
return value + 1
|
||||
}
|
||||
|
||||
self.context = context
|
||||
self.chatLocation = chatLocation
|
||||
self.messageId = messageId
|
||||
self.subject = subject
|
||||
self.botStart = botStart
|
||||
|
||||
var locationBroadcastPanelSource: LocationBroadcastPanelSource
|
||||
|
|
@ -303,7 +310,12 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
|
||||
self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: false)
|
||||
|
||||
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.fontSize, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation)
|
||||
var isScheduledMessages = false
|
||||
if let subject = subject, case .scheduledMessages = subject {
|
||||
isScheduledMessages = true
|
||||
}
|
||||
|
||||
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.fontSize, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation, isScheduledMessages: isScheduledMessages)
|
||||
|
||||
var mediaAccessoryPanelVisibility = MediaAccessoryPanelVisibility.none
|
||||
if case .standard = mode {
|
||||
|
|
@ -508,31 +520,33 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
return
|
||||
}
|
||||
var actions = actions
|
||||
actions.insert(.action(ContextMenuActionItem(text: "Reaction", icon: { _ in nil }, action: { _, f in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
let emojis = ["👍", "😊", "🤔", "😔", "❤️"]
|
||||
for emoji in emojis {
|
||||
items.append(ActionSheetButtonItem(title: "\(emoji)", color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: updatedMessages[0].id, reactions: [emoji]).start()
|
||||
}))
|
||||
}
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
f(.dismissWithoutContent)
|
||||
})), at: 0)
|
||||
if message.id.namespace != Namespaces.Message.CloudScheduled {
|
||||
actions.insert(.action(ContextMenuActionItem(text: "Reaction", icon: { _ in nil }, action: { _, f in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
let emojis = ["👍", "😊", "🤔", "😔", "❤️"]
|
||||
for emoji in emojis {
|
||||
items.append(ActionSheetButtonItem(title: "\(emoji)", color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: updatedMessages[0].id, reactions: [emoji]).start()
|
||||
}))
|
||||
}
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
f(.dismissWithoutContent)
|
||||
})), at: 0)
|
||||
}
|
||||
strongSelf.window?.presentInGlobalOverlay(ContextController(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextControllerContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, recognizer: recognizer))
|
||||
})
|
||||
}
|
||||
|
|
@ -661,7 +675,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
|
|
@ -728,7 +742,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
|
|
@ -777,7 +791,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
|
|
@ -1263,8 +1277,6 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerId):
|
||||
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, animated: true, completion: nil)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}, requestRedeliveryOfFailedMessages: { [weak self] id in
|
||||
guard let strongSelf = self else {
|
||||
|
|
@ -1326,6 +1338,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
strongSelf.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
})
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
}
|
||||
}, requestSelectMessagePollOption: { [weak self] id, opaqueIdentifier in
|
||||
|
|
@ -1410,6 +1423,70 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(Double(timestamp)))
|
||||
}
|
||||
}
|
||||
}, scheduleCurrentMessage: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let mode: ChatScheduleTimeControllerMode
|
||||
if case let .peer(peerId) = strongSelf.presentationInterfaceState.chatLocation, peerId == strongSelf.context.account.peerId {
|
||||
mode = .reminders
|
||||
} else {
|
||||
mode = .scheduledMessages
|
||||
}
|
||||
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, completion: { [weak self] scheduleTime in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleTime)
|
||||
if !strongSelf.presentationInterfaceState.isScheduledMessages {
|
||||
let controller = ChatController(context: strongSelf.context, chatLocation: strongSelf.chatLocation, subject: .scheduledMessages)
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
}
|
||||
}
|
||||
})
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
}
|
||||
}, sendScheduledMessagesNow: { [weak self] messageIds in
|
||||
if let strongSelf = self {
|
||||
strongSelf.sendScheduledMessagesNow(messageIds)
|
||||
}
|
||||
}, editScheduledMessagesTime: { [weak self] messageIds in
|
||||
if let strongSelf = self {
|
||||
let mode: ChatScheduleTimeControllerMode
|
||||
if case let .peer(peerId) = strongSelf.presentationInterfaceState.chatLocation, peerId == strongSelf.context.account.peerId {
|
||||
mode = .reminders
|
||||
} else {
|
||||
mode = .scheduledMessages
|
||||
}
|
||||
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, completion: { [weak self] scheduleTime in
|
||||
if let strongSelf = self, let messageId = messageIds.first {
|
||||
let signal = (strongSelf.context.account.postbox.transaction { transaction -> Message? in
|
||||
return transaction.getMessage(messageId)
|
||||
}
|
||||
|> introduceError(RequestEditMessageError.self)
|
||||
|> mapToSignal({ message -> Signal<RequestEditMessageResult, RequestEditMessageError> in
|
||||
if let message = message {
|
||||
var entities: TextEntitiesMessageAttribute?
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||
entities = attribute
|
||||
break
|
||||
}
|
||||
}
|
||||
return requestEditMessage(account: strongSelf.context.account, messageId: messageId, text: message.text, media: .keep
|
||||
, entities: entities, disableUrlPreview: false, scheduleTime: scheduleTime)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}))
|
||||
|
||||
strongSelf.editMessageDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
||||
|
||||
}, error: { error in
|
||||
|
||||
}))
|
||||
}
|
||||
})
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
}
|
||||
}, requestMessageUpdate: { [weak self] id in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
|
||||
|
|
@ -1430,7 +1507,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
} else {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .chatInfo:
|
||||
return true
|
||||
|
|
@ -1479,6 +1556,8 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
if case let .peer(peerView) = self.chatLocationInfoData {
|
||||
peerView.set(context.account.viewTracker.peerView(peerId))
|
||||
var onlineMemberCount: Signal<Int32?, NoError> = .single(nil)
|
||||
var hasScheduledMessages: Signal<Bool, NoError> = .single(false)
|
||||
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
let recentOnlineSignal: Signal<Int32, NoError> = context.account.viewTracker.peerView(peerId)
|
||||
|> map { view -> Bool in
|
||||
|
|
@ -1510,19 +1589,27 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
self.reportIrrelvantGeoNoticePromise.set(.single(nil))
|
||||
}
|
||||
|
||||
self.peerDisposable.set((combineLatest(queue: Queue.mainQueue(), peerView.get(), onlineMemberCount, self.reportIrrelvantGeoNoticePromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerView, onlineMemberCount, peerReportNotice in
|
||||
if !isScheduledMessages {
|
||||
hasScheduledMessages = context.account.viewTracker.aroundMessageHistoryViewForLocation(chatLocation, index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil, tagMask: nil, excludeNamespaces: [Namespaces.Message.Cloud, Namespaces.Message.Local], orderStatistics: [])
|
||||
|> map { view, _, _ in
|
||||
return !view.entries.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
self.peerDisposable.set((combineLatest(queue: Queue.mainQueue(), peerView.get(), onlineMemberCount, hasScheduledMessages, self.reportIrrelvantGeoNoticePromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerView, onlineMemberCount, hasScheduledMessages, peerReportNotice in
|
||||
if let strongSelf = self {
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, onlineMemberCount: onlineMemberCount)
|
||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages)
|
||||
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.avatarNode.setPeer(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: peer.isDeleted ? .deletedIcon : .none)
|
||||
}
|
||||
|
||||
if strongSelf.peerView === peerView && strongSelf.reportIrrelvantGeoNotice == peerReportNotice {
|
||||
if strongSelf.peerView === peerView && strongSelf.reportIrrelvantGeoNotice == peerReportNotice && strongSelf.hasScheduledMessages == hasScheduledMessages {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.reportIrrelvantGeoNotice = peerReportNotice
|
||||
strongSelf.hasScheduledMessages = hasScheduledMessages
|
||||
|
||||
var upgradedToPeerId: PeerId?
|
||||
if let previous = strongSelf.peerView, let group = previous.peers[previous.peerId] as? TelegramGroup, group.migrationReference == nil, let updatedGroup = peerView.peers[peerView.peerId] as? TelegramGroup, let migrationReference = updatedGroup.migrationReference {
|
||||
|
|
@ -1689,7 +1776,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
strongSelf.updateChatPresentationInterfaceState(animated: animated, interactive: false, {
|
||||
return $0.updatedPeer { _ in
|
||||
return renderedPeer
|
||||
}.updatedIsNotAccessible(isNotAccessible).updatedContactStatus(contactStatus).updatedHasBots(hasBots).updatedIsArchived(isArchived).updatedPeerIsMuted(peerIsMuted).updatedPeerDiscussionId(peerDiscussionId).updatedPeerGeoLocation(peerGeoLocation).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages)
|
||||
}.updatedIsNotAccessible(isNotAccessible).updatedContactStatus(contactStatus).updatedHasBots(hasBots).updatedIsArchived(isArchived).updatedPeerIsMuted(peerIsMuted).updatedPeerDiscussionId(peerDiscussionId).updatedPeerGeoLocation(peerGeoLocation).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages).updatedHasScheduledMessages(hasScheduledMessages)
|
||||
})
|
||||
if !strongSelf.didSetChatLocationInfoReady {
|
||||
strongSelf.didSetChatLocationInfoReady = true
|
||||
|
|
@ -1699,7 +1786,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
if let upgradedToPeerId = upgradedToPeerId {
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
if let index = viewControllers.index(where: { $0 === strongSelf }) {
|
||||
if let index = viewControllers.firstIndex(where: { $0 === strongSelf }) {
|
||||
viewControllers[index] = ChatController(context: strongSelf.context, chatLocation: .peer(upgradedToPeerId))
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
|
|
@ -1716,7 +1803,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let message = message {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .toastAlert:
|
||||
return true
|
||||
|
|
@ -1737,7 +1824,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
return updatedContexts.sorted()
|
||||
}
|
||||
} else {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .toastAlert:
|
||||
return true
|
||||
|
|
@ -2035,7 +2122,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ChatControllerNode(context: self.context, chatLocation: self.chatLocation, messageId: self.messageId, controllerInteraction: self.controllerInteraction!, chatPresentationInterfaceState: self.presentationInterfaceState, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, navigationBar: self.navigationBar, controller: self)
|
||||
self.displayNode = ChatControllerNode(context: self.context, chatLocation: self.chatLocation, subject: self.subject, controllerInteraction: self.controllerInteraction!, chatPresentationInterfaceState: self.presentationInterfaceState, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, navigationBar: self.navigationBar, controller: self)
|
||||
|
||||
self.chatDisplayNode.peerView = self.peerView
|
||||
|
||||
|
|
@ -2102,7 +2189,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
return context
|
||||
}
|
||||
} else {
|
||||
if let index = context.index(where: {
|
||||
if let index = context.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .pinnedMessage:
|
||||
return true
|
||||
|
|
@ -2250,7 +2337,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
return context
|
||||
}
|
||||
} else {
|
||||
if let index = context.index(where: {
|
||||
if let index = context.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .pinnedMessage:
|
||||
return true
|
||||
|
|
@ -2393,7 +2480,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.sendMessages = { [weak self] messages, silentPosting, isAnyMessageTextPartitioned in
|
||||
self.chatDisplayNode.sendMessages = { [weak self] messages, silentPosting, scheduleTime, isAnyMessageTextPartitioned in
|
||||
if let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation {
|
||||
strongSelf.commitPurposefulAction()
|
||||
|
||||
|
|
@ -2422,6 +2509,8 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
let transformedMessages: [EnqueueMessage]
|
||||
if let silentPosting = silentPosting {
|
||||
transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: silentPosting)
|
||||
} else if let scheduleTime = scheduleTime {
|
||||
transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: scheduleTime)
|
||||
} else {
|
||||
transformedMessages = strongSelf.transformEnqueueMessages(messages)
|
||||
}
|
||||
|
|
@ -2680,7 +2769,14 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
let _ = deleteMessagesInteractively(postbox: strongSelf.context.account.postbox, messageIds: Array(messageIds), type: .forEveryone, deleteAllInGroup: true).start()
|
||||
completion(.dismissWithoutContent)
|
||||
} else {
|
||||
strongSelf.presentDeleteMessageOptions(messageIds: messageIds, options: actions.options, contextController: contextController, completion: completion)
|
||||
var isScheduled = false
|
||||
for id in messageIds {
|
||||
if id.namespace == Namespaces.Message.CloudScheduled {
|
||||
isScheduled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
strongSelf.presentDeleteMessageOptions(messageIds: messageIds, options: isScheduled ? [.deleteLocally] : actions.options, contextController: contextController, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2823,7 +2919,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { current in
|
||||
return current.updatedTitlePanelContext {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .chatInfo:
|
||||
return true
|
||||
|
|
@ -2863,7 +2959,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
var navigateIndex: MessageIndex?
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { current in
|
||||
if let data = current.search, let resultsState = data.resultsState {
|
||||
if let currentId = resultsState.currentId, let index = resultsState.messageIndices.index(where: { $0.id == currentId }) {
|
||||
if let currentId = resultsState.currentId, let index = resultsState.messageIndices.firstIndex(where: { $0.id == currentId }) {
|
||||
var updatedIndex: Int?
|
||||
switch action {
|
||||
case .earlier:
|
||||
|
|
@ -3337,7 +3433,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
|
||||
if canManagePin {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_UnpinMessageAlert, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_No, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Yes, action: {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_UnpinMessageAlert, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Conversation_Unpin, action: {
|
||||
if let strongSelf = self {
|
||||
let disposable: MetaDisposable
|
||||
if let current = strongSelf.unpinMessageDisposable {
|
||||
|
|
@ -3656,6 +3752,11 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
strongSelf.sendMessageActionsController = controller
|
||||
strongSelf.presentInGlobalOverlay(controller, with: nil)
|
||||
}
|
||||
}, openScheduledMessages: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let controller = ChatController(context: strongSelf.context, chatLocation: strongSelf.chatLocation, subject: .scheduledMessages)
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
}
|
||||
}, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get()))
|
||||
|
||||
switch self.chatLocation {
|
||||
|
|
@ -4047,7 +4148,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
|
||||
self.updateChatPresentationInterfaceState(animated: false, interactive: false, {
|
||||
$0.updatedTitlePanelContext {
|
||||
if let index = $0.index(where: {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .chatInfo:
|
||||
return true
|
||||
|
|
@ -5114,18 +5215,25 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
return transformEnqueueMessages(messages, silentPosting: silentPosting)
|
||||
}
|
||||
|
||||
private func transformEnqueueMessages(_ messages: [EnqueueMessage], silentPosting: Bool) -> [EnqueueMessage] {
|
||||
private func transformEnqueueMessages(_ messages: [EnqueueMessage], silentPosting: Bool, scheduleTime: Int32? = nil) -> [EnqueueMessage] {
|
||||
return messages.map { message in
|
||||
if silentPosting {
|
||||
if silentPosting || scheduleTime != nil {
|
||||
return message.withUpdatedAttributes { attributes in
|
||||
var attributes = attributes
|
||||
for i in 0 ..< attributes.count {
|
||||
for i in (0 ..< attributes.count).reversed() {
|
||||
if attributes[i] is NotificationInfoMessageAttribute {
|
||||
attributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
if let _ = scheduleTime, attributes[i] is OutgoingScheduleInfoMessageAttribute {
|
||||
attributes.remove(at: i)
|
||||
}
|
||||
}
|
||||
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
|
||||
if silentPosting {
|
||||
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
|
||||
}
|
||||
if let scheduleTime = scheduleTime {
|
||||
attributes.append(OutgoingScheduleInfoMessageAttribute(scheduleTime: scheduleTime))
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
} else {
|
||||
|
|
@ -5134,8 +5242,16 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
}
|
||||
|
||||
private func sendMessages(_ messages: [EnqueueMessage]) {
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
private func sendScheduledMessagesNow(_ messageId: [MessageId]) {
|
||||
let _ = sendScheduledMessageNow(account: self.context.account, messageId: messageId.first!).start()
|
||||
}
|
||||
|
||||
private func sendMessages(_ messages: [EnqueueMessage], commit: Bool = false) {
|
||||
guard case let .peer(peerId) = self.chatLocation else {
|
||||
return
|
||||
}
|
||||
|
||||
if commit || !self.presentationInterfaceState.isScheduledMessages {
|
||||
self.commitPurposefulAction()
|
||||
|
||||
let _ = (enqueueMessages(account: self.context.account, peerId: peerId, messages: self.transformEnqueueMessages(messages))
|
||||
|
|
@ -5144,6 +5260,20 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
})
|
||||
|
||||
self.donateIntent()
|
||||
} else {
|
||||
let mode: ChatScheduleTimeControllerMode
|
||||
if peerId == self.context.account.peerId {
|
||||
mode = .reminders
|
||||
} else {
|
||||
mode = .scheduledMessages
|
||||
}
|
||||
let controller = ChatScheduleTimeController(context: self.context, mode: mode, completion: { [weak self] time in
|
||||
if let strongSelf = self {
|
||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: time), commit: true)
|
||||
}
|
||||
})
|
||||
self.chatDisplayNode.dismissInput()
|
||||
self.present(controller, in: .window(.root))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5485,7 +5615,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
guard let resultsState = resultsState, let currentId = resultsState.currentId else {
|
||||
return nil
|
||||
}
|
||||
if let index = resultsState.messageIndices.index(where: { $0.id == currentId }) {
|
||||
if let index = resultsState.messageIndices.firstIndex(where: { $0.id == currentId }) {
|
||||
if index <= limit / 2 {
|
||||
return resultsState.state
|
||||
}
|
||||
|
|
@ -5658,7 +5788,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
}
|
||||
|
||||
if case let .peer(peerId) = self.chatLocation, let messageId = messageLocation.messageId, (messageId.peerId != peerId && !forceInCurrentChat) {
|
||||
if case let .peer(peerId) = self.chatLocation, let messageId = messageLocation.messageId, (messageId.peerId != peerId && !forceInCurrentChat) || self.presentationInterfaceState.isScheduledMessages {
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
navigateToChatController(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), messageId: messageId, keepStack: .always)
|
||||
}
|
||||
|
|
@ -5798,7 +5928,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
strongSelf.chatDisplayNode.historyNode.scrollToMessage(from: fromIndex, to: index, animated: animated, scrollPosition: scrollPosition)
|
||||
completion?()
|
||||
} else {
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(ChatController(context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), messageId: messageLocation.messageId))
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(ChatController(context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message($0) }))
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
|
@ -5954,10 +6084,10 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
})
|
||||
} else {
|
||||
(self.navigationController as? NavigationController)?.pushViewController(ChatController(context: self.context, chatLocation: .peer(peerId), messageId: messageId))
|
||||
(self.navigationController as? NavigationController)?.pushViewController(ChatController(context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap({ .message($0) })))
|
||||
}
|
||||
case let .withBotStartPayload(botStart):
|
||||
(self.navigationController as? NavigationController)?.pushViewController(ChatController(context: self.context, chatLocation: .peer(peerId), messageId: nil, botStart: botStart))
|
||||
(self.navigationController as? NavigationController)?.pushViewController(ChatController(context: self.context, chatLocation: .peer(peerId), botStart: botStart))
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
@ -6688,7 +6818,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
self.navigationActionDisposable.set((fetchChannelParticipant(account: self.context.account, peerId: peerId, participantId: author.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] participant in
|
||||
if let strongSelf = self {
|
||||
var canBan = participant?.canBeBannedBy(peerId: accountPeerId) ?? true
|
||||
let canBan = participant?.canBeBannedBy(peerId: accountPeerId) ?? true
|
||||
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
|
@ -6823,13 +6953,17 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||
}
|
||||
if options.contains(.deleteLocally) {
|
||||
var localOptionText = self.presentationData.strings.Conversation_DeleteMessagesForMe
|
||||
if options.contains(.unsendPersonal) {
|
||||
localOptionText = self.presentationData.strings.Chat_DeleteMessagesConfirmation(Int32(messageIds.count))
|
||||
} else if case .peer(self.context.account.peerId) = self.chatLocation {
|
||||
if messageIds.count == 1 {
|
||||
localOptionText = self.presentationData.strings.Conversation_Moderate_Delete
|
||||
} else {
|
||||
localOptionText = self.presentationData.strings.Conversation_DeleteManyMessages
|
||||
if self.presentationInterfaceState.isScheduledMessages {
|
||||
localOptionText = self.presentationData.strings.ScheduledMessages_Delete
|
||||
} else {
|
||||
if options.contains(.unsendPersonal) {
|
||||
localOptionText = self.presentationData.strings.Chat_DeleteMessagesConfirmation(Int32(messageIds.count))
|
||||
} else if case .peer(self.context.account.peerId) = self.chatLocation {
|
||||
if messageIds.count == 1 {
|
||||
localOptionText = self.presentationData.strings.Conversation_Moderate_Delete
|
||||
} else {
|
||||
localOptionText = self.presentationData.strings.Conversation_DeleteManyMessages
|
||||
}
|
||||
}
|
||||
}
|
||||
contextItems.append(.action(ContextMenuActionItem(text: localOptionText, textColor: .destructive, icon: { _ in nil }, action: { [weak self] _, f in
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ public final class ChatControllerInteraction {
|
|||
let openAppStorePage: () -> Void
|
||||
let displayMessageTooltip: (MessageId, String, ASDisplayNode?, CGRect?) -> Void
|
||||
let seekToTimecode: (Message, Double, Bool) -> Void
|
||||
let scheduleCurrentMessage: () -> Void
|
||||
let sendScheduledMessagesNow: ([MessageId]) -> Void
|
||||
let editScheduledMessagesTime: ([MessageId]) -> Void
|
||||
|
||||
let requestMessageUpdate: (MessageId) -> Void
|
||||
let cancelInteractiveKeyboardGestures: () -> Void
|
||||
|
|
@ -100,7 +103,7 @@ public final class ChatControllerInteraction {
|
|||
var searchTextHighightState: String?
|
||||
var seenOneTimeAnimatedMedia = Set<MessageId>()
|
||||
|
||||
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
|
||||
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
|
||||
self.openMessage = openMessage
|
||||
self.openPeer = openPeer
|
||||
self.openPeerMention = openPeerMention
|
||||
|
|
@ -142,7 +145,10 @@ public final class ChatControllerInteraction {
|
|||
self.openAppStorePage = openAppStorePage
|
||||
self.displayMessageTooltip = displayMessageTooltip
|
||||
self.seekToTimecode = seekToTimecode
|
||||
|
||||
self.scheduleCurrentMessage = scheduleCurrentMessage
|
||||
self.sendScheduledMessagesNow = sendScheduledMessagesNow
|
||||
self.editScheduledMessagesTime = editScheduledMessagesTime
|
||||
|
||||
self.requestMessageUpdate = requestMessageUpdate
|
||||
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
|
||||
|
||||
|
|
@ -168,6 +174,9 @@ public final class ChatControllerInteraction {
|
|||
}, openAppStorePage: {
|
||||
}, displayMessageTooltip: { _, _, _, _ in
|
||||
}, seekToTimecode: { _, _, _ in
|
||||
}, scheduleCurrentMessage: {
|
||||
}, sendScheduledMessagesNow: { _ in
|
||||
}, editScheduledMessagesTime: { _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||
|
||||
var requestUpdateChatInterfaceState: (Bool, Bool, (ChatInterfaceState) -> ChatInterfaceState) -> Void = { _, _, _ in }
|
||||
var requestUpdateInterfaceState: (ContainedViewLayoutTransition, Bool, (ChatPresentationInterfaceState) -> ChatPresentationInterfaceState) -> Void = { _, _, _ in }
|
||||
var sendMessages: ([EnqueueMessage], Bool?, Bool) -> Void = { _, _, _ in }
|
||||
var sendMessages: ([EnqueueMessage], Bool?, Int32?, Bool) -> Void = { _, _, _, _ in }
|
||||
var displayAttachmentMenu: () -> Void = { }
|
||||
var paste: (ChatTextInputPanelPasteData) -> Void = { _ in }
|
||||
var updateTypingActivity: (Bool) -> Void = { _ in }
|
||||
|
|
@ -190,7 +190,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||
}
|
||||
}*/
|
||||
|
||||
init(context: AccountContext, chatLocation: ChatLocation, messageId: MessageId?, controllerInteraction: ChatControllerInteraction, chatPresentationInterfaceState: ChatPresentationInterfaceState, automaticMediaDownloadSettings: MediaAutoDownloadSettings, navigationBar: NavigationBar?, controller: ChatController?) {
|
||||
init(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, chatPresentationInterfaceState: ChatPresentationInterfaceState, automaticMediaDownloadSettings: MediaAutoDownloadSettings, navigationBar: NavigationBar?, controller: ChatController?) {
|
||||
self.context = context
|
||||
self.chatLocation = chatLocation
|
||||
self.controllerInteraction = controllerInteraction
|
||||
|
|
@ -205,7 +205,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||
self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||
self.titleAccessoryPanelContainer.clipsToBounds = true
|
||||
|
||||
self.historyNode = ChatHistoryListNode(context: context, chatLocation: chatLocation, tagMask: nil, messageId: messageId, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get())
|
||||
self.historyNode = ChatHistoryListNode(context: context, chatLocation: chatLocation, tagMask: nil, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get())
|
||||
self.historyNode.rotated = true
|
||||
self.historyNodeContainer = ASDisplayNode()
|
||||
self.historyNodeContainer.addSubnode(self.historyNode)
|
||||
|
|
@ -286,7 +286,11 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||
|
||||
self.textInputPanelNode?.sendMessage = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.sendCurrentMessage()
|
||||
if strongSelf.chatPresentationInterfaceState.isScheduledMessages && strongSelf.chatPresentationInterfaceState.editMessageState == nil {
|
||||
strongSelf.controllerInteraction.scheduleCurrentMessage()
|
||||
} else {
|
||||
strongSelf.sendCurrentMessage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2011,7 +2015,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
func sendCurrentMessage(silentPosting: Bool? = nil) {
|
||||
func sendCurrentMessage(silentPosting: Bool? = nil, scheduleTime: Int32? = nil) {
|
||||
if let textInputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode {
|
||||
if textInputPanelNode.textInputNode?.isFirstResponder() ?? false {
|
||||
Keyboard.applyAutocorrection()
|
||||
|
|
@ -2078,7 +2082,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||
}
|
||||
|
||||
if case .peer = self.chatLocation {
|
||||
self.sendMessages(messages, silentPosting, messages.count > 1)
|
||||
self.sendMessages(messages, silentPosting, scheduleTime, messages.count > 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ final class ChatEmptyNode: ASDisplayNode {
|
|||
|
||||
let contentType: ChatEmptyNodeContentType
|
||||
if let peer = interfaceState.renderedPeer?.peer {
|
||||
if peer.id == self.accountPeerId {
|
||||
if peer.id == self.accountPeerId && !interfaceState.isScheduledMessages {
|
||||
contentType = .cloud
|
||||
} else if let _ = peer as? TelegramSecretChat {
|
||||
contentType = .secret
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ private final class ChatHistoryTransactionOpaqueState {
|
|||
}
|
||||
}
|
||||
|
||||
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: StickerPackItem]) -> ChatMessageItemAssociatedData {
|
||||
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: StickerPackItem], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData {
|
||||
var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel
|
||||
var contactsPeerIds: Set<PeerId> = Set()
|
||||
if case let .peer(peerId) = chatLocation {
|
||||
|
|
@ -295,7 +295,7 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
|
|||
}
|
||||
}
|
||||
}
|
||||
let associatedData = ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, contactsPeerIds: contactsPeerIds, animatedEmojiStickers: animatedEmojiStickers)
|
||||
let associatedData = ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, isScheduledMessages: isScheduledMessages, contactsPeerIds: contactsPeerIds, animatedEmojiStickers: animatedEmojiStickers)
|
||||
return associatedData
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ private struct ChatHistoryAnimatedEmojiConfiguration {
|
|||
public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
private let context: AccountContext
|
||||
private let chatLocation: ChatLocation
|
||||
private let messageId: MessageId?
|
||||
private let subject: ChatControllerSubject?
|
||||
private let tagMask: MessageTags?
|
||||
private let controllerInteraction: ChatControllerInteraction
|
||||
private let mode: ChatHistoryListMode
|
||||
|
|
@ -443,10 +443,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||
|
||||
private var loadedMessagesFromCachedDataDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, tagMask: MessageTags?, messageId: MessageId?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal<Set<MessageId>?, NoError>, mode: ChatHistoryListMode = .bubbles) {
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, tagMask: MessageTags?, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal<Set<MessageId>?, NoError>, mode: ChatHistoryListMode = .bubbles) {
|
||||
self.context = context
|
||||
self.chatLocation = chatLocation
|
||||
self.messageId = messageId
|
||||
self.subject = subject
|
||||
self.tagMask = tagMask
|
||||
self.controllerInteraction = controllerInteraction
|
||||
self.mode = mode
|
||||
|
|
@ -572,8 +572,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
} else {
|
||||
if let messageId = messageId {
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
if let subject = subject {
|
||||
switch subject {
|
||||
case let .message(messageId):
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
case .scheduledMessages:
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scheduled, id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
}
|
||||
|
||||
} else {
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Initial(count: 60), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
}
|
||||
|
|
@ -630,7 +636,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||
reverse = reverseValue
|
||||
}
|
||||
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers)
|
||||
var isScheduledMessages = false
|
||||
if let subject = subject, case .scheduledMessages = subject {
|
||||
isScheduledMessages = true
|
||||
}
|
||||
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, isScheduledMessages: isScheduledMessages)
|
||||
|
||||
let processedView = ChatHistoryView(originalView: view, filteredEntries: chatHistoryEntriesForView(location: chatLocation, view: view, includeUnreadEntry: mode == .bubbles, includeEmptyEntry: mode == .bubbles && tagMask == nil, includeChatInfoEntry: mode == .bubbles, includeSearchEntry: includeSearchEntry && tagMask != nil, reverse: reverse, groupMessages: mode == .bubbles, selectedMessages: selectedMessages, presentationData: chatPresentationData, historyAppearsCleared: historyAppearsCleared, associatedData: associatedData), associatedData: associatedData, id: id)
|
||||
let previousValueAndVersion = previousView.swap((processedView, update.1))
|
||||
|
|
@ -666,19 +677,19 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||
updatedScrollPosition = nil
|
||||
} else {
|
||||
switch type {
|
||||
case let .Initial(fadeIn):
|
||||
reason = ChatHistoryViewTransitionReason.Initial(fadeIn: fadeIn)
|
||||
case let .Generic(genericType):
|
||||
switch genericType {
|
||||
case .InitialUnread, .Initial:
|
||||
reason = ChatHistoryViewTransitionReason.Initial(fadeIn: false)
|
||||
case .Generic:
|
||||
reason = ChatHistoryViewTransitionReason.InteractiveChanges
|
||||
case .UpdateVisible:
|
||||
reason = ChatHistoryViewTransitionReason.Reload
|
||||
case .FillHole:
|
||||
reason = ChatHistoryViewTransitionReason.HoleReload
|
||||
}
|
||||
case let .Initial(fadeIn):
|
||||
reason = ChatHistoryViewTransitionReason.Initial(fadeIn: fadeIn)
|
||||
case let .Generic(genericType):
|
||||
switch genericType {
|
||||
case .InitialUnread, .Initial:
|
||||
reason = ChatHistoryViewTransitionReason.Initial(fadeIn: false)
|
||||
case .Generic:
|
||||
reason = ChatHistoryViewTransitionReason.InteractiveChanges
|
||||
case .UpdateVisible:
|
||||
reason = ChatHistoryViewTransitionReason.Reload
|
||||
case .FillHole:
|
||||
reason = ChatHistoryViewTransitionReason.HoleReload
|
||||
}
|
||||
}
|
||||
}
|
||||
let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators)
|
||||
|
|
@ -731,8 +742,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||
}
|
||||
})
|
||||
|
||||
if let messageId = messageId {
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0)
|
||||
if let subject = subject {
|
||||
switch subject {
|
||||
case let .message(messageId):
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0)
|
||||
case .scheduledMessages:
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scheduled, id: 0)
|
||||
}
|
||||
} else {
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Initial(count: 60), id: 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,6 +187,75 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, account: A
|
|||
}
|
||||
return .HistoryView(view: view, type: .Generic(type: genericType), scrollPosition: scrollPosition, flashIndicators: animated, originalScrollPosition: chatScrollPosition, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id)
|
||||
}
|
||||
case .Scheduled:
|
||||
var preloaded = false
|
||||
var fadeIn = false
|
||||
let count = 100
|
||||
let signal = account.viewTracker.aroundMessageHistoryViewForLocation(chatLocation, index: .upperBound, anchorIndex: .upperBound, count: count, fixedCombinedReadStates: nil, tagMask: tagMask, excludeNamespaces: [Namespaces.Message.Cloud, Namespaces.Message.Local], orderStatistics: orderStatistics)
|
||||
return signal
|
||||
|> map { view, updateType, initialData -> ChatHistoryViewUpdate in
|
||||
let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation)
|
||||
|
||||
let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData)
|
||||
|
||||
if preloaded {
|
||||
return .HistoryView(view: view, type: .Generic(type: updateType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: combinedInitialData, id: location.id)
|
||||
} else {
|
||||
if view.isLoading {
|
||||
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
|
||||
}
|
||||
var scrollPosition: ChatHistoryViewScrollPosition?
|
||||
|
||||
if let maxReadIndex = view.maxReadIndex, tagMask == nil {
|
||||
let aroundIndex = maxReadIndex
|
||||
scrollPosition = .unread(index: maxReadIndex)
|
||||
|
||||
var targetIndex = 0
|
||||
for i in 0 ..< view.entries.count {
|
||||
if view.entries[i].index >= aroundIndex {
|
||||
targetIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let maxIndex = targetIndex + count / 2
|
||||
let minIndex = targetIndex - count / 2
|
||||
if minIndex <= 0 && view.holeEarlier {
|
||||
fadeIn = true
|
||||
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
|
||||
}
|
||||
if maxIndex >= targetIndex {
|
||||
if view.holeLater {
|
||||
fadeIn = true
|
||||
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
|
||||
}
|
||||
if view.holeEarlier {
|
||||
var incomingCount: Int32 = 0
|
||||
inner: for entry in view.entries.reversed() {
|
||||
if entry.message.flags.contains(.Incoming) {
|
||||
incomingCount += 1
|
||||
}
|
||||
}
|
||||
if case let .peer(peerId) = chatLocation, let combinedReadStates = view.fixedReadStates, case let .peer(readStates) = combinedReadStates, let readState = readStates[peerId], readState.count == incomingCount {
|
||||
} else {
|
||||
fadeIn = true
|
||||
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let historyScrollState = (initialData?.chatInterfaceState as? ChatInterfaceState)?.historyScrollState, tagMask == nil {
|
||||
scrollPosition = .positionRestoration(index: historyScrollState.messageIndex, relativeOffset: CGFloat(historyScrollState.relativeOffset))
|
||||
} else {
|
||||
if view.entries.isEmpty && (view.holeEarlier || view.holeLater) {
|
||||
fadeIn = true
|
||||
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
|
||||
}
|
||||
}
|
||||
|
||||
preloaded = true
|
||||
return .HistoryView(view: view, type: .Initial(fadeIn: fadeIn), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,10 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
|
|||
}
|
||||
}
|
||||
if chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 {
|
||||
if chatPresentationInterfaceState.hasScheduledMessages {
|
||||
accessoryItems.append(.scheduledMessages)
|
||||
}
|
||||
|
||||
var stickersEnabled = true
|
||||
if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
|
||||
if case .broadcast = peer.info, canSendMessagesToPeer(peer) {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ func canEditMessage(context: AccountContext, limitsConfiguration: LimitsConfigur
|
|||
var hasEditRights = false
|
||||
var unlimitedInterval = false
|
||||
|
||||
|
||||
if message.id.peerId.namespace == Namespaces.Peer.SecretChat || message.id.namespace != Namespaces.Message.Cloud {
|
||||
if message.id.namespace == Namespaces.Message.CloudScheduled {
|
||||
hasEditRights = true
|
||||
} else if message.id.peerId.namespace == Namespaces.Peer.SecretChat || message.id.namespace != Namespaces.Message.Cloud {
|
||||
hasEditRights = false
|
||||
} else if let author = message.author, author.id == context.account.peerId {
|
||||
hasEditRights = true
|
||||
|
|
@ -103,6 +104,9 @@ func canReplyInChat(_ chatPresentationInterfaceState: ChatPresentationInterfaceS
|
|||
guard let peer = chatPresentationInterfaceState.renderedPeer?.peer else {
|
||||
return false
|
||||
}
|
||||
guard !chatPresentationInterfaceState.isScheduledMessages else {
|
||||
return false
|
||||
}
|
||||
|
||||
var canReply = false
|
||||
switch chatPresentationInterfaceState.chatLocation {
|
||||
|
|
@ -278,7 +282,11 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
|||
canDeleteMessage = context.account.peerId == message.author?.id
|
||||
}
|
||||
|
||||
if messages[0].flags.intersection([.Failed, .Unsent]).isEmpty {
|
||||
if message.id.namespace == Namespaces.Message.CloudScheduled {
|
||||
canReply = false
|
||||
canPin = false
|
||||
}
|
||||
else if messages[0].flags.intersection([.Failed, .Unsent]).isEmpty {
|
||||
switch chatPresentationInterfaceState.chatLocation {
|
||||
case .peer:
|
||||
if let channel = messages[0].peers[messages[0].id.peerId] as? TelegramChannel {
|
||||
|
|
@ -372,8 +380,22 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
|||
})))
|
||||
}
|
||||
|
||||
if data.messageActions.options.contains(.sendScheduledNow) {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.ScheduledMessages_SendNow, icon: { _ in return nil }, action: { _, f in
|
||||
controllerInteraction.sendScheduledMessagesNow(selectAll ? messages.map { $0.id } : [message.id])
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
}
|
||||
|
||||
if data.messageActions.options.contains(.editScheduledTime) {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.ScheduledMessages_EditTime, icon: { _ in return nil }, action: { _, f in
|
||||
controllerInteraction.editScheduledMessagesTime(selectAll ? messages.map { $0.id } : [message.id])
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
}
|
||||
|
||||
if data.canEdit {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_Edit, icon: { theme in
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_MessageDialogEdit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
interfaceInteraction.setupEditMessage(messages[0].id)
|
||||
|
|
@ -668,6 +690,8 @@ struct ChatAvailableMessageActionOptions: OptionSet {
|
|||
static let rateCall = ChatAvailableMessageActionOptions(rawValue: 1 << 5)
|
||||
static let cancelSending = ChatAvailableMessageActionOptions(rawValue: 1 << 6)
|
||||
static let unsendPersonal = ChatAvailableMessageActionOptions(rawValue: 1 << 7)
|
||||
static let sendScheduledNow = ChatAvailableMessageActionOptions(rawValue: 1 << 8)
|
||||
static let editScheduledTime = ChatAvailableMessageActionOptions(rawValue: 1 << 9)
|
||||
}
|
||||
|
||||
struct ChatAvailableMessageActions {
|
||||
|
|
@ -724,6 +748,7 @@ func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messag
|
|||
var hadPersonalIncoming = false
|
||||
var hadBanPeerId = false
|
||||
for id in messageIds {
|
||||
let isScheduled = id.namespace == Namespaces.Message.CloudScheduled
|
||||
if optionsMap[id] == nil {
|
||||
optionsMap[id] = []
|
||||
}
|
||||
|
|
@ -740,7 +765,11 @@ func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messag
|
|||
optionsMap[id]!.insert(.rateCall)
|
||||
}
|
||||
}
|
||||
if id.peerId == accountPeerId {
|
||||
if id.namespace == Namespaces.Message.CloudScheduled {
|
||||
optionsMap[id]!.insert(.sendScheduledNow)
|
||||
optionsMap[id]!.insert(.editScheduledTime)
|
||||
optionsMap[id]!.insert(.deleteLocally)
|
||||
} else if id.peerId == accountPeerId {
|
||||
if !(message.flags.isSending || message.flags.contains(.Failed)) {
|
||||
optionsMap[id]!.insert(.forward)
|
||||
}
|
||||
|
|
@ -781,7 +810,7 @@ func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messag
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !message.flags.contains(.Incoming) {
|
||||
optionsMap[id]!.insert(.deleteGlobally)
|
||||
} else {
|
||||
|
|
@ -825,7 +854,7 @@ func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messag
|
|||
}
|
||||
}
|
||||
} else if let user = peer as? TelegramUser {
|
||||
if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction {
|
||||
if !isScheduled && message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction {
|
||||
if !(message.flags.isSending || message.flags.contains(.Failed)) {
|
||||
optionsMap[id]!.insert(.forward)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,22 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
|||
return currentButton
|
||||
} else if let peer = presentationInterfaceState.renderedPeer?.peer {
|
||||
let canClear: Bool
|
||||
if peer is TelegramUser || peer is TelegramGroup || peer is TelegramSecretChat {
|
||||
canClear = true
|
||||
} else if let peer = peer as? TelegramChannel, case .group = peer.info, peer.addressName == nil && presentationInterfaceState.peerGeoLocation == nil {
|
||||
var title = strings.Conversation_ClearAll
|
||||
if presentationInterfaceState.isScheduledMessages {
|
||||
canClear = true
|
||||
title = strings.ScheduledMessages_ClearAll
|
||||
} else {
|
||||
canClear = false
|
||||
if peer is TelegramUser || peer is TelegramGroup || peer is TelegramSecretChat {
|
||||
canClear = true
|
||||
} else if let peer = peer as? TelegramChannel, case .group = peer.info, peer.addressName == nil && presentationInterfaceState.peerGeoLocation == nil {
|
||||
canClear = true
|
||||
} else {
|
||||
canClear = false
|
||||
}
|
||||
}
|
||||
|
||||
if canClear {
|
||||
return ChatNavigationButton(action: .clearHistory, buttonItem: UIBarButtonItem(title: strings.Conversation_ClearAll, style: .plain, target: target, action: selector))
|
||||
return ChatNavigationButton(action: .clearHistory, buttonItem: UIBarButtonItem(title: title, style: .plain, target: target, action: selector))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,9 +60,13 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch
|
|||
if case .standard(true) = presentationInterfaceState.mode {
|
||||
} else if let peer = presentationInterfaceState.renderedPeer?.peer {
|
||||
if presentationInterfaceState.accountPeerId == peer.id {
|
||||
let buttonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(presentationInterfaceState.theme), style: .plain, target: target, action: selector)
|
||||
buttonItem.accessibilityLabel = strings.Conversation_Info
|
||||
return ChatNavigationButton(action: .search, buttonItem: buttonItem)
|
||||
if presentationInterfaceState.isScheduledMessages {
|
||||
return nil
|
||||
} else {
|
||||
let buttonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(presentationInterfaceState.theme), style: .plain, target: target, action: selector)
|
||||
buttonItem.accessibilityLabel = strings.Conversation_Info
|
||||
return ChatNavigationButton(action: .search, buttonItem: buttonItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
|||
}
|
||||
|
||||
var displayActionsPanel = false
|
||||
if !chatPresentationInterfaceState.peerIsBlocked, let contactStatus = chatPresentationInterfaceState.contactStatus, let peerStatusSettings = contactStatus.peerStatusSettings {
|
||||
if !chatPresentationInterfaceState.peerIsBlocked && !chatPresentationInterfaceState.isScheduledMessages, let contactStatus = chatPresentationInterfaceState.contactStatus, let peerStatusSettings = contactStatus.peerStatusSettings {
|
||||
if !peerStatusSettings.isEmpty {
|
||||
if contactStatus.canAddContact && peerStatusSettings.contains(.canAddContact) {
|
||||
displayActionsPanel = true
|
||||
|
|
|
|||
|
|
@ -1226,7 +1226,7 @@ public class ChatListController: TelegramBaseController, UIViewControllerPreview
|
|||
sourceRect = CGRect(x: sourceRect.minX, y: sourceRect.minY + bounds.minY, width: bounds.width, height: bounds.height)
|
||||
sourceRect.size.height -= UIScreenPixel
|
||||
|
||||
let chatController = ChatController(context: self.context, chatLocation: .peer(messageId.peerId), messageId: messageId, mode: .standard(previewing: true))
|
||||
let chatController = ChatController(context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (chatController, sourceRect)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ private let inlineBotNameFont = nameFont
|
|||
|
||||
private class ChatMessageHeartbeatHaptic {
|
||||
private var hapticFeedback = HapticFeedback()
|
||||
var timer: SwiftSignalKit.Timer?
|
||||
var time: Double = 0
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
private var time: Double = 0.0
|
||||
var enabled = false {
|
||||
didSet {
|
||||
if !self.enabled {
|
||||
|
|
@ -57,7 +57,7 @@ private class ChatMessageHeartbeatHaptic {
|
|||
if time > 2.0 {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var startTime: Double = 0.0
|
||||
var delay: Double = 0.0
|
||||
|
||||
|
|
@ -238,7 +238,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let (emoji, fitz) = item.message.text.basicEmoji
|
||||
if self.telegramFile == nil, let emojiFile = item.associatedData.animatedEmojiStickers[emoji]?.file {
|
||||
if self.emojiFile?.id != emojiFile.id {
|
||||
|
|
@ -803,7 +803,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||
|> deliverOnMainQueue
|
||||
}
|
||||
|
||||
if self.item?.message.text == "❤️" {
|
||||
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 {
|
||||
let _ = startTime.start(next: { [weak self] time in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -19,14 +19,16 @@ private let granularity: Int32 = 60 * 60 * 24
|
|||
final class ChatMessageDateHeader: ListViewItemHeader {
|
||||
private let timestamp: Int32
|
||||
private let roundedTimestamp: Int32
|
||||
private let scheduled: Bool
|
||||
|
||||
let id: Int64
|
||||
let presentationData: ChatPresentationData
|
||||
let context: AccountContext
|
||||
let action: ((Int32) -> Void)?
|
||||
|
||||
init(timestamp: Int32, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32) -> Void)? = nil) {
|
||||
init(timestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32) -> Void)? = nil) {
|
||||
self.timestamp = timestamp
|
||||
self.scheduled = scheduled
|
||||
self.presentationData = presentationData
|
||||
self.context = context
|
||||
self.action = action
|
||||
|
|
@ -43,7 +45,7 @@ final class ChatMessageDateHeader: ListViewItemHeader {
|
|||
let height: CGFloat = 34.0
|
||||
|
||||
func node() -> ListViewItemHeaderNode {
|
||||
return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, presentationData: self.presentationData, context: self.context, action: self.action)
|
||||
return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, scheduled: self.scheduled, presentationData: self.presentationData, context: self.context, action: self.action)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||
private var stickDistanceFactor: CGFloat = 0.0
|
||||
private var action: ((Int32) -> Void)? = nil
|
||||
|
||||
init(localTimestamp: Int32, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32) -> Void)? = nil) {
|
||||
init(localTimestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32) -> Void)? = nil) {
|
||||
self.presentationData = presentationData
|
||||
self.context = context
|
||||
|
||||
|
|
@ -137,7 +139,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||
var timeinfoNow: tm = tm()
|
||||
localtime_r(&now, &timeinfoNow)
|
||||
|
||||
let text: String
|
||||
var text: String
|
||||
if timeinfo.tm_year == timeinfoNow.tm_year {
|
||||
if timeinfo.tm_yday == timeinfoNow.tm_yday {
|
||||
text = presentationData.strings.Weekday_Today
|
||||
|
|
@ -148,6 +150,10 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||
text = presentationData.strings.Date_ChatDateHeaderYear(monthAtIndex(Int(timeinfo.tm_mon), strings: presentationData.strings), "\(timeinfo.tm_mday)", "\(1900 + timeinfo.tm_year)").0
|
||||
}
|
||||
|
||||
if scheduled {
|
||||
text = presentationData.strings.ScheduledMessages_ScheduledDate(text).0
|
||||
}
|
||||
|
||||
let attributedString = NSAttributedString(string: text, font: titleFont, textColor: bubbleVariableColor(variableColor: presentationData.theme.theme.chat.serviceMessage.dateTextColor, wallpaper: presentationData.theme.wallpaper))
|
||||
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
||||
|
||||
|
|
|
|||
|
|
@ -212,14 +212,16 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
|||
let automaticDownloadPeerType: MediaAutoDownloadPeerType
|
||||
let automaticDownloadNetworkType: MediaAutoDownloadNetworkType
|
||||
let isRecentActions: Bool
|
||||
let isScheduledMessages: Bool
|
||||
let contactsPeerIds: Set<PeerId>
|
||||
let animatedEmojiStickers: [String: StickerPackItem]
|
||||
let forcedResourceStatus: FileMediaResourceStatus?
|
||||
|
||||
init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool, contactsPeerIds: Set<PeerId> = Set(), animatedEmojiStickers: [String: StickerPackItem] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) {
|
||||
init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set<PeerId> = Set(), animatedEmojiStickers: [String: StickerPackItem] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) {
|
||||
self.automaticDownloadPeerType = automaticDownloadPeerType
|
||||
self.automaticDownloadNetworkType = automaticDownloadNetworkType
|
||||
self.isRecentActions = isRecentActions
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.contactsPeerIds = contactsPeerIds
|
||||
self.animatedEmojiStickers = animatedEmojiStickers
|
||||
self.forcedResourceStatus = forcedResourceStatus
|
||||
|
|
@ -235,9 +237,15 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
|||
if lhs.isRecentActions != rhs.isRecentActions {
|
||||
return false
|
||||
}
|
||||
if lhs.isScheduledMessages != rhs.isScheduledMessages {
|
||||
return false
|
||||
}
|
||||
if lhs.contactsPeerIds != rhs.contactsPeerIds {
|
||||
return false
|
||||
}
|
||||
if lhs.animatedEmojiStickers != rhs.animatedEmojiStickers {
|
||||
return false
|
||||
}
|
||||
if lhs.forcedResourceStatus != rhs.forcedResourceStatus {
|
||||
return false
|
||||
}
|
||||
|
|
@ -320,7 +328,13 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||
|
||||
self.effectiveAuthorId = effectiveAuthor?.id
|
||||
|
||||
self.header = ChatMessageDateHeader(timestamp: content.index.timestamp, presentationData: presentationData, context: context, action: { timestamp in
|
||||
let timestamp: Int32
|
||||
if let scheduleTime = content.firstMessage.scheduleTime {
|
||||
timestamp = scheduleTime
|
||||
} else {
|
||||
timestamp = content.index.timestamp
|
||||
}
|
||||
self.header = ChatMessageDateHeader(timestamp: timestamp, scheduled: associatedData.isScheduledMessages, presentationData: presentationData, context: context, action: { timestamp in
|
||||
var calendar = NSCalendar.current
|
||||
calendar.timeZone = TimeZone(abbreviation: "UTC")!
|
||||
let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
|
||||
|
|
|
|||
|
|
@ -109,9 +109,10 @@ final class ChatPanelInterfaceInteraction {
|
|||
let reportPeerIrrelevantGeoLocation: () -> Void
|
||||
let displaySlowmodeTooltip: (ASDisplayNode, CGRect) -> Void
|
||||
let displaySendMessageOptions: () -> Void
|
||||
let openScheduledMessages: () -> Void
|
||||
let statuses: ChatPanelInterfaceInteractionStatuses?
|
||||
|
||||
init(setupReplyMessage: @escaping (MessageId) -> Void, setupEditMessage: @escaping (MessageId?) -> Void, beginMessageSelection: @escaping ([MessageId]) -> Void, deleteSelectedMessages: @escaping () -> Void, reportSelectedMessages: @escaping () -> Void, reportMessages: @escaping ([Message], ContextController?) -> Void, deleteMessages: @escaping ([Message], ContextController?, @escaping (ContextMenuActionResult) -> Void) -> Void, forwardSelectedMessages: @escaping () -> Void, forwardCurrentForwardMessages: @escaping () -> Void, forwardMessages: @escaping ([Message]) -> Void, shareSelectedMessages: @escaping () -> Void, updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void, updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void, openStickers: @escaping () -> Void, editMessage: @escaping () -> Void, beginMessageSearch: @escaping (ChatSearchDomain, String) -> Void, dismissMessageSearch: @escaping () -> Void, updateMessageSearch: @escaping (String) -> Void, navigateMessageSearch: @escaping (ChatPanelSearchNavigationAction) -> Void, openCalendarSearch: @escaping () -> Void, toggleMembersSearch: @escaping (Bool) -> Void, navigateToMessage: @escaping (MessageId) -> Void, navigateToChat: @escaping (PeerId) -> Void, openPeerInfo: @escaping () -> Void, togglePeerNotifications: @escaping () -> Void, sendContextResult: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool, sendBotCommand: @escaping (Peer, String) -> Void, sendBotStart: @escaping (String?) -> Void, botSwitchChatWithPayload: @escaping (PeerId, String) -> Void, beginMediaRecording: @escaping (Bool) -> Void, finishMediaRecording: @escaping (ChatFinishMediaRecordingAction) -> Void, stopMediaRecording: @escaping () -> Void, lockMediaRecording: @escaping () -> Void, deleteRecordedMedia: @escaping () -> Void, sendRecordedMedia: @escaping () -> Void, displayRestrictedInfo: @escaping (ChatPanelRestrictionInfoSubject, ChatPanelRestrictionInfoDisplayType) -> Void, displayVideoUnmuteTip: @escaping (CGPoint?) -> Void, switchMediaRecordingMode: @escaping () -> Void, setupMessageAutoremoveTimeout: @escaping () -> Void, sendSticker: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, unblockPeer: @escaping () -> Void, pinMessage: @escaping (MessageId) -> Void, unpinMessage: @escaping () -> Void, shareAccountContact: @escaping () -> Void, reportPeer: @escaping () -> Void, presentPeerContact: @escaping () -> Void, dismissReportPeer: @escaping () -> Void, deleteChat: @escaping () -> Void, beginCall: @escaping () -> Void, toggleMessageStickerStarred: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, navigateFeed: @escaping () -> Void, openGrouping: @escaping () -> Void, toggleSilentPost: @escaping () -> Void, requestUnvoteInMessage: @escaping (MessageId) -> Void, requestStopPollInMessage: @escaping (MessageId) -> Void, updateInputLanguage: @escaping ((String?) -> String?) -> Void, unarchiveChat: @escaping () -> Void, openLinkEditing: @escaping () -> Void, reportPeerIrrelevantGeoLocation: @escaping () -> Void, displaySlowmodeTooltip: @escaping (ASDisplayNode, CGRect) -> Void, displaySendMessageOptions: @escaping () -> Void, statuses: ChatPanelInterfaceInteractionStatuses?) {
|
||||
init(setupReplyMessage: @escaping (MessageId) -> Void, setupEditMessage: @escaping (MessageId?) -> Void, beginMessageSelection: @escaping ([MessageId]) -> Void, deleteSelectedMessages: @escaping () -> Void, reportSelectedMessages: @escaping () -> Void, reportMessages: @escaping ([Message], ContextController?) -> Void, deleteMessages: @escaping ([Message], ContextController?, @escaping (ContextMenuActionResult) -> Void) -> Void, forwardSelectedMessages: @escaping () -> Void, forwardCurrentForwardMessages: @escaping () -> Void, forwardMessages: @escaping ([Message]) -> Void, shareSelectedMessages: @escaping () -> Void, updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void, updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void, openStickers: @escaping () -> Void, editMessage: @escaping () -> Void, beginMessageSearch: @escaping (ChatSearchDomain, String) -> Void, dismissMessageSearch: @escaping () -> Void, updateMessageSearch: @escaping (String) -> Void, navigateMessageSearch: @escaping (ChatPanelSearchNavigationAction) -> Void, openCalendarSearch: @escaping () -> Void, toggleMembersSearch: @escaping (Bool) -> Void, navigateToMessage: @escaping (MessageId) -> Void, navigateToChat: @escaping (PeerId) -> Void, openPeerInfo: @escaping () -> Void, togglePeerNotifications: @escaping () -> Void, sendContextResult: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool, sendBotCommand: @escaping (Peer, String) -> Void, sendBotStart: @escaping (String?) -> Void, botSwitchChatWithPayload: @escaping (PeerId, String) -> Void, beginMediaRecording: @escaping (Bool) -> Void, finishMediaRecording: @escaping (ChatFinishMediaRecordingAction) -> Void, stopMediaRecording: @escaping () -> Void, lockMediaRecording: @escaping () -> Void, deleteRecordedMedia: @escaping () -> Void, sendRecordedMedia: @escaping () -> Void, displayRestrictedInfo: @escaping (ChatPanelRestrictionInfoSubject, ChatPanelRestrictionInfoDisplayType) -> Void, displayVideoUnmuteTip: @escaping (CGPoint?) -> Void, switchMediaRecordingMode: @escaping () -> Void, setupMessageAutoremoveTimeout: @escaping () -> Void, sendSticker: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, unblockPeer: @escaping () -> Void, pinMessage: @escaping (MessageId) -> Void, unpinMessage: @escaping () -> Void, shareAccountContact: @escaping () -> Void, reportPeer: @escaping () -> Void, presentPeerContact: @escaping () -> Void, dismissReportPeer: @escaping () -> Void, deleteChat: @escaping () -> Void, beginCall: @escaping () -> Void, toggleMessageStickerStarred: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, navigateFeed: @escaping () -> Void, openGrouping: @escaping () -> Void, toggleSilentPost: @escaping () -> Void, requestUnvoteInMessage: @escaping (MessageId) -> Void, requestStopPollInMessage: @escaping (MessageId) -> Void, updateInputLanguage: @escaping ((String?) -> String?) -> Void, unarchiveChat: @escaping () -> Void, openLinkEditing: @escaping () -> Void, reportPeerIrrelevantGeoLocation: @escaping () -> Void, displaySlowmodeTooltip: @escaping (ASDisplayNode, CGRect) -> Void, displaySendMessageOptions: @escaping () -> Void, openScheduledMessages: @escaping () -> Void, statuses: ChatPanelInterfaceInteractionStatuses?) {
|
||||
self.setupReplyMessage = setupReplyMessage
|
||||
self.setupEditMessage = setupEditMessage
|
||||
self.beginMessageSelection = beginMessageSelection
|
||||
|
|
@ -176,6 +177,7 @@ final class ChatPanelInterfaceInteraction {
|
|||
self.reportPeerIrrelevantGeoLocation = reportPeerIrrelevantGeoLocation
|
||||
self.displaySlowmodeTooltip = displaySlowmodeTooltip
|
||||
self.displaySendMessageOptions = displaySendMessageOptions
|
||||
self.openScheduledMessages = openScheduledMessages
|
||||
self.statuses = statuses
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,8 +389,10 @@ final class ChatPresentationInterfaceState: Equatable {
|
|||
let fontSize: PresentationFontSize
|
||||
let accountPeerId: PeerId
|
||||
let mode: ChatControllerPresentationMode
|
||||
let hasScheduledMessages: Bool
|
||||
let isScheduledMessages: Bool
|
||||
|
||||
init(chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, limitsConfiguration: LimitsConfiguration, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation) {
|
||||
init(chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, limitsConfiguration: LimitsConfiguration, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation, isScheduledMessages: Bool) {
|
||||
self.interfaceState = ChatInterfaceState()
|
||||
self.inputTextPanelState = ChatTextInputPanelState()
|
||||
self.editMessageState = nil
|
||||
|
|
@ -430,9 +432,11 @@ final class ChatPresentationInterfaceState: Equatable {
|
|||
self.fontSize = fontSize
|
||||
self.accountPeerId = accountPeerId
|
||||
self.mode = mode
|
||||
self.hasScheduledMessages = false
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
}
|
||||
|
||||
init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isNotAccessible: Bool, explicitelyCanPinMessages: Bool, contactStatus: ChatContactStatus?, hasBots: Bool, isArchived: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, peerDiscussionId: PeerId?, peerGeoLocation: PeerGeoLocation?, callsAvailable: Bool, callsPrivate: Bool, slowmodeState: ChatSlowmodeState?, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, limitsConfiguration: LimitsConfiguration, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) {
|
||||
init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isNotAccessible: Bool, explicitelyCanPinMessages: Bool, contactStatus: ChatContactStatus?, hasBots: Bool, isArchived: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, peerDiscussionId: PeerId?, peerGeoLocation: PeerGeoLocation?, callsAvailable: Bool, callsPrivate: Bool, slowmodeState: ChatSlowmodeState?, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, limitsConfiguration: LimitsConfiguration, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, hasScheduledMessages: Bool, isScheduledMessages: Bool) {
|
||||
self.interfaceState = interfaceState
|
||||
self.chatLocation = chatLocation
|
||||
self.renderedPeer = renderedPeer
|
||||
|
|
@ -472,6 +476,8 @@ final class ChatPresentationInterfaceState: Equatable {
|
|||
self.fontSize = fontSize
|
||||
self.accountPeerId = accountPeerId
|
||||
self.mode = mode
|
||||
self.hasScheduledMessages = hasScheduledMessages
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
}
|
||||
|
||||
static func ==(lhs: ChatPresentationInterfaceState, rhs: ChatPresentationInterfaceState) -> Bool {
|
||||
|
|
@ -611,35 +617,41 @@ final class ChatPresentationInterfaceState: Equatable {
|
|||
if lhs.mode != rhs.mode {
|
||||
return false
|
||||
}
|
||||
if lhs.hasScheduledMessages != rhs.hasScheduledMessages {
|
||||
return false
|
||||
}
|
||||
if lhs.isScheduledMessages != rhs.isScheduledMessages {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func updatedInterfaceState(_ f: (ChatInterfaceState) -> ChatInterfaceState) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPeer(_ f: (RenderedPeer?) -> RenderedPeer?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedIsNotAccessible(_ isNotAccessible: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedExplicitelyCanPinMessages(_ explicitelyCanPinMessages: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedContactStatus(_ contactStatus: ChatContactStatus?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedHasBots(_ hasBots: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedIsArchived(_ isArchived: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedInputQueryResult(queryKind: ChatPresentationInputQueryKind, _ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState {
|
||||
|
|
@ -650,111 +662,115 @@ final class ChatPresentationInterfaceState: Equatable {
|
|||
} else {
|
||||
inputQueryResults.removeValue(forKey: queryKind)
|
||||
}
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedInputTextPanelState(_ f: (ChatTextInputPanelState) -> ChatTextInputPanelState) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedEditMessageState(_ editMessageState: ChatEditInterfaceMessageState?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedRecordedMediaPreview(_ recordedMediaPreview: ChatRecordedMediaPreview?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedInputMode(_ f: (ChatInputMode) -> ChatInputMode) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedTitlePanelContext(_ f: ([ChatTitlePanelContext]) -> [ChatTitlePanelContext]) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedKeyboardButtonsMessage(_ message: Message?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPinnedMessage(_ pinnedMessage: Message?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPeerIsBlocked(_ peerIsBlocked: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPeerIsMuted(_ peerIsMuted: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPeerDiscussionId(_ peerDiscussionId: PeerId?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedCallsAvailable(_ callsAvailable: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedCallsPrivate(_ callsPrivate: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedSlowmodeState(_ slowmodeState: ChatSlowmodeState?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedBotStartPayload(_ botStartPayload: String?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedChatHistoryState(_ chatHistoryState: ChatHistoryNodeHistoryState?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedUrlPreview(_ urlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedEditingUrlPreview(_ editingUrlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedSearch(_ search: ChatSearchData?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedSearchQuerySuggestionResult(_ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedMode(_ mode: ChatControllerPresentationMode) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedTheme(_ theme: PresentationTheme) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedStrings(_ strings: PresentationStrings) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedDateTimeFormat(_ dateTimeFormat: PresentationDateTimeFormat) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedChatWallpaper(_ chatWallpaper: TelegramWallpaper) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
|
||||
func updatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> ChatPresentationInterfaceState {
|
||||
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, hasBots: self.hasBots, isArchived: self.isArchived, 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, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, 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, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: hasScheduledMessages, isScheduledMessages: self.isScheduledMessages)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ final class ChatRecentActionsController: TelegramBaseController {
|
|||
}, reportPeerIrrelevantGeoLocation: {
|
||||
}, displaySlowmodeTooltip: { _, _ in
|
||||
}, displaySendMessageOptions: {
|
||||
}, openScheduledMessages: {
|
||||
}, statuses: nil)
|
||||
|
||||
self.navigationItem.titleView = self.titleView
|
||||
|
|
|
|||
|
|
@ -395,6 +395,9 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||
}
|
||||
}, displayMessageTooltip: { _, _, _, _ in
|
||||
}, seekToTimecode: { _, _, _ in
|
||||
}, scheduleCurrentMessage: {
|
||||
}, sendScheduledMessagesNow: { _ in
|
||||
}, editScheduledMessagesTime: { _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import AccountContext
|
||||
|
||||
enum ChatScheduleTimeControllerMode {
|
||||
case scheduledMessages
|
||||
case reminders
|
||||
}
|
||||
|
||||
final class ChatScheduleTimeController: ViewController {
|
||||
private var controllerNode: ChatScheduleTimeControllerNode {
|
||||
return self.displayNode as! ChatScheduleTimeControllerNode
|
||||
}
|
||||
|
||||
private var animatedIn = false
|
||||
|
||||
private let context: AccountContext
|
||||
private let mode: ChatScheduleTimeControllerMode
|
||||
private let completion: (Int32) -> Void
|
||||
|
||||
init(context: AccountContext, mode: ChatScheduleTimeControllerMode, completion: @escaping (Int32) -> Void) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.completion = completion
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
|
||||
self.statusBar.statusBarStyle = .Ignore
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ChatScheduleTimeControllerNode(context: self.context, mode: self.mode)
|
||||
self.controllerNode.completion = { [weak self] time in
|
||||
self?.completion(time + 5)
|
||||
self?.dismiss()
|
||||
}
|
||||
self.controllerNode.dismiss = { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
self.controllerNode.cancel = { [weak self] in
|
||||
self?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override public func loadView() {
|
||||
super.loadView()
|
||||
|
||||
self.statusBar.removeFromSupernode()
|
||||
}
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if !self.animatedIn {
|
||||
self.animatedIn = true
|
||||
self.controllerNode.animateIn()
|
||||
}
|
||||
}
|
||||
|
||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||
self.controllerNode.animateOut(completion: completion)
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramStringFormatting
|
||||
import AccountContext
|
||||
import ShareController
|
||||
|
||||
class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private let mode: ChatScheduleTimeControllerMode
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private let dimNode: ASDisplayNode
|
||||
private let wrappingScrollNode: ASScrollNode
|
||||
private let contentContainerNode: ASDisplayNode
|
||||
private let contentBackgroundNode: ASImageNode
|
||||
private let titleNode: ASTextNode
|
||||
private let separatorNode: ASDisplayNode
|
||||
private let cancelButton: HighlightableButtonNode
|
||||
private let doneButton: SolidRoundedButtonNode
|
||||
|
||||
private let pickerView: UIDatePicker
|
||||
private let dateFormatter: DateFormatter
|
||||
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
var completion: ((Int32) -> Void)?
|
||||
var dismiss: (() -> Void)?
|
||||
var cancel: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, mode: ChatScheduleTimeControllerMode) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.wrappingScrollNode = ASScrollNode()
|
||||
self.wrappingScrollNode.view.alwaysBounceVertical = true
|
||||
self.wrappingScrollNode.view.delaysContentTouches = false
|
||||
self.wrappingScrollNode.view.canCancelContentTouches = true
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
||||
|
||||
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
self.contentContainerNode.isOpaque = false
|
||||
self.contentContainerNode.clipsToBounds = true
|
||||
|
||||
self.contentBackgroundNode = ASImageNode()
|
||||
self.contentBackgroundNode.displaysAsynchronously = false
|
||||
self.contentBackgroundNode.displayWithoutProcessing = true
|
||||
self.contentBackgroundNode.image = roundedBackground
|
||||
|
||||
let title: String
|
||||
switch mode {
|
||||
case .scheduledMessages:
|
||||
title = self.presentationData.strings.Conversation_ScheduleMessage_Title
|
||||
case .reminders:
|
||||
title = self.presentationData.strings.Conversation_SetReminder_Title
|
||||
}
|
||||
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
||||
|
||||
self.separatorNode = ASDisplayNode()
|
||||
//self.separatorNode.backgroundColor = self.theme.controlColor
|
||||
|
||||
self.cancelButton = HighlightableButtonNode()
|
||||
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
|
||||
self.doneButton = SolidRoundedButtonNode(theme: self.presentationData.theme, height: 52.0, cornerRadius: 11.0, gloss: false)
|
||||
|
||||
self.pickerView = UIDatePicker()
|
||||
self.pickerView.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
self.pickerView.datePickerMode = .dateAndTime
|
||||
self.pickerView.locale = localeWithStrings(self.presentationData.strings)
|
||||
|
||||
self.dateFormatter = DateFormatter()
|
||||
self.dateFormatter.timeStyle = .none
|
||||
self.dateFormatter.dateStyle = .short
|
||||
self.dateFormatter.timeZone = TimeZone.current
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = nil
|
||||
self.isOpaque = false
|
||||
|
||||
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
|
||||
self.addSubnode(self.dimNode)
|
||||
|
||||
self.wrappingScrollNode.view.delegate = self
|
||||
self.addSubnode(self.wrappingScrollNode)
|
||||
|
||||
self.wrappingScrollNode.addSubnode(self.contentBackgroundNode)
|
||||
self.wrappingScrollNode.addSubnode(self.contentContainerNode)
|
||||
|
||||
self.contentContainerNode.addSubnode(self.titleNode)
|
||||
self.contentContainerNode.addSubnode(self.cancelButton)
|
||||
self.contentContainerNode.addSubnode(self.doneButton)
|
||||
|
||||
self.pickerView.timeZone = TimeZone.current
|
||||
self.pickerView.minuteInterval = 5
|
||||
self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1))
|
||||
|
||||
self.pickerView.setValue(self.presentationData.theme.actionSheet.primaryTextColor, forKey: "textColor")
|
||||
|
||||
self.contentContainerNode.view.addSubview(self.pickerView)
|
||||
self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
|
||||
|
||||
self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.doneButton.pressed = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if strongSelf.pickerView.date < Date() {
|
||||
strongSelf.updateMinimumDate()
|
||||
strongSelf.pickerView.layer.addShakeAnimation()
|
||||
} else {
|
||||
strongSelf.completion?(Int32(strongSelf.pickerView.date.timeIntervalSince1970))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.updateMinimumDate()
|
||||
self.updateButtonTitle()
|
||||
}
|
||||
|
||||
private func updateMinimumDate() {
|
||||
let timeZone = TimeZone(secondsFromGMT: 0)!
|
||||
var calendar = Calendar(identifier: .gregorian)
|
||||
calendar.timeZone = timeZone
|
||||
let currentDate = Date()
|
||||
var components = calendar.dateComponents(Set([.era, .year, .month, .day, .hour, .minute, .second]), from: currentDate)
|
||||
components.second = 0
|
||||
let minute = (components.minute ?? 0) % 5
|
||||
|
||||
if let date = calendar.date(byAdding: .minute, value: 5 - minute, to: calendar.date(from: components)!) {
|
||||
self.pickerView.minimumDate = date
|
||||
self.pickerView.date = date
|
||||
}
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||
self.wrappingScrollNode.view.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
}
|
||||
|
||||
private func updateButtonTitle() {
|
||||
let calendar = Calendar(identifier: .gregorian)
|
||||
let date = self.pickerView.date
|
||||
|
||||
let time = stringForMessageTimestamp(timestamp: Int32(date.timeIntervalSince1970), dateTimeFormat: self.presentationData.dateTimeFormat)
|
||||
switch mode {
|
||||
case .scheduledMessages:
|
||||
if calendar.isDateInToday(date) {
|
||||
self.doneButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendToday(time).0
|
||||
} else if calendar.isDateInTomorrow(date) {
|
||||
self.doneButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendTomorrow(time).0
|
||||
} else {
|
||||
self.doneButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendOn(self.dateFormatter.string(from: date), time).0
|
||||
}
|
||||
case .reminders:
|
||||
if calendar.isDateInToday(date) {
|
||||
self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindToday(time).0
|
||||
} else if calendar.isDateInTomorrow(date) {
|
||||
self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindTomorrow(time).0
|
||||
} else {
|
||||
self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindOn(self.dateFormatter.string(from: date), time).0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func datePickerUpdated() {
|
||||
self.updateButtonTitle()
|
||||
if self.pickerView.date < Date() {
|
||||
self.doneButton.alpha = 0.4
|
||||
self.doneButton.isUserInteractionEnabled = false
|
||||
} else {
|
||||
self.doneButton.alpha = 1.0
|
||||
self.doneButton.isUserInteractionEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
@objc func cancelButtonPressed() {
|
||||
self.cancel?()
|
||||
}
|
||||
|
||||
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.cancelButtonPressed()
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||
|
||||
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
|
||||
|
||||
let dimPosition = self.dimNode.layer.position
|
||||
self.dimNode.layer.animatePosition(from: CGPoint(x: dimPosition.x, y: dimPosition.y - offset), to: dimPosition, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
self.layer.animateBoundsOriginYAdditive(from: -offset, to: 0.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
|
||||
func animateOut(completion: (() -> Void)? = nil) {
|
||||
var dimCompleted = false
|
||||
var offsetCompleted = false
|
||||
|
||||
let internalCompletion: () -> Void = { [weak self] in
|
||||
if let strongSelf = self, dimCompleted && offsetCompleted {
|
||||
strongSelf.dismiss?()
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
|
||||
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||
dimCompleted = true
|
||||
internalCompletion()
|
||||
})
|
||||
|
||||
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
|
||||
let dimPosition = self.dimNode.layer.position
|
||||
self.dimNode.layer.animatePosition(from: dimPosition, to: CGPoint(x: dimPosition.x, y: dimPosition.y - offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
self.layer.animateBoundsOriginYAdditive(from: 0.0, to: -offset, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
||||
offsetCompleted = true
|
||||
internalCompletion()
|
||||
})
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.bounds.contains(point) {
|
||||
if !self.contentBackgroundNode.bounds.contains(self.convert(point, to: self.contentBackgroundNode)) {
|
||||
return self.dimNode.view
|
||||
}
|
||||
}
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
let contentOffset = scrollView.contentOffset
|
||||
let additionalTopHeight = max(0.0, -contentOffset.y)
|
||||
|
||||
if additionalTopHeight >= 30.0 {
|
||||
self.cancelButtonPressed()
|
||||
}
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.containerLayout = (layout, navigationBarHeight)
|
||||
|
||||
var insets = layout.insets(options: [.statusBar, .input])
|
||||
let cleanInsets = layout.insets(options: [.statusBar])
|
||||
insets.top = max(10.0, insets.top)
|
||||
|
||||
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom
|
||||
let titleAreaHeight: CGFloat = 54.0
|
||||
let contentHeight = titleAreaHeight + bottomInset + 285.0
|
||||
let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: layout.safeInsets.left)
|
||||
|
||||
let sideInset = floor((layout.size.width - width) / 2.0)
|
||||
let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: layout.size.height - contentHeight), size: CGSize(width: width, height: contentHeight))
|
||||
let contentFrame = contentContainerFrame
|
||||
|
||||
var backgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX, y: contentFrame.minY), size: CGSize(width: contentFrame.width, height: contentFrame.height + 2000.0))
|
||||
if backgroundFrame.minY < contentFrame.minY {
|
||||
backgroundFrame.origin.y = contentFrame.minY
|
||||
}
|
||||
transition.updateFrame(node: self.contentBackgroundNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.wrappingScrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
|
||||
let titleSize = self.titleNode.measure(CGSize(width: width, height: titleAreaHeight))
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 16.0), size: titleSize)
|
||||
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
||||
|
||||
let cancelSize = self.cancelButton.measure(CGSize(width: width, height: titleAreaHeight))
|
||||
let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
|
||||
transition.updateFrame(node: self.cancelButton, frame: cancelFrame)
|
||||
|
||||
let buttonInset: CGFloat = 16.0
|
||||
let buttonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
||||
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - buttonHeight - insets.bottom - 10.0, width: contentFrame.width, height: buttonHeight))
|
||||
|
||||
self.pickerView.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: 216.0))
|
||||
|
||||
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
||||
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: titleAreaHeight), size: CGSize(width: contentContainerFrame.size.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
|
|
@ -61,12 +61,20 @@ final class ChatSendMessageActionSheetController: ViewController {
|
|||
forwardedCount = forwardMessageIds.count
|
||||
}
|
||||
|
||||
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, sendButtonFrame: self.sendButtonFrame, textInputNode: self.textInputNode, forwardedCount: forwardedCount, send: { [weak self] in
|
||||
var reminders = false
|
||||
if case let .peer(peerId) = self.interfaceState.chatLocation, peerId == context.account.peerId {
|
||||
reminders = true
|
||||
}
|
||||
|
||||
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, reminders: reminders, sendButtonFrame: self.sendButtonFrame, textInputNode: self.textInputNode, forwardedCount: forwardedCount, send: { [weak self] in
|
||||
self?.controllerInteraction?.sendCurrentMessage(false)
|
||||
self?.dismiss(cancel: false)
|
||||
}, sendSilently: { [weak self] in
|
||||
self?.controllerInteraction?.sendCurrentMessage(true)
|
||||
self?.dismiss(cancel: false)
|
||||
}, schedule: { [weak self] in
|
||||
self?.controllerInteraction?.scheduleCurrentMessage()
|
||||
self?.dismiss(cancel: false)
|
||||
}, cancel: { [weak self] in
|
||||
self?.dismiss(cancel: true)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,8 +11,25 @@ import AccountContext
|
|||
private let leftInset: CGFloat = 16.0
|
||||
private let rightInset: CGFloat = 46.0
|
||||
|
||||
private enum ChatSendMessageActionIcon {
|
||||
case sendWithoutSound
|
||||
case schedule
|
||||
|
||||
func image(theme: PresentationTheme) -> UIImage? {
|
||||
let imageName: String
|
||||
switch self {
|
||||
case .sendWithoutSound:
|
||||
imageName = "Chat/Input/Menu/SilentIcon"
|
||||
case .schedule:
|
||||
imageName = "Chat/Input/Menu/ScheduleIcon"
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.actionSheet.primaryTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
private final class ActionSheetItemNode: ASDisplayNode {
|
||||
private let title: String
|
||||
private let icon: ChatSendMessageActionIcon
|
||||
private let action: () -> Void
|
||||
|
||||
private let separatorNode: ASDisplayNode
|
||||
|
|
@ -23,8 +40,9 @@ private final class ActionSheetItemNode: ASDisplayNode {
|
|||
|
||||
private var maxWidth: CGFloat?
|
||||
|
||||
init(theme: PresentationTheme, title: String, action: @escaping () -> Void) {
|
||||
init(theme: PresentationTheme, title: String, icon: ChatSendMessageActionIcon, hasSeparator: Bool, action: @escaping () -> Void) {
|
||||
self.title = title
|
||||
self.icon = icon
|
||||
self.action = action
|
||||
|
||||
self.separatorNode = ASDisplayNode()
|
||||
|
|
@ -41,7 +59,7 @@ private final class ActionSheetItemNode: ASDisplayNode {
|
|||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.regular(17.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
|
||||
self.iconNode.image = icon.image(theme: theme)
|
||||
self.iconNode.contentMode = .center
|
||||
|
||||
super.init()
|
||||
|
|
@ -50,6 +68,9 @@ private final class ActionSheetItemNode: ASDisplayNode {
|
|||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
if hasSeparator {
|
||||
self.addSubnode(self.separatorNode)
|
||||
}
|
||||
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
||||
|
|
@ -69,7 +90,7 @@ private final class ActionSheetItemNode: ASDisplayNode {
|
|||
self.separatorNode.backgroundColor = theme.actionSheet.opaqueItemSeparatorColor
|
||||
self.highlightedBackgroundNode.backgroundColor = theme.actionSheet.opaqueItemHighlightedBackgroundColor
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.regular(17.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
|
||||
self.iconNode.image = self.icon.image(theme: theme)
|
||||
|
||||
if let maxWidth = self.maxWidth {
|
||||
let _ = self.titleNode.updateLayout(CGSize(width: maxWidth - leftInset - rightInset, height: .greatestFiniteMagnitude))
|
||||
|
|
@ -130,7 +151,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
init(context: AccountContext, sendButtonFrame: CGRect, textInputNode: EditableTextNode, forwardedCount: Int?, send: (() -> Void)?, sendSilently: (() -> Void)?, cancel: (() -> Void)?) {
|
||||
init(context: AccountContext, reminders: Bool, sendButtonFrame: CGRect, textInputNode: EditableTextNode, forwardedCount: Int?, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
|
||||
self.context = context
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.sendButtonFrame = sendButtonFrame
|
||||
|
|
@ -188,8 +209,13 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
self.contentContainerNode.clipsToBounds = true
|
||||
|
||||
var contentNodes: [ActionSheetItemNode] = []
|
||||
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: self.presentationData.strings.Conversation_SendMessage_SendSilently, action: {
|
||||
sendSilently?()
|
||||
if !reminders {
|
||||
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: self.presentationData.strings.Conversation_SendMessage_SendSilently, icon: .sendWithoutSound, hasSeparator: true, action: {
|
||||
sendSilently?()
|
||||
}))
|
||||
}
|
||||
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: reminders ? self.presentationData.strings.Conversation_SendMessage_SetReminder: self.presentationData.strings.Conversation_SendMessage_ScheduleMessage, icon: .schedule, hasSeparator: false, action: {
|
||||
schedule?()
|
||||
}))
|
||||
self.contentNodes = contentNodes
|
||||
|
||||
|
|
@ -218,8 +244,8 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
}
|
||||
self.messageBackgroundNode.contentMode = .scaleToFill
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: self.context.account.postbox.mediaBox, knockoutWallpaper: self.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper)
|
||||
self.messageBackgroundNode.image = graphics.chatMessageBackgroundOutgoingImage
|
||||
let outgoing: PresentationThemeBubbleColorComponents = self.presentationData.chatWallpaper.isEmpty ? self.presentationData.theme.chat.message.outgoing.bubble.withoutWallpaper : self.presentationData.theme.chat.message.outgoing.bubble.withWallpaper
|
||||
self.messageBackgroundNode.image = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: self.presentationData.theme.chat, wallpaper: self.presentationData.chatWallpaper, knockout: false)
|
||||
|
||||
self.view.addSubview(self.effectView)
|
||||
self.addSubnode(self.dimNode)
|
||||
|
|
@ -264,6 +290,9 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
guard presentationData.theme !== self.presentationData.theme else {
|
||||
return
|
||||
}
|
||||
self.presentationData = presentationData
|
||||
|
||||
if self.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
|
||||
|
|
@ -288,8 +317,8 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
self.toMessageTextNode.attributedText = toAttributedText
|
||||
}
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: self.context.account.postbox.mediaBox, knockoutWallpaper: self.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper)
|
||||
self.messageBackgroundNode.image = graphics.chatMessageBackgroundOutgoingImage
|
||||
let outgoing: PresentationThemeBubbleColorComponents = self.presentationData.chatWallpaper.isEmpty ? self.presentationData.theme.chat.message.outgoing.bubble.withoutWallpaper : self.presentationData.theme.chat.message.outgoing.bubble.withWallpaper
|
||||
self.messageBackgroundNode.image = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: self.presentationData.theme.chat, wallpaper: self.presentationData.chatWallpaper, knockout: false)
|
||||
|
||||
for node in self.contentNodes {
|
||||
node.updateTheme(presentationData.theme)
|
||||
|
|
@ -355,7 +384,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
let inputHeight = layout.inputHeight ?? 0.0
|
||||
var clipDelta = delta
|
||||
if inputHeight.isZero {
|
||||
clipDelta -= 60.0
|
||||
clipDelta -= self.contentContainerNode.frame.height + 16.0
|
||||
}
|
||||
|
||||
self.messageClipNode.layer.animateBounds(from: fromFrame, to: self.messageClipNode.bounds, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
|
|
@ -449,7 +478,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
let inputHeight = layout.inputHeight ?? 0.0
|
||||
var clipDelta = delta
|
||||
if inputHeight.isZero {
|
||||
clipDelta -= 60.0
|
||||
clipDelta -= self.contentContainerNode.frame.height + 16.0
|
||||
}
|
||||
|
||||
if cancel {
|
||||
|
|
@ -501,6 +530,8 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
contentSize.height += height
|
||||
}
|
||||
|
||||
let menuHeightWithInset = contentSize.height + 16.0
|
||||
|
||||
let insets = layout.insets(options: [.statusBar, .input])
|
||||
let inputHeight = layout.inputHeight ?? 0.0
|
||||
|
||||
|
|
@ -508,7 +539,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
|
||||
var contentOrigin = CGPoint(x: layout.size.width - sideInset - contentSize.width - layout.safeInsets.right, y: layout.size.height - 6.0 - insets.bottom - contentSize.height)
|
||||
if inputHeight > 0.0 {
|
||||
contentOrigin.y += 60.0
|
||||
contentOrigin.y += menuHeightWithInset
|
||||
}
|
||||
contentOrigin.y = min(contentOrigin.y + contentOffset, layout.size.height - 6.0 - layout.intrinsicInsets.bottom - contentSize.height)
|
||||
|
||||
|
|
@ -523,7 +554,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
let initialSendButtonFrame = self.sendButtonFrame
|
||||
var sendButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - initialSendButtonFrame.width + 1.0 - UIScreenPixel - layout.safeInsets.right, y: layout.size.height - insets.bottom - initialSendButtonFrame.height), size: initialSendButtonFrame.size)
|
||||
if inputHeight.isZero {
|
||||
sendButtonFrame.origin.y -= 60.0
|
||||
sendButtonFrame.origin.y -= menuHeightWithInset
|
||||
}
|
||||
sendButtonFrame.origin.y = min(sendButtonFrame.origin.y + contentOffset, layout.size.height - layout.intrinsicInsets.bottom - initialSendButtonFrame.height)
|
||||
transition.updateFrame(node: self.sendButtonNode, frame: sendButtonFrame)
|
||||
|
|
@ -533,7 +564,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||
messageFrame.origin.x -= 13.0
|
||||
messageFrame.origin.y = layout.size.height - messageFrame.origin.y - messageFrame.size.height - 1.0
|
||||
if inputHeight.isZero {
|
||||
messageFrame.origin.y += 60.0
|
||||
messageFrame.origin.y += menuHeightWithInset
|
||||
}
|
||||
|
||||
if self.textInputNode.textView.attributedText.string.isEmpty {
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ enum ChatTextInputAccessoryItem: Equatable {
|
|||
case commands
|
||||
case silentPost(Bool)
|
||||
case messageAutoremoveTimeout(Int32?)
|
||||
case scheduledMessages
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,12 +113,14 @@ private final class AccessoryItemIconButton: HighlightTrackingButton {
|
|||
} else {
|
||||
return (PresentationResourcesChat.chatInputTextFieldTimerImage(theme), nil, 1.0, UIEdgeInsets(top: 0.0, left: 0.0, bottom: 1.0, right: 0.0))
|
||||
}
|
||||
case .scheduledMessages:
|
||||
return (PresentationResourcesChat.chatInputTextFieldScheduleImage(theme), nil, 1.0, UIEdgeInsets())
|
||||
}
|
||||
}
|
||||
|
||||
static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
||||
switch item {
|
||||
case .keyboard, .stickers, .inputButtons, .silentPost, .commands:
|
||||
case .keyboard, .stickers, .inputButtons, .silentPost, .commands, .scheduledMessages:
|
||||
return (image?.size.width ?? 0.0) + CGFloat(8.0)
|
||||
case let .messageAutoremoveTimeout(timeout):
|
||||
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
||||
|
|
@ -775,7 +777,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||
self.textPlaceholderNode.frame = CGRect(origin: self.textPlaceholderNode.frame.origin, size: placeholderSize)
|
||||
}
|
||||
|
||||
self.actionButtons.sendButtonLongPressEnabled = peer.id != interfaceState.accountPeerId && peer.id.namespace != Namespaces.Peer.SecretChat
|
||||
self.actionButtons.sendButtonLongPressEnabled = peer.id.namespace != Namespaces.Peer.SecretChat && !interfaceState.isScheduledMessages
|
||||
}
|
||||
|
||||
let sendButtonHasApplyIcon = interfaceState.interfaceState.editMessage != nil
|
||||
|
|
@ -798,7 +800,11 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||
if self.actionButtons.sendButtonHasApplyIcon {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyButtonImage(interfaceState.theme), for: [])
|
||||
} else {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(interfaceState.theme), for: [])
|
||||
if interfaceState.isScheduledMessages {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: [])
|
||||
} else {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(interfaceState.theme), for: [])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1413,7 +1419,11 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||
if self.actionButtons.sendButtonHasApplyIcon {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyButtonImage(interfaceState.theme), for: [])
|
||||
} else {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(interfaceState.theme), for: [])
|
||||
if interfaceState.isScheduledMessages {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: [])
|
||||
} else {
|
||||
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(interfaceState.theme), for: [])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1704,6 +1714,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||
self.interfaceInteraction?.toggleSilentPost()
|
||||
case .messageAutoremoveTimeout:
|
||||
self.interfaceInteraction?.setupMessageAutoremoveTimeout()
|
||||
case .scheduledMessages:
|
||||
self.interfaceInteraction?.openScheduledMessages()
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import TelegramStringFormatting
|
|||
import PeerPresenceStatusManager
|
||||
|
||||
enum ChatTitleContent {
|
||||
case peer(peerView: PeerView, onlineMemberCount: Int32?)
|
||||
case peer(peerView: PeerView, onlineMemberCount: Int32?, isScheduledMessages: Bool)
|
||||
case group([Peer])
|
||||
}
|
||||
|
||||
|
|
@ -177,26 +177,36 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||
var titleLeftIcon: ChatTitleIcon = .none
|
||||
var titleRightIcon: ChatTitleIcon = .none
|
||||
var titleScamIcon = false
|
||||
var isEnabled = true
|
||||
switch titleContent {
|
||||
case let .peer(peerView, _):
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
if peerView.peerId == self.account.peerId {
|
||||
string = NSAttributedString(string: self.strings.Conversation_SavedMessages, font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
case let .peer(peerView, _, isScheduledMessages):
|
||||
if isScheduledMessages {
|
||||
if let peer = peerViewMainPeer(peerView), peerView.peerId == self.account.peerId {
|
||||
string = NSAttributedString(string: self.strings.ScheduledMessages_RemindersTitle, font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
} else {
|
||||
if !peerView.peerIsContact, let user = peer as? TelegramUser, !user.flags.contains(.isSupport), user.botInfo == nil, let phone = user.phone, !phone.isEmpty {
|
||||
string = NSAttributedString(string: formatPhoneNumber(phone), font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
} else {
|
||||
string = NSAttributedString(string: peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
}
|
||||
string = NSAttributedString(string: self.strings.ScheduledMessages_Title, font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
}
|
||||
titleScamIcon = peer.isScam
|
||||
}
|
||||
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
titleLeftIcon = .lock
|
||||
}
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
|
||||
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
||||
titleRightIcon = .mute
|
||||
isEnabled = false
|
||||
} else {
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
if peerView.peerId == self.account.peerId {
|
||||
string = NSAttributedString(string: self.strings.Conversation_SavedMessages, font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
} else {
|
||||
if !peerView.peerIsContact, let user = peer as? TelegramUser, !user.flags.contains(.isSupport), user.botInfo == nil, let phone = user.phone, !phone.isEmpty {
|
||||
string = NSAttributedString(string: formatPhoneNumber(phone), font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
} else {
|
||||
string = NSAttributedString(string: peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: Font.medium(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
}
|
||||
}
|
||||
titleScamIcon = peer.isScam
|
||||
}
|
||||
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
titleLeftIcon = .lock
|
||||
}
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
|
||||
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
||||
titleRightIcon = .mute
|
||||
}
|
||||
}
|
||||
}
|
||||
case .group:
|
||||
|
|
@ -235,7 +245,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||
}
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
|
||||
self.isUserInteractionEnabled = isEnabled
|
||||
self.updateStatus()
|
||||
}
|
||||
}
|
||||
|
|
@ -245,9 +255,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||
var inputActivitiesAllowed = true
|
||||
if let titleContent = self.titleContent {
|
||||
switch titleContent {
|
||||
case let .peer(peerView, _):
|
||||
case let .peer(peerView, _, isScheduledMessages):
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
if peer.id == self.account.peerId {
|
||||
if peer.id == self.account.peerId || isScheduledMessages {
|
||||
inputActivitiesAllowed = false
|
||||
}
|
||||
}
|
||||
|
|
@ -316,10 +326,10 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||
} else {
|
||||
if let titleContent = self.titleContent {
|
||||
switch titleContent {
|
||||
case let .peer(peerView, onlineMemberCount):
|
||||
case let .peer(peerView, onlineMemberCount, isScheduledMessages):
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
let servicePeer = isServicePeer(peer)
|
||||
if peer.id == self.account.peerId {
|
||||
if peer.id == self.account.peerId || isScheduledMessages {
|
||||
let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
|
||||
state = .info(string, .generic)
|
||||
} else if let user = peer as? TelegramUser {
|
||||
|
|
@ -537,7 +547,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||
}
|
||||
|
||||
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) {
|
||||
var clearBounds = clearBounds
|
||||
self.validLayout = (size, clearBounds)
|
||||
|
||||
let transition: ContainedViewLayoutTransition = .immediate
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class ChatUnreadItem: ListViewItem {
|
|||
init(index: MessageIndex, presentationData: ChatPresentationData, context: AccountContext) {
|
||||
self.index = index
|
||||
self.presentationData = presentationData
|
||||
self.header = ChatMessageDateHeader(timestamp: index.timestamp, presentationData: presentationData, context: context)
|
||||
self.header = ChatMessageDateHeader(timestamp: index.timestamp, scheduled: false, presentationData: presentationData, context: context)
|
||||
}
|
||||
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ private func fetchAnimatedStickerFirstFrameRepresentation(account: Account, reso
|
|||
return EmptyDisposable
|
||||
}
|
||||
})
|
||||
|> runOn(Queue.concurrentDefaultQueue())
|
||||
|> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
private func fetchAnimatedStickerRepresentation(account: Account, resource: MediaResource, resourceData: MediaResourceData, representation: CachedAnimatedStickerRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ func galleryItemForEntry(context: AccountContext, presentationData: Presentation
|
|||
content = SystemVideoContent(url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0))
|
||||
}
|
||||
}
|
||||
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent) {
|
||||
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init)) {
|
||||
content = webEmbedContent
|
||||
}
|
||||
}
|
||||
|
|
@ -365,7 +365,14 @@ class GalleryController: ViewController {
|
|||
switch source {
|
||||
case .peerMessagesAtId:
|
||||
if let tags = tagsForMessage(message!) {
|
||||
let view = context.account.postbox.aroundMessageHistoryViewForLocation(.peer(message!.id.peerId), anchor: .index(message!.index), count: 50, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, orderStatistics: [.combinedLocation])
|
||||
var excludeNamespaces: [MessageId.Namespace]
|
||||
if message!.id.namespace == Namespaces.Message.CloudScheduled {
|
||||
excludeNamespaces = [Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]
|
||||
} else {
|
||||
excludeNamespaces = [Namespaces.Message.CloudScheduled]
|
||||
}
|
||||
|
||||
let view = context.account.postbox.aroundMessageHistoryViewForLocation(.peer(message!.id.peerId), anchor: .index(message!.index), count: 50, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, excludeNamespaces: excludeNamespaces, orderStatistics: [.combinedLocation])
|
||||
|
||||
return view
|
||||
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
|
||||
|
|
@ -910,16 +917,13 @@ class GalleryController: ViewController {
|
|||
if let (media, _) = mediaForMessage(message: message) {
|
||||
if let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments, let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
|
||||
nodeAnimatesItself = true
|
||||
centralItemNode.activateAsInitial()
|
||||
|
||||
if presentationArguments.animated {
|
||||
centralItemNode.animateIn(from: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface)
|
||||
}
|
||||
|
||||
self._hiddenMedia.set(.single((message.id, media)))
|
||||
} else if self.isPresentedInPreviewingContext() {
|
||||
centralItemNode.activateAsInitial()
|
||||
}
|
||||
centralItemNode.activateAsInitial()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ final class GifPaneSearchContentNode: ASDisplayNode & PaneSearchContentNode {
|
|||
self.addSubnode(multiplexedNode)
|
||||
|
||||
multiplexedNode.fileSelected = { [weak self] fileReference, sourceNode, sourceRect in
|
||||
self?.controllerInteraction.sendGif(fileReference, sourceNode, sourceRect)
|
||||
let _ = self?.controllerInteraction.sendGif(fileReference, sourceNode, sourceRect)
|
||||
}
|
||||
|
||||
multiplexedNode.didScroll = { [weak self] offset, height in
|
||||
|
|
|
|||
|
|
@ -2296,7 +2296,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
|||
let infoController = groupInfoController(context: context, peerId: upgradedPeerId, membersLoaded: {
|
||||
f()
|
||||
})
|
||||
let chatController = ChatController(context: context, chatLocation: .peer(upgradedPeerId), messageId: nil, botStart: nil, mode: .standard(previewing: false))
|
||||
let chatController = ChatController(context: context, chatLocation: .peer(upgradedPeerId), mode: .standard(previewing: false))
|
||||
var viewControllers: [UIViewController] = []
|
||||
if let first = navigationController.viewControllers.first {
|
||||
viewControllers.append(first)
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ final class HashtagChatInputPanelItemNode: ListViewItemNode {
|
|||
let leftInset: CGFloat = 15.0 + params.leftInset
|
||||
let rightInset: CGFloat = 10.0 + params.rightInset
|
||||
|
||||
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "#\(item.text)", font: textFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "#\(item.text)", font: textFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: baseWidth, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: HashtagChatInputPanelItemNode.itemHeight), insets: UIEdgeInsets())
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||
self.segmentedControl.selectedSegmentIndex = 0
|
||||
|
||||
if let peer = peer {
|
||||
self.chatController = ChatController(context: context, chatLocation: .peer(peer.id), messageId: nil, botStart: nil, mode: .inline)
|
||||
self.chatController = ChatController(context: context, chatLocation: .peer(peer.id), botStart: nil, mode: .inline)
|
||||
} else {
|
||||
self.chatController = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ private enum InstalledStickerPacksSection: Int32 {
|
|||
|
||||
public enum InstalledStickerPacksEntryTag: ItemListItemTag {
|
||||
case suggestOptions
|
||||
case loopAnimatedStickers
|
||||
|
||||
public func isEqual(to other: ItemListItemTag) -> Bool {
|
||||
if let other = other as? InstalledStickerPacksEntryTag, self == other {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue