mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Merge remote-tracking branch 'refs/remotes/origin/master'
This commit is contained in:
commit
68a66f8650
@ -8261,6 +8261,8 @@ Sorry for the inconvenience.";
|
|||||||
"Channel.AdminLog.TopicRenamedWithRemovedIcon" = "%1$@ renamed topic %2$@ to %3$@ and removed icon";
|
"Channel.AdminLog.TopicRenamedWithRemovedIcon" = "%1$@ renamed topic %2$@ to %3$@ and removed icon";
|
||||||
"Channel.AdminLog.TopicChangedIcon" = "%1$@ changed topic %2$@ icon to %3$@";
|
"Channel.AdminLog.TopicChangedIcon" = "%1$@ changed topic %2$@ icon to %3$@";
|
||||||
"Channel.AdminLog.TopicRemovedIcon" = "%1$@ removed topic %2$@ icon";
|
"Channel.AdminLog.TopicRemovedIcon" = "%1$@ removed topic %2$@ icon";
|
||||||
|
"Channel.AdminLog.TopicUnhidden" = "%1$@ unhid topic %2$@";
|
||||||
|
"Channel.AdminLog.TopicHidden" = "%1$@ hid topic %2$@";
|
||||||
|
|
||||||
"Attachment.Pasteboard" = "Clipboard";
|
"Attachment.Pasteboard" = "Clipboard";
|
||||||
"Attachment.DiscardPasteboardAlertText" = "Discard pasted items?";
|
"Attachment.DiscardPasteboardAlertText" = "Discard pasted items?";
|
||||||
@ -8405,6 +8407,8 @@ Sorry for the inconvenience.";
|
|||||||
"GlobalAutodeleteSettings.AttemptDisabledGenericSelection" = "You can't enable auto-delete in this chat.";
|
"GlobalAutodeleteSettings.AttemptDisabledGenericSelection" = "You can't enable auto-delete in this chat.";
|
||||||
|
|
||||||
"EmojiSearch.SearchEmojiPlaceholder" = "Search Emoji";
|
"EmojiSearch.SearchEmojiPlaceholder" = "Search Emoji";
|
||||||
|
"StickersSearch.SearchStickersPlaceholder" = "Search Stickers";
|
||||||
|
"GifSearch.SearchGifPlaceholder" = "Search GIFs";
|
||||||
|
|
||||||
"MessageTimer.LargeShortSeconds_1" = "%@s";
|
"MessageTimer.LargeShortSeconds_1" = "%@s";
|
||||||
"MessageTimer.LargeShortSeconds_2" = "%@s";
|
"MessageTimer.LargeShortSeconds_2" = "%@s";
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import ProgressNavigationButtonNode
|
import ProgressNavigationButtonNode
|
||||||
@ -120,6 +121,10 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
|||||||
override public func viewDidAppear(_ animated: Bool) {
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
if let navigationController = self.navigationController as? NavigationController, let layout = self.validLayout {
|
||||||
|
addTemporaryKeyboardSnapshotView(navigationController: navigationController, parentView: self.view, layout: layout)
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.activateInput()
|
self.controllerNode.activateInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,3 +224,25 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
|||||||
self.controllerNode.updateCode("\(code)")
|
self.controllerNode.updateCode("\(code)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addTemporaryKeyboardSnapshotView(navigationController: NavigationController, parentView: UIView, layout: ContainerViewLayout) {
|
||||||
|
if case .compact = layout.metrics.widthClass, let statusBarHost = navigationController.statusBarHost {
|
||||||
|
if let keyboardView = statusBarHost.keyboardView {
|
||||||
|
if let snapshotView = keyboardView.snapshotView(afterScreenUpdates: false) {
|
||||||
|
keyboardView.layer.removeAllAnimations()
|
||||||
|
UIView.performWithoutAnimation {
|
||||||
|
snapshotView.frame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - snapshotView.frame.size.height), size: snapshotView.frame.size)
|
||||||
|
if let keyboardWindow = statusBarHost.keyboardWindow {
|
||||||
|
keyboardWindow.addSubview(snapshotView)
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.45, {
|
||||||
|
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||||
|
snapshotView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -75,6 +75,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let appearanceTimestamp = CACurrentMediaTime()
|
||||||
|
|
||||||
init(strings: PresentationStrings, theme: PresentationTheme) {
|
init(strings: PresentationStrings, theme: PresentationTheme) {
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
@ -270,8 +272,16 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
|||||||
}
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
let previousInputHeight = self.layoutArguments?.0.inputHeight ?? 0.0
|
||||||
|
let newInputHeight = layout.inputHeight ?? 0.0
|
||||||
|
|
||||||
self.layoutArguments = (layout, navigationBarHeight)
|
self.layoutArguments = (layout, navigationBarHeight)
|
||||||
|
|
||||||
|
var layout = layout
|
||||||
|
if CACurrentMediaTime() - self.appearanceTimestamp < 2.0, newInputHeight < previousInputHeight {
|
||||||
|
layout = layout.withUpdatedInputHeight(previousInputHeight)
|
||||||
|
}
|
||||||
|
|
||||||
let maximumWidth: CGFloat = min(430.0, layout.size.width)
|
let maximumWidth: CGFloat = min(430.0, layout.size.width)
|
||||||
let inset: CGFloat = 24.0
|
let inset: CGFloat = 24.0
|
||||||
|
|
||||||
|
@ -89,6 +89,10 @@ final class AuthorizationSequencePasswordEntryController: ViewController {
|
|||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
if let navigationController = self.navigationController as? NavigationController, let layout = self.validLayout {
|
||||||
|
addTemporaryKeyboardSnapshotView(navigationController: navigationController, parentView: self.view, layout: layout)
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.activateInput()
|
self.controllerNode.activateInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +130,10 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
|||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
if let navigationController = self.navigationController as? NavigationController, let layout = self.validLayout {
|
||||||
|
addTemporaryKeyboardSnapshotView(navigationController: navigationController, parentView: self.view, layout: layout)
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.activateInput()
|
self.controllerNode.activateInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import TextFormat
|
import TextFormat
|
||||||
import Markdown
|
import Markdown
|
||||||
@ -40,6 +41,8 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
|
|||||||
|
|
||||||
private var layoutArguments: (ContainerViewLayout, CGFloat)?
|
private var layoutArguments: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
|
private let appearanceTimestamp = CACurrentMediaTime()
|
||||||
|
|
||||||
var currentName: (String, String) {
|
var currentName: (String, String) {
|
||||||
return (self.firstNameField.textField.text ?? "", self.lastNameField.textField.text ?? "")
|
return (self.firstNameField.textField.text ?? "", self.lastNameField.textField.text ?? "")
|
||||||
}
|
}
|
||||||
@ -209,8 +212,16 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
|
|||||||
}
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
let previousInputHeight = self.layoutArguments?.0.inputHeight ?? 0.0
|
||||||
|
let newInputHeight = layout.inputHeight ?? 0.0
|
||||||
|
|
||||||
self.layoutArguments = (layout, navigationBarHeight)
|
self.layoutArguments = (layout, navigationBarHeight)
|
||||||
|
|
||||||
|
var layout = layout
|
||||||
|
if CACurrentMediaTime() - self.appearanceTimestamp < 2.0, newInputHeight < previousInputHeight {
|
||||||
|
layout = layout.withUpdatedInputHeight(previousInputHeight)
|
||||||
|
}
|
||||||
|
|
||||||
let maximumWidth: CGFloat = min(430.0, layout.size.width)
|
let maximumWidth: CGFloat = min(430.0, layout.size.width)
|
||||||
|
|
||||||
var insets = layout.insets(options: [.statusBar])
|
var insets = layout.insets(options: [.statusBar])
|
||||||
|
@ -1295,8 +1295,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cachedPeerData = peerView.cachedData
|
let cachedPeerData = peerView.cachedData
|
||||||
if let cachedPeerData = cachedPeerData as? CachedUserData {
|
if let cachedPeerData = cachedPeerData as? CachedUserData, case let .known(maybePhoto) = cachedPeerData.photo {
|
||||||
if let photo = cachedPeerData.photo, let video = smallestVideoRepresentation(photo.videoRepresentations), let peerReference = PeerReference(peer._asPeer()) {
|
if let photo = maybePhoto, let video = smallestVideoRepresentation(photo.videoRepresentations), let peerReference = PeerReference(peer._asPeer()) {
|
||||||
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
|
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
|
||||||
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||||
let videoContent = NativeVideoContent(id: .profileVideo(videoId, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
|
let videoContent = NativeVideoContent(id: .profileVideo(videoId, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
|
||||||
|
@ -2299,7 +2299,7 @@ public final class ChatListNode: ListView {
|
|||||||
isEmpty = true
|
isEmpty = true
|
||||||
loop1: for entry in transition.chatListView.filteredEntries {
|
loop1: for entry in transition.chatListView.filteredEntries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case .GroupReferenceEntry, .HeaderEntry, .HoleEntry:
|
case .HeaderEntry, .HoleEntry:
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
if case .ArchiveIntro = entry {
|
if case .ArchiveIntro = entry {
|
||||||
|
@ -612,7 +612,7 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
autoremoveTimeout: item.item.autoremoveTimeout,
|
autoremoveTimeout: item.item.autoremoveTimeout,
|
||||||
forumTopicData: item.item.forumTopicData,
|
forumTopicData: item.item.forumTopicData,
|
||||||
topForumTopicItems: item.item.topForumTopicItems,
|
topForumTopicItems: item.item.topForumTopicItems,
|
||||||
revealed: threadId == 1 && (state.hiddenItemShouldBeTemporaryRevealed || state.editing)
|
revealed: state.hiddenItemShouldBeTemporaryRevealed || state.editing
|
||||||
)))
|
)))
|
||||||
if pinningIndex != 0 {
|
if pinningIndex != 0 {
|
||||||
pinningIndex -= 1
|
pinningIndex -= 1
|
||||||
@ -632,7 +632,7 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
message: groupReference.topMessage,
|
message: groupReference.topMessage,
|
||||||
editing: state.editing,
|
editing: state.editing,
|
||||||
unreadCount: groupReference.unreadCount,
|
unreadCount: groupReference.unreadCount,
|
||||||
revealed: state.hiddenItemShouldBeTemporaryRevealed,
|
revealed: state.hiddenItemShouldBeTemporaryRevealed || view.items.isEmpty,
|
||||||
hiddenByDefault: hideArchivedFolderByDefault
|
hiddenByDefault: hideArchivedFolderByDefault
|
||||||
))
|
))
|
||||||
if pinningIndex != 0 {
|
if pinningIndex != 0 {
|
||||||
|
@ -1411,10 +1411,14 @@ open class TextNode: ASDisplayNode {
|
|||||||
context.setAllowsFontSubpixelQuantization(true)
|
context.setAllowsFontSubpixelQuantization(true)
|
||||||
context.setShouldSubpixelQuantizeFonts(true)
|
context.setShouldSubpixelQuantizeFonts(true)
|
||||||
|
|
||||||
|
var blendMode: CGBlendMode = .normal
|
||||||
|
|
||||||
var clearRects: [CGRect] = []
|
var clearRects: [CGRect] = []
|
||||||
if let layout = parameters as? TextNodeLayout {
|
if let layout = parameters as? TextNodeLayout {
|
||||||
if !isRasterizing || layout.backgroundColor != nil {
|
if !isRasterizing || layout.backgroundColor != nil {
|
||||||
context.setBlendMode(.copy)
|
context.setBlendMode(.copy)
|
||||||
|
blendMode = .copy
|
||||||
|
|
||||||
context.setFillColor((layout.backgroundColor ?? UIColor.clear).cgColor)
|
context.setFillColor((layout.backgroundColor ?? UIColor.clear).cgColor)
|
||||||
context.fill(bounds)
|
context.fill(bounds)
|
||||||
}
|
}
|
||||||
@ -1426,6 +1430,8 @@ open class TextNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let (textStrokeColor, textStrokeWidth) = layout.textStroke {
|
if let (textStrokeColor, textStrokeWidth) = layout.textStroke {
|
||||||
context.setBlendMode(.normal)
|
context.setBlendMode(.normal)
|
||||||
|
blendMode = .normal
|
||||||
|
|
||||||
context.setLineCap(.round)
|
context.setLineCap(.round)
|
||||||
context.setLineJoin(.round)
|
context.setLineJoin(.round)
|
||||||
context.setStrokeColor(textStrokeColor.cgColor)
|
context.setStrokeColor(textStrokeColor.cgColor)
|
||||||
@ -1487,7 +1493,28 @@ open class TextNode: ASDisplayNode {
|
|||||||
if attributes["Attribute__EmbeddedItem"] != nil {
|
if attributes["Attribute__EmbeddedItem"] != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fixCoupleEmoji = false
|
||||||
|
if glyphCount == 2, let font = attributes["NSFont"] as? UIFont, font.fontName.contains("ColorEmoji"), let string = layout.attributedString {
|
||||||
|
let range = CTRunGetStringRange(run)
|
||||||
|
let substring = string.attributedSubstring(from: NSMakeRange(range.location, range.length)).string
|
||||||
|
|
||||||
|
let heart = Unicode.Scalar(0x2764)!
|
||||||
|
let man = Unicode.Scalar(0x1F468)!
|
||||||
|
let woman = Unicode.Scalar(0x1F469)!
|
||||||
|
|
||||||
|
if substring.unicodeScalars.contains(heart) && (substring.unicodeScalars.contains(man) || substring.unicodeScalars.contains(woman)) {
|
||||||
|
fixCoupleEmoji = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fixCoupleEmoji {
|
||||||
|
context.setBlendMode(.normal)
|
||||||
|
}
|
||||||
CTRunDraw(run, context, CFRangeMake(0, glyphCount))
|
CTRunDraw(run, context, CFRangeMake(0, glyphCount))
|
||||||
|
if fixCoupleEmoji {
|
||||||
|
context.setBlendMode(blendMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ private final class PictureInPictureContentImpl: NSObject, PictureInPictureConte
|
|||||||
guard let status = self.status else {
|
guard let status = self.status else {
|
||||||
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)))
|
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)))
|
||||||
}
|
}
|
||||||
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: status.duration, preferredTimescale: CMTimeScale(30.0)))
|
return CMTimeRange(start: CMTime(seconds: status.timestamp, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: status.duration, preferredTimescale: CMTimeScale(30.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
|
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
|
||||||
|
@ -104,7 +104,9 @@ final class AppIconsDemoComponent: Component {
|
|||||||
position = CGPoint(x: availableSize.width * 0.5, y: availableSize.height * 0.5)
|
position = CGPoint(x: availableSize.width * 0.5, y: availableSize.height * 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.animating {
|
||||||
view.center = position.offsetBy(dx: availableSize.width / 2.0, dy: 0.0)
|
view.center = position.offsetBy(dx: availableSize.width / 2.0, dy: 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
@ -126,7 +128,10 @@ final class AppIconsDemoComponent: Component {
|
|||||||
return availableSize
|
return availableSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var animating = false
|
||||||
func animateIn(availableSize: CGSize) {
|
func animateIn(availableSize: CGSize) {
|
||||||
|
self.animating = true
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
for view in self.imageViews {
|
for view in self.imageViews {
|
||||||
let from: CGPoint
|
let from: CGPoint
|
||||||
@ -146,9 +151,17 @@ final class AppIconsDemoComponent: Component {
|
|||||||
delay = 0.0
|
delay = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let initialPosition = view.layer.position
|
||||||
|
view.layer.position = initialPosition.offsetBy(dx: from.x, dy: from.y)
|
||||||
|
|
||||||
Queue.mainQueue().after(delay) {
|
Queue.mainQueue().after(delay) {
|
||||||
|
view.layer.position = initialPosition
|
||||||
view.layer.animateScale(from: 3.0, to: 1.0, duration: 0.5, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring)
|
view.layer.animateScale(from: 3.0, to: 1.0, duration: 0.5, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
view.layer.animatePosition(from: from, to: CGPoint(), duration: 0.5, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
view.layer.animatePosition(from: from, to: CGPoint(), duration: 0.5, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||||
|
|
||||||
|
if i == 2 {
|
||||||
|
self.animating = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -50,6 +50,34 @@ public enum CachedPeerAutoremoveTimeout: Equatable, PostboxCoding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum CachedPeerProfilePhoto: Equatable, PostboxCoding {
|
||||||
|
case unknown
|
||||||
|
case known(TelegramMediaImage?)
|
||||||
|
|
||||||
|
public init(decoder: PostboxDecoder) {
|
||||||
|
switch decoder.decodeInt32ForKey("_v", orElse: 0) {
|
||||||
|
case 1:
|
||||||
|
self = .known(decoder.decodeObjectForKey("v", decoder: { TelegramMediaImage(decoder: $0) }) as? TelegramMediaImage)
|
||||||
|
default:
|
||||||
|
self = .unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
|
switch self {
|
||||||
|
case .unknown:
|
||||||
|
encoder.encodeInt32(0, forKey: "_v")
|
||||||
|
case let .known(value):
|
||||||
|
encoder.encodeInt32(1, forKey: "_v")
|
||||||
|
if let value = value {
|
||||||
|
encoder.encodeObject(value, forKey: "v")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "v")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct CachedPremiumGiftOption: Equatable, PostboxCoding {
|
public struct CachedPremiumGiftOption: Equatable, PostboxCoding {
|
||||||
public let months: Int32
|
public let months: Int32
|
||||||
public let currency: String
|
public let currency: String
|
||||||
@ -123,7 +151,7 @@ public final class CachedUserData: CachedPeerData {
|
|||||||
public let hasScheduledMessages: Bool
|
public let hasScheduledMessages: Bool
|
||||||
public let autoremoveTimeout: CachedPeerAutoremoveTimeout
|
public let autoremoveTimeout: CachedPeerAutoremoveTimeout
|
||||||
public let themeEmoticon: String?
|
public let themeEmoticon: String?
|
||||||
public let photo: TelegramMediaImage?
|
public let photo: CachedPeerProfilePhoto
|
||||||
public let premiumGiftOptions: [CachedPremiumGiftOption]
|
public let premiumGiftOptions: [CachedPremiumGiftOption]
|
||||||
public let voiceMessagesAvailable: Bool
|
public let voiceMessagesAvailable: Bool
|
||||||
|
|
||||||
@ -145,14 +173,14 @@ public final class CachedUserData: CachedPeerData {
|
|||||||
self.hasScheduledMessages = false
|
self.hasScheduledMessages = false
|
||||||
self.autoremoveTimeout = .unknown
|
self.autoremoveTimeout = .unknown
|
||||||
self.themeEmoticon = nil
|
self.themeEmoticon = nil
|
||||||
self.photo = nil
|
self.photo = .unknown
|
||||||
self.premiumGiftOptions = []
|
self.premiumGiftOptions = []
|
||||||
self.voiceMessagesAvailable = true
|
self.voiceMessagesAvailable = true
|
||||||
self.peerIds = Set()
|
self.peerIds = Set()
|
||||||
self.messageIds = Set()
|
self.messageIds = Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: TelegramMediaImage?, premiumGiftOptions: [CachedPremiumGiftOption], voiceMessagesAvailable: Bool) {
|
public init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, premiumGiftOptions: [CachedPremiumGiftOption], voiceMessagesAvailable: Bool) {
|
||||||
self.about = about
|
self.about = about
|
||||||
self.botInfo = botInfo
|
self.botInfo = botInfo
|
||||||
self.peerStatusSettings = peerStatusSettings
|
self.peerStatusSettings = peerStatusSettings
|
||||||
@ -204,11 +232,7 @@ public final class CachedUserData: CachedPeerData {
|
|||||||
self.autoremoveTimeout = decoder.decodeObjectForKey("artv", decoder: CachedPeerAutoremoveTimeout.init(decoder:)) as? CachedPeerAutoremoveTimeout ?? .unknown
|
self.autoremoveTimeout = decoder.decodeObjectForKey("artv", decoder: CachedPeerAutoremoveTimeout.init(decoder:)) as? CachedPeerAutoremoveTimeout ?? .unknown
|
||||||
self.themeEmoticon = decoder.decodeOptionalStringForKey("te")
|
self.themeEmoticon = decoder.decodeOptionalStringForKey("te")
|
||||||
|
|
||||||
if let photo = decoder.decodeObjectForKey("ph", decoder: { TelegramMediaImage(decoder: $0) }) as? TelegramMediaImage {
|
self.photo = decoder.decodeObjectForKey("phv", decoder: CachedPeerProfilePhoto.init(decoder:)) as? CachedPeerProfilePhoto ?? .unknown
|
||||||
self.photo = photo
|
|
||||||
} else {
|
|
||||||
self.photo = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
self.premiumGiftOptions = decoder.decodeObjectArrayWithDecoderForKey("pgo") as [CachedPremiumGiftOption]
|
self.premiumGiftOptions = decoder.decodeObjectArrayWithDecoderForKey("pgo") as [CachedPremiumGiftOption]
|
||||||
self.voiceMessagesAvailable = decoder.decodeInt32ForKey("vma", orElse: 0) != 0
|
self.voiceMessagesAvailable = decoder.decodeInt32ForKey("vma", orElse: 0) != 0
|
||||||
@ -261,11 +285,7 @@ public final class CachedUserData: CachedPeerData {
|
|||||||
encoder.encodeNil(forKey: "te")
|
encoder.encodeNil(forKey: "te")
|
||||||
}
|
}
|
||||||
|
|
||||||
if let photo = self.photo {
|
encoder.encodeObject(self.photo, forKey: "phv")
|
||||||
encoder.encodeObject(photo, forKey: "ph")
|
|
||||||
} else {
|
|
||||||
encoder.encodeNil(forKey: "ph")
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder.encodeObjectArray(self.premiumGiftOptions, forKey: "pgo")
|
encoder.encodeObjectArray(self.premiumGiftOptions, forKey: "pgo")
|
||||||
encoder.encodeInt32(self.voiceMessagesAvailable ? 1 : 0, forKey: "vma")
|
encoder.encodeInt32(self.voiceMessagesAvailable ? 1 : 0, forKey: "vma")
|
||||||
@ -338,7 +358,7 @@ public final class CachedUserData: CachedPeerData {
|
|||||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedPhoto(_ photo: TelegramMediaImage?) -> CachedUserData {
|
public func withUpdatedPhoto(_ photo: CachedPeerProfilePhoto) -> CachedUserData {
|
||||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +739,11 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
preconditionFailure()
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
if let cachedData = view.cachedPeerData as? CachedUserData {
|
if let cachedData = view.cachedPeerData as? CachedUserData {
|
||||||
return .known(cachedData.photo)
|
if case let .known(value) = cachedData.photo {
|
||||||
|
return .known(value)
|
||||||
|
} else {
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
} else if let cachedData = view.cachedPeerData as? CachedGroupData {
|
} else if let cachedData = view.cachedPeerData as? CachedGroupData {
|
||||||
return .known(cachedData.photo)
|
return .known(cachedData.photo)
|
||||||
} else if let cachedData = view.cachedPeerData as? CachedChannelData {
|
} else if let cachedData = view.cachedPeerData as? CachedChannelData {
|
||||||
|
@ -35,10 +35,12 @@ public enum AdminLogEventAction {
|
|||||||
public struct ForumTopicInfo {
|
public struct ForumTopicInfo {
|
||||||
public var info: EngineMessageHistoryThread.Info
|
public var info: EngineMessageHistoryThread.Info
|
||||||
public var isClosed: Bool
|
public var isClosed: Bool
|
||||||
|
public var isHidden: Bool
|
||||||
|
|
||||||
public init(info: EngineMessageHistoryThread.Info, isClosed: Bool) {
|
public init(info: EngineMessageHistoryThread.Info, isClosed: Bool, isHidden: Bool) {
|
||||||
self.info = info
|
self.info = info
|
||||||
self.isClosed = isClosed
|
self.isClosed = isClosed
|
||||||
|
self.isHidden = isHidden
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,17 +304,17 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m
|
|||||||
let prevInfo: AdminLogEventAction.ForumTopicInfo
|
let prevInfo: AdminLogEventAction.ForumTopicInfo
|
||||||
switch prevTopic {
|
switch prevTopic {
|
||||||
case let .forumTopic(flags, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
|
case let .forumTopic(flags, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
|
||||||
prevInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor), isClosed: (flags & (1 << 2)) != 0)
|
prevInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor), isClosed: (flags & (1 << 2)) != 0, isHidden: (flags & (1 << 6)) != 0)
|
||||||
case .forumTopicDeleted:
|
case .forumTopicDeleted:
|
||||||
prevInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0), isClosed: false)
|
prevInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0), isClosed: false, isHidden: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
let newInfo: AdminLogEventAction.ForumTopicInfo
|
let newInfo: AdminLogEventAction.ForumTopicInfo
|
||||||
switch newTopic {
|
switch newTopic {
|
||||||
case let .forumTopic(flags, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
|
case let .forumTopic(flags, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
|
||||||
newInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor), isClosed: (flags & (1 << 2)) != 0)
|
newInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor), isClosed: (flags & (1 << 2)) != 0, isHidden: (flags & (1 << 6)) != 0)
|
||||||
case .forumTopicDeleted:
|
case .forumTopicDeleted:
|
||||||
newInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0), isClosed: false)
|
newInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0), isClosed: false, isHidden: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
action = .editTopic(prevInfo: prevInfo, newInfo: newInfo)
|
action = .editTopic(prevInfo: prevInfo, newInfo: newInfo)
|
||||||
|
@ -267,7 +267,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
return previous.withUpdatedAbout(userFullAbout).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFullCommonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
|
return previous.withUpdatedAbout(userFullAbout).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFullCommonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||||
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
|
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
|
||||||
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
|
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
|
||||||
.withUpdatedPhoto(photo)
|
.withUpdatedPhoto(.known(photo))
|
||||||
.withUpdatedPremiumGiftOptions(premiumGiftOptions)
|
.withUpdatedPremiumGiftOptions(premiumGiftOptions)
|
||||||
.withUpdatedVoiceMessagesAvailable(voiceMessagesAvailable)
|
.withUpdatedVoiceMessagesAvailable(voiceMessagesAvailable)
|
||||||
}
|
}
|
||||||
|
@ -290,6 +290,9 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case chatKeyboardActionButtonWebAppIcon
|
case chatKeyboardActionButtonWebAppIcon
|
||||||
|
|
||||||
case chatGeneralThreadIcon
|
case chatGeneralThreadIcon
|
||||||
|
case chatGeneralThreadIncomingIcon
|
||||||
|
case chatGeneralThreadOutgoingIcon
|
||||||
|
case chatGeneralThreadFreeIcon
|
||||||
|
|
||||||
case uploadToneIcon
|
case uploadToneIcon
|
||||||
}
|
}
|
||||||
|
@ -1325,4 +1325,22 @@ public struct PresentationResourcesChat {
|
|||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Info/GeneralIcon"), color: theme.rootController.navigationBar.controlColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Info/GeneralIcon"), color: theme.rootController.navigationBar.controlColor)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func chatGeneralThreadIncomingIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.chatGeneralThreadIncomingIcon.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: theme.chat.message.incoming.accentTextColor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func chatGeneralThreadOutgoingIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.chatGeneralThreadOutgoingIcon.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: theme.chat.message.outgoing.accentTextColor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func chatGeneralThreadFreeIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.chatGeneralThreadFreeIcon.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: theme.chat.message.mediaOverlayControlColors.foregroundColor)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,8 +123,8 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cachedPeerData = peerView.cachedData
|
let cachedPeerData = peerView.cachedData
|
||||||
if let cachedPeerData = cachedPeerData as? CachedUserData {
|
if let cachedPeerData = cachedPeerData as? CachedUserData, case let .known(maybePhoto) = cachedPeerData.photo {
|
||||||
if let photo = cachedPeerData.photo, let video = smallestVideoRepresentation(photo.videoRepresentations), let peerReference = PeerReference(peer._asPeer()) {
|
if let photo = maybePhoto, let video = smallestVideoRepresentation(photo.videoRepresentations), let peerReference = PeerReference(peer._asPeer()) {
|
||||||
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
|
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
|
||||||
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||||
let videoContent = NativeVideoContent(id: .profileVideo(videoId, "header"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
|
let videoContent = NativeVideoContent(id: .profileVideo(videoId, "header"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
|
||||||
|
@ -501,6 +501,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
return EmojiPagerContentComponent(
|
return EmojiPagerContentComponent(
|
||||||
id: "stickers",
|
id: "stickers",
|
||||||
context: context,
|
context: context,
|
||||||
@ -537,7 +538,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
itemLayoutType: .detailed,
|
itemLayoutType: .detailed,
|
||||||
itemContentUniqueId: nil,
|
itemContentUniqueId: nil,
|
||||||
warpContentsOnEdges: false,
|
warpContentsOnEdges: false,
|
||||||
displaySearchWithPlaceholder: "Search Stickers",
|
displaySearchWithPlaceholder: presentationData.strings.StickersSearch_SearchStickersPlaceholder,
|
||||||
searchInitiallyHidden: false,
|
searchInitiallyHidden: false,
|
||||||
searchIsPlaceholderOnly: true,
|
searchIsPlaceholderOnly: true,
|
||||||
emptySearchResults: nil,
|
emptySearchResults: nil,
|
||||||
@ -748,6 +749,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
return !savedGifs.isEmpty
|
return !savedGifs.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let gifItems: Signal<EntityKeyboardGifContent, NoError>
|
let gifItems: Signal<EntityKeyboardGifContent, NoError>
|
||||||
switch subject {
|
switch subject {
|
||||||
case .recent:
|
case .recent:
|
||||||
@ -769,7 +771,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
items: items,
|
items: items,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
loadMoreToken: nil,
|
loadMoreToken: nil,
|
||||||
displaySearchWithPlaceholder: "Search GIFs",
|
displaySearchWithPlaceholder: presentationData.strings.GifSearch_SearchGifPlaceholder,
|
||||||
searchInitiallyHidden: false
|
searchInitiallyHidden: false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1186,6 +1186,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var replyMessage: Message?
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let attribute = attribute as? InlineBotMessageAttribute {
|
if let attribute = attribute as? InlineBotMessageAttribute {
|
||||||
var inlineBotNameString: String?
|
var inlineBotNameString: String?
|
||||||
@ -1206,15 +1207,16 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
|
if let replyAttribute = attribute as? ReplyMessageAttribute {
|
||||||
var hasReply = true
|
replyMessage = item.message.associatedMessages[replyAttribute.messageId]
|
||||||
|
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty {
|
||||||
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
|
replyMarkup = attribute
|
||||||
hasReply = false
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if case .peer = item.chatLocation, replyMessage.threadId != nil, case let .peer(peerId) = item.chatLocation, peerId == replyMessage.id.peerId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
|
var hasReply = replyMessage != nil
|
||||||
if let threadId = item.message.threadId, Int64(replyMessage.id.id) == threadId {
|
if case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil {
|
||||||
|
if let threadId = item.message.threadId, let replyMessage = replyMessage, Int64(replyMessage.id.id) == threadId {
|
||||||
hasReply = false
|
hasReply = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,7 +1226,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
context: item.context,
|
context: item.context,
|
||||||
controllerInteraction: item.controllerInteraction,
|
controllerInteraction: item.controllerInteraction,
|
||||||
type: .standalone,
|
type: .standalone,
|
||||||
message: replyMessage,
|
threadId: item.message.threadId ?? 1,
|
||||||
parentMessage: item.message,
|
parentMessage: item.message,
|
||||||
constrainedSize: CGSize(width: availableContentWidth, height: CGFloat.greatestFiniteMagnitude),
|
constrainedSize: CGSize(width: availableContentWidth, height: CGFloat.greatestFiniteMagnitude),
|
||||||
animationCache: item.controllerInteraction.presentationContext.animationCache,
|
animationCache: item.controllerInteraction.presentationContext.animationCache,
|
||||||
@ -1232,7 +1234,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasReply {
|
if let replyMessage = replyMessage, hasReply {
|
||||||
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
|
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
|
||||||
presentationData: item.presentationData,
|
presentationData: item.presentationData,
|
||||||
strings: item.presentationData.strings,
|
strings: item.presentationData.strings,
|
||||||
@ -1245,10 +1247,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
|
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty {
|
|
||||||
replyMarkup = attribute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if item.message.id.peerId != item.context.account.peerId && !item.message.id.peerId.isReplies {
|
if item.message.id.peerId != item.context.account.peerId && !item.message.id.peerId.isReplies {
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
|
@ -1737,6 +1737,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
if replyMessage != nil {
|
if replyMessage != nil {
|
||||||
displayHeader = true
|
displayHeader = true
|
||||||
}
|
}
|
||||||
|
if !displayHeader, case .peer = item.chatLocation, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil {
|
||||||
|
displayHeader = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let firstNodeTopPosition: ChatMessageBubbleRelativePosition
|
let firstNodeTopPosition: ChatMessageBubbleRelativePosition
|
||||||
@ -1963,8 +1966,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hasReply = replyMessage != nil
|
var hasReply = replyMessage != nil
|
||||||
if !isInstantVideo, let replyMessage = replyMessage, replyMessage.threadId != nil, case let .peer(peerId) = item.chatLocation, peerId == replyMessage.id.peerId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil {
|
if !isInstantVideo, case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil {
|
||||||
if let threadId = item.message.threadId, Int64(replyMessage.id.id) == threadId {
|
if let threadId = item.message.threadId, let replyMessage = replyMessage, Int64(replyMessage.id.id) == threadId {
|
||||||
hasReply = false
|
hasReply = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1980,7 +1983,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
context: item.context,
|
context: item.context,
|
||||||
controllerInteraction: item.controllerInteraction,
|
controllerInteraction: item.controllerInteraction,
|
||||||
type: .bubble(incoming: incoming),
|
type: .bubble(incoming: incoming),
|
||||||
message: replyMessage,
|
threadId: item.message.threadId ?? 1,
|
||||||
parentMessage: item.message,
|
parentMessage: item.message,
|
||||||
constrainedSize: CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude),
|
constrainedSize: CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude),
|
||||||
animationCache: item.controllerInteraction.presentationContext.animationCache,
|
animationCache: item.controllerInteraction.presentationContext.animationCache,
|
||||||
|
@ -531,8 +531,8 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cachedPeerData = peerView.cachedData
|
let cachedPeerData = peerView.cachedData
|
||||||
if let cachedPeerData = cachedPeerData as? CachedUserData {
|
if let cachedPeerData = cachedPeerData as? CachedUserData, case let .known(maybePhoto) = cachedPeerData.photo {
|
||||||
if let photo = cachedPeerData.photo, let video = photo.videoRepresentations.last, let peerReference = PeerReference(peer) {
|
if let photo = maybePhoto, let video = photo.videoRepresentations.last, let peerReference = PeerReference(peer) {
|
||||||
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
|
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
|
||||||
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||||
let videoContent = NativeVideoContent(id: .profileVideo(videoId, "\(Int32.random(in: 0 ..< Int32.max))"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
|
let videoContent = NativeVideoContent(id: .profileVideo(videoId, "\(Int32.random(in: 0 ..< Int32.max))"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
|
||||||
|
@ -614,6 +614,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var replyMessage: Message?
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let attribute = attribute as? InlineBotMessageAttribute {
|
if let attribute = attribute as? InlineBotMessageAttribute {
|
||||||
var inlineBotNameString: String?
|
var inlineBotNameString: String?
|
||||||
@ -634,24 +635,27 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
|
|
||||||
var hasReply = true
|
|
||||||
|
|
||||||
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
|
if let replyAttribute = attribute as? ReplyMessageAttribute {
|
||||||
|
replyMessage = item.message.associatedMessages[replyAttribute.messageId]
|
||||||
|
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty {
|
||||||
|
replyMarkup = attribute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasReply = replyMessage != nil
|
||||||
|
if case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil {
|
||||||
|
if let threadId = item.message.threadId, let replyMessage = replyMessage, Int64(replyMessage.id.id) == threadId {
|
||||||
hasReply = false
|
hasReply = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if case .peer = item.chatLocation, replyMessage.threadId != nil, case let .peer(peerId) = item.chatLocation, peerId == replyMessage.id.peerId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
|
|
||||||
if let threadId = item.message.threadId, Int64(replyMessage.id.id) == threadId {
|
|
||||||
hasReply = false
|
|
||||||
}
|
|
||||||
threadInfoApply = makeThreadInfoLayout(ChatMessageThreadInfoNode.Arguments(
|
threadInfoApply = makeThreadInfoLayout(ChatMessageThreadInfoNode.Arguments(
|
||||||
presentationData: item.presentationData,
|
presentationData: item.presentationData,
|
||||||
strings: item.presentationData.strings,
|
strings: item.presentationData.strings,
|
||||||
context: item.context,
|
context: item.context,
|
||||||
controllerInteraction: item.controllerInteraction,
|
controllerInteraction: item.controllerInteraction,
|
||||||
type: .standalone,
|
type: .standalone,
|
||||||
message: replyMessage,
|
threadId: item.message.threadId ?? 1,
|
||||||
parentMessage: item.message,
|
parentMessage: item.message,
|
||||||
constrainedSize: CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude),
|
constrainedSize: CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude),
|
||||||
animationCache: item.controllerInteraction.presentationContext.animationCache,
|
animationCache: item.controllerInteraction.presentationContext.animationCache,
|
||||||
@ -659,7 +663,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasReply {
|
if let replyMessage = replyMessage, hasReply {
|
||||||
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
|
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
|
||||||
presentationData: item.presentationData,
|
presentationData: item.presentationData,
|
||||||
strings: item.presentationData.strings,
|
strings: item.presentationData.strings,
|
||||||
@ -672,10 +676,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
|
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty {
|
|
||||||
replyMarkup = attribute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if item.message.id.peerId != item.context.account.peerId && !item.message.id.peerId.isReplies {
|
if item.message.id.peerId != item.context.account.peerId && !item.message.id.peerId.isReplies {
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
|
@ -183,7 +183,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let controllerInteraction: ChatControllerInteraction
|
let controllerInteraction: ChatControllerInteraction
|
||||||
let type: ChatMessageThreadInfoType
|
let type: ChatMessageThreadInfoType
|
||||||
let message: Message
|
let threadId: Int64
|
||||||
let parentMessage: Message
|
let parentMessage: Message
|
||||||
let constrainedSize: CGSize
|
let constrainedSize: CGSize
|
||||||
let animationCache: AnimationCache?
|
let animationCache: AnimationCache?
|
||||||
@ -195,7 +195,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
controllerInteraction: ChatControllerInteraction,
|
controllerInteraction: ChatControllerInteraction,
|
||||||
type: ChatMessageThreadInfoType,
|
type: ChatMessageThreadInfoType,
|
||||||
message: Message,
|
threadId: Int64,
|
||||||
parentMessage: Message,
|
parentMessage: Message,
|
||||||
constrainedSize: CGSize,
|
constrainedSize: CGSize,
|
||||||
animationCache: AnimationCache?,
|
animationCache: AnimationCache?,
|
||||||
@ -206,7 +206,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
self.context = context
|
self.context = context
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
self.type = type
|
self.type = type
|
||||||
self.message = message
|
self.threadId = threadId
|
||||||
self.parentMessage = parentMessage
|
self.parentMessage = parentMessage
|
||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
self.animationCache = animationCache
|
self.animationCache = animationCache
|
||||||
@ -318,7 +318,6 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
var topicIconId: Int64?
|
var topicIconId: Int64?
|
||||||
var topicIconColor: Int32 = 0
|
var topicIconColor: Int32 = 0
|
||||||
if let _ = arguments.parentMessage.threadId, let channel = arguments.parentMessage.peers[arguments.parentMessage.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), let threadInfo = arguments.parentMessage.associatedThreadInfo {
|
if let _ = arguments.parentMessage.threadId, let channel = arguments.parentMessage.peers[arguments.parentMessage.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), let threadInfo = arguments.parentMessage.associatedThreadInfo {
|
||||||
|
|
||||||
topicTitle = threadInfo.title
|
topicTitle = threadInfo.title
|
||||||
topicIconId = threadInfo.icon
|
topicIconId = threadInfo.icon
|
||||||
topicIconColor = threadInfo.iconColor
|
topicIconColor = threadInfo.iconColor
|
||||||
@ -327,9 +326,10 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
let backgroundColor: UIColor
|
let backgroundColor: UIColor
|
||||||
let textColor: UIColor
|
let textColor: UIColor
|
||||||
let arrowIcon: UIImage?
|
let arrowIcon: UIImage?
|
||||||
|
let generalThreadIcon: UIImage?
|
||||||
switch arguments.type {
|
switch arguments.type {
|
||||||
case let .bubble(incoming):
|
case let .bubble(incoming):
|
||||||
if topicIconId == nil, topicIconColor != 0, incoming {
|
if topicIconId == nil, topicIconColor != 0, incoming, arguments.threadId != 1 {
|
||||||
let colors = topicIconColors(for: topicIconColor)
|
let colors = topicIconColors(for: topicIconColor)
|
||||||
backgroundColor = UIColor(rgb: colors.0.last ?? 0x000000)
|
backgroundColor = UIColor(rgb: colors.0.last ?? 0x000000)
|
||||||
textColor = UIColor(rgb: colors.1.first ?? 0x000000)
|
textColor = UIColor(rgb: colors.1.first ?? 0x000000)
|
||||||
@ -345,13 +345,15 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
arrowIcon = PresentationResourcesChat.chatBubbleArrowOutgoingImage(arguments.presentationData.theme.theme)
|
arrowIcon = PresentationResourcesChat.chatBubbleArrowOutgoingImage(arguments.presentationData.theme.theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
generalThreadIcon = incoming ? PresentationResourcesChat.chatGeneralThreadIncomingIcon(arguments.presentationData.theme.theme) : PresentationResourcesChat.chatGeneralThreadOutgoingIcon(arguments.presentationData.theme.theme)
|
||||||
case .standalone:
|
case .standalone:
|
||||||
textColor = .white
|
textColor = arguments.presentationData.theme.theme.chat.message.mediaOverlayControlColors.foregroundColor
|
||||||
backgroundColor = .white
|
backgroundColor = .white
|
||||||
arrowIcon = PresentationResourcesChat.chatBubbleArrowFreeImage(arguments.presentationData.theme.theme)
|
arrowIcon = PresentationResourcesChat.chatBubbleArrowFreeImage(arguments.presentationData.theme.theme)
|
||||||
|
generalThreadIcon = PresentationResourcesChat.chatGeneralThreadFreeIcon(arguments.presentationData.theme.theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
let placeholderColor: UIColor = arguments.message.effectivelyIncoming(arguments.context.account.peerId) ? arguments.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : arguments.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor
|
let placeholderColor: UIColor = arguments.parentMessage.effectivelyIncoming(arguments.context.account.peerId) ? arguments.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : arguments.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor
|
||||||
|
|
||||||
let text = NSAttributedString(string: topicTitle, font: textFont, textColor: textColor)
|
let text = NSAttributedString(string: topicTitle, font: textFont, textColor: textColor)
|
||||||
|
|
||||||
@ -390,9 +392,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
node.pressed = {
|
node.pressed = {
|
||||||
if let threadId = arguments.message.threadId {
|
arguments.controllerInteraction.navigateToThreadMessage(arguments.parentMessage.id.peerId, arguments.threadId, arguments.parentMessage.id)
|
||||||
arguments.controllerInteraction.navigateToThreadMessage(arguments.parentMessage.id.peerId, threadId, arguments.parentMessage.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.lineRects != lineRects {
|
if node.lineRects != lineRects {
|
||||||
@ -480,7 +480,9 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let titleTopicIconContent: EmojiStatusComponent.Content
|
let titleTopicIconContent: EmojiStatusComponent.Content
|
||||||
if let fileId = topicIconId, fileId != 0 {
|
if arguments.threadId == 1 {
|
||||||
|
titleTopicIconContent = .image(image: generalThreadIcon)
|
||||||
|
} else if let fileId = topicIconId, fileId != 0 {
|
||||||
titleTopicIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 36.0, height: 36.0), placeholderColor: arguments.presentationData.theme.theme.list.mediaPlaceholderColor, themeColor: arguments.presentationData.theme.theme.list.itemAccentColor, loopMode: .count(1))
|
titleTopicIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 36.0, height: 36.0), placeholderColor: arguments.presentationData.theme.theme.list.mediaPlaceholderColor, themeColor: arguments.presentationData.theme.theme.list.itemAccentColor, loopMode: .count(1))
|
||||||
} else {
|
} else {
|
||||||
titleTopicIconContent = .topic(title: String(topicTitle.prefix(1)), color: topicIconColor, size: CGSize(width: 22.0, height: 22.0))
|
titleTopicIconContent = .topic(title: String(topicTitle.prefix(1)), color: topicIconColor, size: CGSize(width: 22.0, height: 22.0))
|
||||||
|
@ -1714,7 +1714,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
"Channel.AdminLog.TopicRemovedIcon" = "%1$@ removed topic %2$@ icon";*/
|
"Channel.AdminLog.TopicRemovedIcon" = "%1$@ removed topic %2$@ icon";*/
|
||||||
|
|
||||||
let authorTitle: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
|
let authorTitle: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
|
||||||
if prevInfo.isClosed != newInfo.isClosed {
|
if prevInfo.isHidden != newInfo.isHidden {
|
||||||
|
appendAttributedText(text: newInfo.isHidden ? self.presentationData.strings.Channel_AdminLog_TopicHidden(authorTitle, newInfo.info.title) : self.presentationData.strings.Channel_AdminLog_TopicUnhidden(authorTitle, newInfo.info.title), generateEntities: { index in
|
||||||
|
if index == 0, let author = author {
|
||||||
|
return [.TextMention(peerId: author.id)]
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}, to: &text, entities: &entities)
|
||||||
|
} else if prevInfo.isClosed != newInfo.isClosed {
|
||||||
appendAttributedText(text: newInfo.isClosed ? self.presentationData.strings.Channel_AdminLog_TopicClosed(authorTitle, newInfo.info.title) : self.presentationData.strings.Channel_AdminLog_TopicReopened(authorTitle, newInfo.info.title), generateEntities: { index in
|
appendAttributedText(text: newInfo.isClosed ? self.presentationData.strings.Channel_AdminLog_TopicClosed(authorTitle, newInfo.info.title) : self.presentationData.strings.Channel_AdminLog_TopicReopened(authorTitle, newInfo.info.title), generateEntities: { index in
|
||||||
if index == 0, let author = author {
|
if index == 0, let author = author {
|
||||||
return [.TextMention(peerId: author.id)]
|
return [.TextMention(peerId: author.id)]
|
||||||
|
@ -1151,7 +1151,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
|||||||
}
|
}
|
||||||
|
|
||||||
var canReport = true
|
var canReport = true
|
||||||
if channel.isVerified || channel.adminRights != nil || channel.flags.contains(.isCreator) {
|
if channel.adminRights != nil || channel.flags.contains(.isCreator) {
|
||||||
canReport = false
|
canReport = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import Postbox
|
|||||||
import TelegramAudio
|
import TelegramAudio
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import AVKit
|
import AVKit
|
||||||
|
import UniversalMediaPlayer
|
||||||
|
|
||||||
public final class OverlayUniversalVideoNode: OverlayMediaItemNode, AVPictureInPictureSampleBufferPlaybackDelegate {
|
public final class OverlayUniversalVideoNode: OverlayMediaItemNode, AVPictureInPictureSampleBufferPlaybackDelegate {
|
||||||
public let content: UniversalVideoContent
|
public let content: UniversalVideoContent
|
||||||
@ -37,6 +38,9 @@ public final class OverlayUniversalVideoNode: OverlayMediaItemNode, AVPictureInP
|
|||||||
public var customClose: (() -> Void)?
|
public var customClose: (() -> Void)?
|
||||||
public var controlsAreShowingUpdated: ((Bool) -> Void)?
|
public var controlsAreShowingUpdated: ((Bool) -> Void)?
|
||||||
|
|
||||||
|
private var statusDisposable: Disposable?
|
||||||
|
private var status: MediaPlayerStatus?
|
||||||
|
|
||||||
public init(postbox: Postbox, audioSession: ManagedAudioSession, manager: UniversalVideoManager, content: UniversalVideoContent, shouldBeDismissed: Signal<Bool, NoError> = .single(false), expand: @escaping () -> Void, close: @escaping () -> Void) {
|
public init(postbox: Postbox, audioSession: ManagedAudioSession, manager: UniversalVideoManager, content: UniversalVideoContent, shouldBeDismissed: Signal<Bool, NoError> = .single(false), expand: @escaping () -> Void, close: @escaping () -> Void) {
|
||||||
self.content = content
|
self.content = content
|
||||||
self.defaultExpand = expand
|
self.defaultExpand = expand
|
||||||
@ -124,6 +128,16 @@ public final class OverlayUniversalVideoNode: OverlayMediaItemNode, AVPictureInP
|
|||||||
strongSelf.dismiss()
|
strongSelf.dismiss()
|
||||||
closeImpl?()
|
closeImpl?()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.statusDisposable = (self.videoNode.status
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||||
|
self?.status = status
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.shouldBeDismissedDisposable?.dispose()
|
||||||
|
self.statusDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func didLoad() {
|
override public func didLoad() {
|
||||||
@ -194,7 +208,10 @@ public final class OverlayUniversalVideoNode: OverlayMediaItemNode, AVPictureInP
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
|
public func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
|
||||||
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: 10.0, preferredTimescale: CMTimeScale(30.0)))
|
guard let status = self.status else {
|
||||||
|
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)))
|
||||||
|
}
|
||||||
|
return CMTimeRange(start: CMTime(seconds: status.timestamp, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: status.duration, preferredTimescale: CMTimeScale(30.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
|
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
|
||||||
|
@ -414,10 +414,6 @@ public final class WebSearchController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateSearchQuery(_ query: String) {
|
private func updateSearchQuery(_ query: String) {
|
||||||
if !query.isEmpty {
|
|
||||||
let _ = addRecentWebSearchQuery(engine: self.context.engine, string: query).start()
|
|
||||||
}
|
|
||||||
|
|
||||||
let scope: Signal<WebSearchScope?, NoError>
|
let scope: Signal<WebSearchScope?, NoError>
|
||||||
switch self.mode {
|
switch self.mode {
|
||||||
case .media:
|
case .media:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user