Cherry-pick more fixes

This commit is contained in:
Ilya Laktyushin 2023-03-24 17:01:39 +04:00
parent c92a855083
commit 158f92cf4e
41 changed files with 468 additions and 413 deletions

View File

@ -89,7 +89,7 @@ public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forcePro
let clipStyle: AvatarNodeClipStyle
if round {
if case let .channel(channel) = peer, channel.flags.contains(.isForum) {
if case let .channel(channel) = peer, channel.isForum {
clipStyle = .roundedRect
} else {
clipStyle = .round

View File

@ -26,9 +26,8 @@ final class BrowserWebContent: UIView, BrowserContent, UIScrollViewDelegate {
let configuration = WKWebViewConfiguration()
self.webView = WKWebView(frame: CGRect(), configuration: configuration)
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
self.webView.allowsLinkPreview = false
}
self.webView.allowsLinkPreview = false
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
self.webView.scrollView.contentInsetAdjustmentBehavior = .never
}

View File

@ -690,13 +690,13 @@ final class CallListControllerNode: ASDisplayNode {
let alpha: CGFloat = isHidden ? 0.0 : 1.0
let previousAlpha = self.emptyTextNode.alpha
self.emptyTextNode.alpha = alpha
self.emptyTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2)
self.emptyTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25)
if previousAlpha.isZero && !alpha.isZero {
self.emptyAnimationNode.visibility = true
}
self.emptyAnimationNode.alpha = alpha
self.emptyAnimationNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2, completion: { [weak self] _ in
self.emptyAnimationNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25, completion: { [weak self] _ in
if let strongSelf = self {
if !previousAlpha.isZero && strongSelf.emptyAnimationNode.alpha.isZero {
strongSelf.emptyAnimationNode.visibility = false
@ -705,9 +705,9 @@ final class CallListControllerNode: ASDisplayNode {
})
self.emptyButtonIconNode.alpha = alpha
self.emptyButtonIconNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2)
self.emptyButtonIconNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25)
self.emptyButtonTextNode.alpha = alpha
self.emptyButtonTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2)
self.emptyButtonTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25)
self.emptyButtonNode.isUserInteractionEnabled = !isHidden
if !isHidden {
@ -733,7 +733,6 @@ final class CallListControllerNode: ASDisplayNode {
}
self.emptyTextNode.attributedText = NSAttributedString(string: emptyText, font: textFont, textColor: color, paragraphAlignment: .center)
self.emptyButtonTextNode.attributedText = NSAttributedString(string: buttonText, font: buttonFont, textColor: theme.list.itemAccentColor, paragraphAlignment: .center)
if let layout = self.containerLayout {

View File

@ -230,7 +230,7 @@ func countMeaningfulCallListEntries(_ entries: [CallListNodeEntry]) -> Int {
var count: Int = 0
for entry in entries {
switch entry.stableId {
case .setting, .groupCall:
case .setting:
break
default:
count += 1

View File

@ -1205,10 +1205,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
controller.navigationPresentation = .modal
controller.completion = { [weak controller] title, fileId, _ in
controller.completion = { [weak controller] title, fileId, iconColor, _ in
controller?.isInProgress = true
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId)
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId)
|> deliverOnMainQueue).start(next: { topicId in
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text, keepStack: .never).start()
}, error: { _ in
@ -2441,10 +2441,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
controller.navigationPresentation = .modal
controller.completion = { [weak controller] title, fileId, _ in
controller.completion = { [weak controller] title, fileId, iconColor, _ in
controller?.isInProgress = true
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId)
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId)
|> deliverOnMainQueue).start(next: { topicId in
if let navigationController = (sourceController.navigationController as? NavigationController) {
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text, keepStack: .never).start()

View File

@ -127,10 +127,8 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
case _ as TelegramMediaImage:
if message.text.isEmpty {
messageText = strings.Message_Photo
} else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
if enableMediaEmoji {
messageText = "🖼 \(messageText)"
}
} else if enableMediaEmoji {
messageText = "🖼 \(messageText)"
}
case let fileMedia as TelegramMediaFile:
var processed = false
@ -188,7 +186,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
if message.text.isEmpty {
messageText = strings.Message_Video
processed = true
} else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
} else {
if enableMediaEmoji {
if !fileMedia.isAnimated {
messageText = "📹 \(messageText)"

View File

@ -209,15 +209,6 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.cancel = cancel
self.effectView = UIVisualEffectView()
if #available(iOS 9.0, *) {
} else {
if self.presentationData.theme.rootController.keyboardColor == .dark {
self.effectView.effect = UIBlurEffect(style: .dark)
} else {
self.effectView.effect = UIBlurEffect(style: .light)
}
self.effectView.alpha = 0.0
}
self.dimNode = ASDisplayNode()
self.dimNode.alpha = 1.0
@ -430,14 +421,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
}
self.presentationData = presentationData
if #available(iOS 9.0, *) {
} else {
if self.presentationData.theme.rootController.keyboardColor == .dark {
self.effectView.effect = UIBlurEffect(style: .dark)
} else {
self.effectView.effect = UIBlurEffect(style: .light)
}
}
self.effectView.effect = makeCustomZoomBlurEffect(isLight: self.presentationData.theme.rootController.keyboardColor == .light)
self.dimNode.backgroundColor = presentationData.theme.contextMenu.dimColor
@ -465,11 +449,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.textInputNode.textView.setContentOffset(self.textInputNode.textView.contentOffset, animated: false)
UIView.animate(withDuration: 0.2, animations: {
if #available(iOS 9.0, *) {
self.effectView.effect = makeCustomZoomBlurEffect(isLight: !self.presentationData.theme.overallDarkAppearance)
} else {
self.effectView.alpha = 1.0
}
self.effectView.effect = makeCustomZoomBlurEffect(isLight: self.presentationData.theme.rootController.keyboardColor == .light)
}, completion: { _ in })
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.contentContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
@ -562,12 +542,8 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
}
}
UIView.animate(withDuration: 0.4, animations: {
if #available(iOS 9.0, *) {
self.effectView.effect = nil
} else {
self.effectView.alpha = 0.0
}
UIView.animate(withDuration: 0.2, animations: {
self.effectView.effect = nil
}, completion: { _ in
completedEffect = true
intermediateCompletion()
@ -596,7 +572,6 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
}
let duration = 0.4
self.sendButtonNode.layer.animatePosition(from: self.sendButtonNode.position, to: self.sendButtonFrame.center, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
completedButton = true
intermediateCompletion()

View File

@ -427,7 +427,7 @@ private struct CreatePollControllerState: Equatable {
var isEditingSolution: Bool = false
}
private func createPollControllerEntries(presentationData: PresentationData, peer: EnginePeer, state: CreatePollControllerState, limitsConfiguration: EngineConfiguration.Limits, defaultIsQuiz: Bool?) -> [CreatePollEntry] {
private func createPollControllerEntries(presentationData: PresentationData, peer: EnginePeer, state: CreatePollControllerState, limitsConfiguration: EngineConfiguration.UserLimits, defaultIsQuiz: Bool?) -> [CreatePollEntry] {
var entries: [CreatePollEntry] = []
var textLimitText = ItemListSectionHeaderAccessoryText(value: "", color: .generic)
@ -436,7 +436,7 @@ private func createPollControllerEntries(presentationData: PresentationData, pee
textLimitText = ItemListSectionHeaderAccessoryText(value: "\(remainingCount)", color: remainingCount < 0 ? .destructive : .generic)
}
entries.append(.textHeader(presentationData.strings.CreatePoll_TextHeader, textLimitText))
entries.append(.text(presentationData.strings.CreatePoll_TextPlaceholder, state.text, Int(limitsConfiguration.maxMediaCaptionLength)))
entries.append(.text(presentationData.strings.CreatePoll_TextPlaceholder, state.text, Int(limitsConfiguration.maxCaptionLength)))
let optionsHeaderTitle: String
if let defaultIsQuiz = defaultIsQuiz, defaultIsQuiz {
optionsHeaderTitle = presentationData.strings.CreatePoll_QuizOptionsHeader
@ -866,7 +866,7 @@ public func createPollController(context: AccountContext, updatedPresentationDat
let signal = combineLatest(queue: .mainQueue(),
presentationData,
statePromise.get(),
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.Limits())
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false))
)
|> map { presentationData, state, limitsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in
var presentationData = presentationData

View File

@ -265,7 +265,7 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin
textColor: titleColor)
}
self.titleLabelNode.isUserInteractionEnabled = self.titleLabelNode.tapAttributeAction != nil
self.titleLabelNode.isUserInteractionEnabled = self.titleLabelNode.tapAttributeAction != nil && self.item.action == nil
self.subtitleNode.attributedText = subtitle.flatMap { subtitle in
return NSAttributedString(

View File

@ -1860,6 +1860,10 @@ final class ControlledTransitionProperty {
let toValue: AnyValue
private let completion: ((Bool) -> Void)?
private lazy var animationKey: String = {
return "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())"
}()
init<T: Equatable>(layer: CALayer, path: String, fromValue: T, toValue: T, completion: ((Bool) -> Void)?) where T: AnyValueProviding {
self.layer = layer
self.path = path
@ -1871,7 +1875,7 @@ final class ControlledTransitionProperty {
}
deinit {
self.layer.removeAnimation(forKey: "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())")
self.layer.removeAnimation(forKey: self.animationKey)
}
func update(at fraction: CGFloat) {
@ -1887,7 +1891,7 @@ final class ControlledTransitionProperty {
animation.toValue = value.nsValue
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.isRemovedOnCompletion = false
self.layer.add(animation, forKey: "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())")
self.layer.add(animation, forKey: self.animationKey)
}
func complete(atEnd: Bool) {

View File

@ -1292,7 +1292,12 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
overrideImage = .deletedIcon
}
strongSelf.avatarNode.imageNode.animateFirstTransition = item.animateFirstAvatarTransition
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad)
var clipStyle: AvatarNodeClipStyle = .round
if case let .channel(channel) = item.peer, channel.isForum {
clipStyle = .roundedRect
}
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: clipStyle, synchronousLoad: synchronousLoad)
}
}

View File

@ -156,7 +156,7 @@ final class LocationSearchContainerNode: ASDisplayNode {
let searchItems = self.searchQuery.get()
|> mapToSignal { query -> Signal<String?, NoError> in
if let query = query, !query.isEmpty {
return (.complete() |> delay(0.6, queue: Queue.mainQueue()))
return (.complete() |> delay(1.0, queue: Queue.mainQueue()))
|> then(.single(query))
} else {
return .single(query)

View File

@ -711,6 +711,10 @@ NSString *suffix = @"";
[platform isEqualToString:@"iPad11,7"])
return @"iPad (8th gen)";
if ([platform isEqualToString:@"iPad12,1"] ||
[platform isEqualToString:@"iPad12,2"])
return @"iPad (9th gen)";
if ([platform isEqualToString:@"iPad13,1"] ||
[platform isEqualToString:@"iPad13,2"])
return @"iPad Air (4th gen)";

View File

@ -466,14 +466,41 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
} else {
effectiveRightsFlags = defaultBannedRightsFlags
}
if value {
effectiveRightsFlags.remove(rights)
effectiveRightsFlags = effectiveRightsFlags.subtracting(groupPermissionDependencies(rights))
if rights == .banSendMedia {
if value {
effectiveRightsFlags.remove(rights)
for item in banSendMediaSubList() {
effectiveRightsFlags.remove(item.0)
}
} else {
effectiveRightsFlags.insert(rights)
for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
}
}
for item in banSendMediaSubList() {
effectiveRightsFlags.insert(item.0)
for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) {
if groupPermissionDependencies(right).contains(item.0) {
effectiveRightsFlags.insert(right)
}
}
}
}
} else {
effectiveRightsFlags.insert(rights)
for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
if value {
effectiveRightsFlags.remove(rights)
effectiveRightsFlags = effectiveRightsFlags.subtracting(groupPermissionDependencies(rights))
} else {
effectiveRightsFlags.insert(rights)
for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
}
}
}
}

View File

@ -826,8 +826,12 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon
case let .member(_, _, _, banInfo, _):
if let banInfo = banInfo {
var exceptionsString = ""
let sendMediaRights = banSendMediaSubList().map { $0.0 }
for (rights, _) in allGroupPermissionList(peer: .channel(channel), expandMedia: true) {
if banInfo.rights.flags.contains(rights) {
if banInfo.rights.flags.contains(.banSendMedia) && sendMediaRights.contains(rights) {
continue
}
if !exceptionsString.isEmpty {
exceptionsString.append(", ")
}
@ -1086,8 +1090,12 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon
case let .member(_, _, _, banInfo, _):
if let banInfo = banInfo {
var exceptionsString = ""
let sendMediaRights = banSendMediaSubList().map { $0.0 }
for (rights, _) in allGroupPermissionList(peer: .legacyGroup(group), expandMedia: true) {
if banInfo.rights.flags.contains(rights) {
if banInfo.rights.flags.contains(.banSendMedia) && sendMediaRights.contains(rights) {
continue
}
if !exceptionsString.isEmpty {
exceptionsString.append(", ")
}

View File

@ -341,8 +341,12 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry {
case let .member(_, _, _, banInfo, _):
var exceptionsString = ""
if let banInfo = banInfo {
let sendMediaRights = banSendMediaSubList().map { $0.0 }
for (rights, _) in internal_allPossibleGroupPermissionList {
if !defaultBannedRights.contains(rights) && banInfo.rights.flags.contains(rights) {
if banInfo.rights.flags.contains(.banSendMedia) && sendMediaRights.contains(rights) {
continue
}
if !exceptionsString.isEmpty {
exceptionsString.append(", ")
}

View File

@ -303,7 +303,13 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
disposable.set((callContext.context.panelData
|> deliverOnMainQueue).start(next: { panelData in
callContext.keep()
subscriber.putNext(panelData)
var updatedPanelData = panelData
if let panelData {
var updatedInfo = panelData.info
updatedInfo.subscribedToScheduled = activeCall.subscribedToScheduled
updatedPanelData = panelData.withInfo(updatedInfo)
}
subscriber.putNext(updatedPanelData)
}))
}

View File

@ -64,6 +64,18 @@ public final class GroupCallPanelData {
self.activeSpeakers = activeSpeakers
self.groupCall = groupCall
}
public func withInfo(_ info: GroupCallInfo) -> GroupCallPanelData {
return GroupCallPanelData(
peerId: self.peerId,
isChannel: self.isChannel,
info: info,
topParticipants: self.topParticipants,
participantCount: self.participantCount,
activeSpeakers: self.activeSpeakers,
groupCall: self.groupCall
)
}
}
private final class FakeAudioLevelGenerator {

View File

@ -116,12 +116,12 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
activeSpeakers: Set(),
groupCall: nil
)))*/
let state = engine.calls.getGroupCallParticipants(callId: call.id, accessHash: call.accessHash, offset: "", ssrcs: [], limit: 100, sortAscending: nil)
|> map(Optional.init)
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
return .single(nil)
}
|> map(Optional.init)
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
return .single(nil)
}
self.disposable = (combineLatest(queue: .mainQueue(),
state,
@ -139,7 +139,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
state: state,
previousServiceState: nil
)
strongSelf.participantsContext = context
strongSelf.panelDataPromise.set(combineLatest(queue: .mainQueue(),
context.state,

View File

@ -1026,7 +1026,7 @@ public final class AccountStateManager {
}
let _ = (signal
|> deliverOn(self.queue)).start(next: { [weak self] messages in
|> deliverOn(self.queue)).start(next: { [weak self] messages in
if let strongSelf = self {
strongSelf.notificationMessagesPipe.putNext(messages)
}
@ -1953,6 +1953,9 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
}
if let channel = message.peers[message.id.peerId] as? TelegramChannel {
if !channel.flags.contains(.isForum) {
threadData = nil
}
switch channel.participationStatus {
case .kicked, .left:
return ([], false, sound, false, threadData)

View File

@ -14,7 +14,7 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
|> mapToSignal { result, defaultHistoryTtl -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Signal<Void, NoError> in
switch result {
case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, captionLengthMax, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, reactionsDefault, autologinToken):
case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, _, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, reactionsDefault, autologinToken):
var addressList: [Int: [MTDatacenterAddress]] = [:]
for option in dcOptions {
switch option {
@ -61,7 +61,7 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
return entry
})
updateLimitsConfiguration(transaction: transaction, configuration: LimitsConfiguration(maxPinnedChatCount: 5, maxArchivedPinnedChatCount: 5, maxGroupMemberCount: chatSizeMax, maxSupergroupMemberCount: megagroupSizeMax, maxMessageForwardBatchSize: forwardedCountMax, maxSavedGifCount: 10, maxRecentStickerCount: stickersRecentLimit, maxFavedStickerCount: 10, maxMessageEditingInterval: editTimeLimit, maxMediaCaptionLength: captionLengthMax, canRemoveIncomingMessagesInPrivateChats: (flags & (1 << 6)) != 0, maxMessageRevokeInterval: revokeTimeLimit, maxMessageRevokeIntervalInPrivateChats: revokePmTimeLimit))
updateLimitsConfiguration(transaction: transaction, configuration: LimitsConfiguration(maxGroupMemberCount: chatSizeMax, maxSupergroupMemberCount: megagroupSizeMax, maxMessageForwardBatchSize: forwardedCountMax, maxRecentStickerCount: stickersRecentLimit, maxMessageEditingInterval: editTimeLimit, canRemoveIncomingMessagesInPrivateChats: (flags & (1 << 6)) != 0, maxMessageRevokeInterval: revokeTimeLimit, maxMessageRevokeIntervalInPrivateChats: revokePmTimeLimit))
updateSearchBotsConfiguration(transaction: transaction, configuration: SearchBotsConfiguration(imageBotUsername: imgSearchUsername, gifBotUsername: gifSearchUsername, venueBotUsername: venueSearchUsername))

View File

@ -3,6 +3,7 @@ import SwiftSignalKit
public struct UserLimitsConfiguration: Equatable {
public let maxPinnedChatCount: Int32
public let maxArchivedPinnedChatCount: Int32
public let maxChannelsCount: Int32
public let maxPublicLinksCount: Int32
public let maxSavedGifCount: Int32
@ -18,6 +19,7 @@ public struct UserLimitsConfiguration: Equatable {
public static var defaultValue: UserLimitsConfiguration {
return UserLimitsConfiguration(
maxPinnedChatCount: 5,
maxArchivedPinnedChatCount: 100,
maxChannelsCount: 500,
maxPublicLinksCount: 10,
maxSavedGifCount: 200,
@ -34,6 +36,7 @@ public struct UserLimitsConfiguration: Equatable {
public init(
maxPinnedChatCount: Int32,
maxArchivedPinnedChatCount: Int32,
maxChannelsCount: Int32,
maxPublicLinksCount: Int32,
maxSavedGifCount: Int32,
@ -47,6 +50,7 @@ public struct UserLimitsConfiguration: Equatable {
maxReactionsPerMessage: Int32
) {
self.maxPinnedChatCount = maxPinnedChatCount
self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount
self.maxChannelsCount = maxChannelsCount
self.maxPublicLinksCount = maxPublicLinksCount
self.maxSavedGifCount = maxSavedGifCount
@ -83,6 +87,7 @@ extension UserLimitsConfiguration {
}
self.maxPinnedChatCount = getValue("dialogs_pinned_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxArchivedPinnedChatCount = getValue("dialogs_folder_pinned_limit", orElse: defaultValue.maxArchivedPinnedChatCount)
self.maxChannelsCount = getValue("channels_limit", orElse: defaultValue.maxChannelsCount)
self.maxPublicLinksCount = getValue("channels_public_limit", orElse: defaultValue.maxPublicLinksCount)
self.maxSavedGifCount = getValue("saved_gifs_limit", orElse: defaultValue.maxSavedGifCount)

View File

@ -3,35 +3,25 @@ import Postbox
public struct LimitsConfiguration: Codable, Equatable {
public static let timeIntervalForever: Int32 = 0x7fffffff
public var maxPinnedChatCount: Int32
public var maxArchivedPinnedChatCount: Int32
public var maxGroupMemberCount: Int32
public var maxSupergroupMemberCount: Int32
public var maxMessageForwardBatchSize: Int32
public var maxSavedGifCount: Int32
public var maxRecentStickerCount: Int32
public var maxFavedStickerCount: Int32
public var maxMessageEditingInterval: Int32
public var maxMediaCaptionLength: Int32
public var canRemoveIncomingMessagesInPrivateChats: Bool
public var maxMessageRevokeInterval: Int32
public var maxMessageRevokeIntervalInPrivateChats: Int32
public static var defaultValue: LimitsConfiguration {
return LimitsConfiguration(maxPinnedChatCount: 5, maxArchivedPinnedChatCount: 20, maxGroupMemberCount: 200, maxSupergroupMemberCount: 200000, maxMessageForwardBatchSize: 50, maxSavedGifCount: 200, maxRecentStickerCount: 20, maxFavedStickerCount: 5, maxMessageEditingInterval: 2 * 24 * 60 * 60, maxMediaCaptionLength: 1000, canRemoveIncomingMessagesInPrivateChats: false, maxMessageRevokeInterval: 2 * 24 * 60 * 60, maxMessageRevokeIntervalInPrivateChats: 2 * 24 * 60 * 60)
return LimitsConfiguration(maxGroupMemberCount: 200, maxSupergroupMemberCount: 200000, maxMessageForwardBatchSize: 50, maxRecentStickerCount: 20, maxMessageEditingInterval: 2 * 24 * 60 * 60, canRemoveIncomingMessagesInPrivateChats: false, maxMessageRevokeInterval: 2 * 24 * 60 * 60, maxMessageRevokeIntervalInPrivateChats: 2 * 24 * 60 * 60)
}
public init(maxPinnedChatCount: Int32, maxArchivedPinnedChatCount: Int32, maxGroupMemberCount: Int32, maxSupergroupMemberCount: Int32, maxMessageForwardBatchSize: Int32, maxSavedGifCount: Int32, maxRecentStickerCount: Int32, maxFavedStickerCount: Int32, maxMessageEditingInterval: Int32, maxMediaCaptionLength: Int32, canRemoveIncomingMessagesInPrivateChats: Bool, maxMessageRevokeInterval: Int32, maxMessageRevokeIntervalInPrivateChats: Int32) {
self.maxPinnedChatCount = maxPinnedChatCount
self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount
public init(maxGroupMemberCount: Int32, maxSupergroupMemberCount: Int32, maxMessageForwardBatchSize: Int32, maxRecentStickerCount: Int32, maxMessageEditingInterval: Int32, canRemoveIncomingMessagesInPrivateChats: Bool, maxMessageRevokeInterval: Int32, maxMessageRevokeIntervalInPrivateChats: Int32) {
self.maxGroupMemberCount = maxGroupMemberCount
self.maxSupergroupMemberCount = maxSupergroupMemberCount
self.maxMessageForwardBatchSize = maxMessageForwardBatchSize
self.maxSavedGifCount = maxSavedGifCount
self.maxRecentStickerCount = maxRecentStickerCount
self.maxFavedStickerCount = maxFavedStickerCount
self.maxMessageEditingInterval = maxMessageEditingInterval
self.maxMediaCaptionLength = maxMediaCaptionLength
self.canRemoveIncomingMessagesInPrivateChats = canRemoveIncomingMessagesInPrivateChats
self.maxMessageRevokeInterval = maxMessageRevokeInterval
self.maxMessageRevokeIntervalInPrivateChats = maxMessageRevokeIntervalInPrivateChats
@ -40,16 +30,11 @@ public struct LimitsConfiguration: Codable, Equatable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
self.maxPinnedChatCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxPinnedChatCount")) ?? 5
self.maxArchivedPinnedChatCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxArchivedPinnedChatCount")) ?? 20
self.maxGroupMemberCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxGroupMemberCount")) ?? 200
self.maxSupergroupMemberCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxSupergroupMemberCount")) ?? 5000
self.maxMessageForwardBatchSize = (try? container.decodeIfPresent(Int32.self, forKey: "maxMessageForwardBatchSize")) ?? 50
self.maxSavedGifCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxSavedGifCount")) ?? 200
self.maxRecentStickerCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxRecentStickerCount")) ?? 20
self.maxFavedStickerCount = (try? container.decodeIfPresent(Int32.self, forKey: "maxFavedStickerCount")) ?? 5
self.maxMessageEditingInterval = (try? container.decodeIfPresent(Int32.self, forKey: "maxMessageEditingInterval")) ?? (2 * 24 * 60 * 60)
self.maxMediaCaptionLength = (try? container.decodeIfPresent(Int32.self, forKey: "maxMediaCaptionLength")) ?? 1000
self.canRemoveIncomingMessagesInPrivateChats = (try? container.decodeIfPresent(Int32.self, forKey: "canRemoveIncomingMessagesInPrivateChats") ?? 0) != 0
self.maxMessageRevokeInterval = (try? container.decodeIfPresent(Int32.self, forKey: "maxMessageRevokeInterval")) ?? (2 * 24 * 60 * 60)
self.maxMessageRevokeIntervalInPrivateChats = (try? container.decodeIfPresent(Int32.self, forKey: "maxMessageRevokeIntervalInPrivateChats")) ?? (2 * 24 * 60 * 60)
@ -58,16 +43,11 @@ public struct LimitsConfiguration: Codable, Equatable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encode(self.maxPinnedChatCount, forKey: "maxPinnedChatCount")
try container.encode(self.maxArchivedPinnedChatCount, forKey: "maxArchivedPinnedChatCount")
try container.encode(self.maxGroupMemberCount, forKey: "maxGroupMemberCount")
try container.encode(self.maxSupergroupMemberCount, forKey: "maxSupergroupMemberCount")
try container.encode(self.maxMessageForwardBatchSize, forKey: "maxMessageForwardBatchSize")
try container.encode(self.maxSavedGifCount, forKey: "maxSavedGifCount")
try container.encode(self.maxRecentStickerCount, forKey: "maxRecentStickerCount")
try container.encode(self.maxFavedStickerCount, forKey: "maxFavedStickerCount")
try container.encode(self.maxMessageEditingInterval, forKey: "maxMessageEditingInterval")
try container.encode(self.maxMediaCaptionLength, forKey: "maxMediaCaptionLength")
try container.encode((self.canRemoveIncomingMessagesInPrivateChats ? 1 : 0) as Int32, forKey: "canRemoveIncomingMessagesInPrivateChats")
try container.encode(self.maxMessageRevokeInterval, forKey: "maxMessageRevokeInterval")
try container.encode(self.maxMessageRevokeIntervalInPrivateChats, forKey: "maxMessageRevokeIntervalInPrivateChats")

View File

@ -5,45 +5,30 @@ public enum EngineConfiguration {
public struct Limits: Equatable {
public static let timeIntervalForever: Int32 = 0x7fffffff
public var maxPinnedChatCount: Int32
public var maxArchivedPinnedChatCount: Int32
public var maxGroupMemberCount: Int32
public var maxSupergroupMemberCount: Int32
public var maxMessageForwardBatchSize: Int32
public var maxSavedGifCount: Int32
public var maxFavedStickerCount: Int32
public var maxRecentStickerCount: Int32
public var maxMessageEditingInterval: Int32
public var maxMediaCaptionLength: Int32
public var canRemoveIncomingMessagesInPrivateChats: Bool
public var maxMessageRevokeInterval: Int32
public var maxMessageRevokeIntervalInPrivateChats: Int32
public init(
maxPinnedChatCount: Int32,
maxArchivedPinnedChatCount: Int32,
maxGroupMemberCount: Int32,
maxSupergroupMemberCount: Int32,
maxMessageForwardBatchSize: Int32,
maxSavedGifCount: Int32,
maxFavedStickerCount: Int32,
maxRecentStickerCount: Int32,
maxMessageEditingInterval: Int32,
maxMediaCaptionLength: Int32,
canRemoveIncomingMessagesInPrivateChats: Bool,
maxMessageRevokeInterval: Int32,
maxMessageRevokeIntervalInPrivateChats: Int32
) {
self.maxPinnedChatCount = maxPinnedChatCount
self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount
self.maxGroupMemberCount = maxGroupMemberCount
self.maxSupergroupMemberCount = maxSupergroupMemberCount
self.maxMessageForwardBatchSize = maxMessageForwardBatchSize
self.maxSavedGifCount = maxSavedGifCount
self.maxFavedStickerCount = maxFavedStickerCount
self.maxRecentStickerCount = maxRecentStickerCount
self.maxMessageEditingInterval = maxMessageEditingInterval
self.maxMediaCaptionLength = maxMediaCaptionLength
self.canRemoveIncomingMessagesInPrivateChats = canRemoveIncomingMessagesInPrivateChats
self.maxMessageRevokeInterval = maxMessageRevokeInterval
self.maxMessageRevokeIntervalInPrivateChats = maxMessageRevokeIntervalInPrivateChats
@ -52,6 +37,7 @@ public enum EngineConfiguration {
public struct UserLimits: Equatable {
public let maxPinnedChatCount: Int32
public let maxArchivedPinnedChatCount: Int32
public let maxChannelsCount: Int32
public let maxPublicLinksCount: Int32
public let maxSavedGifCount: Int32
@ -70,6 +56,7 @@ public enum EngineConfiguration {
public init(
maxPinnedChatCount: Int32,
maxArchivedPinnedChatCount: Int32,
maxChannelsCount: Int32,
maxPublicLinksCount: Int32,
maxSavedGifCount: Int32,
@ -83,6 +70,7 @@ public enum EngineConfiguration {
maxReactionsPerMessage: Int32
) {
self.maxPinnedChatCount = maxPinnedChatCount
self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount
self.maxChannelsCount = maxChannelsCount
self.maxPublicLinksCount = maxPublicLinksCount
self.maxSavedGifCount = maxSavedGifCount
@ -103,16 +91,11 @@ public typealias EngineContentSettings = ContentSettings
public extension EngineConfiguration.Limits {
init(_ limitsConfiguration: LimitsConfiguration) {
self.init(
maxPinnedChatCount: limitsConfiguration.maxPinnedChatCount,
maxArchivedPinnedChatCount: limitsConfiguration.maxArchivedPinnedChatCount,
maxGroupMemberCount: limitsConfiguration.maxGroupMemberCount,
maxSupergroupMemberCount: limitsConfiguration.maxSupergroupMemberCount,
maxMessageForwardBatchSize: limitsConfiguration.maxMessageForwardBatchSize,
maxSavedGifCount: limitsConfiguration.maxSavedGifCount,
maxFavedStickerCount: limitsConfiguration.maxFavedStickerCount,
maxRecentStickerCount: limitsConfiguration.maxRecentStickerCount,
maxMessageEditingInterval: limitsConfiguration.maxMessageEditingInterval,
maxMediaCaptionLength: limitsConfiguration.maxMediaCaptionLength,
canRemoveIncomingMessagesInPrivateChats: limitsConfiguration.canRemoveIncomingMessagesInPrivateChats,
maxMessageRevokeInterval: limitsConfiguration.maxMessageRevokeInterval,
maxMessageRevokeIntervalInPrivateChats: limitsConfiguration.maxMessageRevokeIntervalInPrivateChats
@ -121,16 +104,11 @@ public extension EngineConfiguration.Limits {
func _asLimits() -> LimitsConfiguration {
return LimitsConfiguration(
maxPinnedChatCount: self.maxPinnedChatCount,
maxArchivedPinnedChatCount: self.maxArchivedPinnedChatCount,
maxGroupMemberCount: self.maxGroupMemberCount,
maxSupergroupMemberCount: self.maxSupergroupMemberCount,
maxMessageForwardBatchSize: self.maxMessageForwardBatchSize,
maxSavedGifCount: self.maxSavedGifCount,
maxRecentStickerCount: self.maxRecentStickerCount,
maxFavedStickerCount: self.maxFavedStickerCount,
maxMessageEditingInterval: self.maxMessageEditingInterval,
maxMediaCaptionLength: self.maxMediaCaptionLength,
canRemoveIncomingMessagesInPrivateChats: self.canRemoveIncomingMessagesInPrivateChats,
maxMessageRevokeInterval: self.maxMessageRevokeInterval,
maxMessageRevokeIntervalInPrivateChats: self.maxMessageRevokeIntervalInPrivateChats
@ -142,6 +120,7 @@ public extension EngineConfiguration.UserLimits {
init(_ userLimitsConfiguration: UserLimitsConfiguration) {
self.init(
maxPinnedChatCount: userLimitsConfiguration.maxPinnedChatCount,
maxArchivedPinnedChatCount: userLimitsConfiguration.maxArchivedPinnedChatCount,
maxChannelsCount: userLimitsConfiguration.maxChannelsCount,
maxPublicLinksCount: userLimitsConfiguration.maxPublicLinksCount,
maxSavedGifCount: userLimitsConfiguration.maxSavedGifCount,

View File

@ -457,8 +457,13 @@ extension EngineChatList.Item {
let readCounters = readState.flatMap(EnginePeerReadCounters.init)
if let channel = renderedPeer.peer as? TelegramChannel, channel.flags.contains(.isForum) {
draft = nil
if let channel = renderedPeer.peer as? TelegramChannel {
if channel.flags.contains(.isForum) {
draft = nil
} else {
forumTopicDataValue = nil
topForumTopicItems = []
}
}
self.init(

View File

@ -17,7 +17,6 @@ func _internal_toggleItemPinned(postbox: Postbox, accountPeerId: PeerId, locatio
let isPremium = transaction.getPeer(accountPeerId)?.isPremium ?? false
let appConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? .defaultValue
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
let userLimitsConfiguration = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: isPremium)
switch location {
@ -46,7 +45,7 @@ func _internal_toggleItemPinned(postbox: Postbox, accountPeerId: PeerId, locatio
if case .root = groupId {
limitCount = Int(userLimitsConfiguration.maxPinnedChatCount)
} else {
limitCount = Int(limitsConfiguration.maxArchivedPinnedChatCount)
limitCount = Int(userLimitsConfiguration.maxArchivedPinnedChatCount)
}
let count = sameKind.count + additionalCount

View File

@ -95,6 +95,7 @@ private final class TitleFieldComponent: Component {
let iconColor: Int32
let text: String
let placeholderText: String
let isEditing: Bool
let textUpdated: (String) -> Void
let iconPressed: () -> Void
@ -108,6 +109,7 @@ private final class TitleFieldComponent: Component {
iconColor: Int32,
text: String,
placeholderText: String,
isEditing: Bool,
textUpdated: @escaping (String) -> Void,
iconPressed: @escaping () -> Void
) {
@ -120,6 +122,7 @@ private final class TitleFieldComponent: Component {
self.iconColor = iconColor
self.text = text
self.placeholderText = placeholderText
self.isEditing = isEditing
self.textUpdated = textUpdated
self.iconPressed = iconPressed
}
@ -152,6 +155,9 @@ private final class TitleFieldComponent: Component {
if lhs.placeholderText != rhs.placeholderText {
return false
}
if lhs.isEditing != rhs.isEditing {
return false
}
return true
}
@ -237,6 +243,7 @@ private final class TitleFieldComponent: Component {
iconContent = .animation(content: .customEmoji(fileId: component.fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: component.placeholderColor, themeColor: component.accentColor, loopMode: .count(2))
self.iconButton.isUserInteractionEnabled = false
}
self.iconButton.isUserInteractionEnabled = !component.isEditing
let placeholderSize = self.placeholderView.update(
transition: .easeInOut(duration: 0.2),
@ -471,15 +478,26 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
let mode: ForumCreateTopicScreen.Mode
let titleUpdated: (String) -> Void
let iconUpdated: (Int64?) -> Void
let iconColorUpdated: (Int32) -> Void
let isHiddenUpdated: (Bool) -> Void
let openPremium: () -> Void
init(context: AccountContext, peerId: EnginePeer.Id, mode: ForumCreateTopicScreen.Mode, titleUpdated: @escaping (String) -> Void, iconUpdated: @escaping (Int64?) -> Void, isHiddenUpdated: @escaping (Bool) -> Void, openPremium: @escaping () -> Void) {
init(
context: AccountContext,
peerId: EnginePeer.Id,
mode: ForumCreateTopicScreen.Mode,
titleUpdated: @escaping (String) -> Void,
iconUpdated: @escaping (Int64?) -> Void,
iconColorUpdated: @escaping (Int32) -> Void,
isHiddenUpdated: @escaping (Bool) -> Void,
openPremium: @escaping () -> Void
) {
self.context = context
self.peerId = peerId
self.mode = mode
self.titleUpdated = titleUpdated
self.iconUpdated = iconUpdated
self.iconColorUpdated = iconColorUpdated
self.isHiddenUpdated = isHiddenUpdated
self.openPremium = openPremium
}
@ -501,6 +519,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
private let context: AccountContext
private let titleUpdated: (String) -> Void
private let iconUpdated: (Int64?) -> Void
private let iconColorUpdated: (Int32) -> Void
private let isHiddenUpdated: (Bool) -> Void
private let openPremium: () -> Void
@ -520,10 +539,11 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
private var hasPremium: Bool = false
init(context: AccountContext, mode: ForumCreateTopicScreen.Mode, titleUpdated: @escaping (String) -> Void, iconUpdated: @escaping (Int64?) -> Void, isHiddenUpdated: @escaping (Bool) -> Void, openPremium: @escaping () -> Void) {
init(context: AccountContext, mode: ForumCreateTopicScreen.Mode, titleUpdated: @escaping (String) -> Void, iconUpdated: @escaping (Int64?) -> Void, iconColorUpdated: @escaping (Int32) -> Void, isHiddenUpdated: @escaping (Bool) -> Void, openPremium: @escaping () -> Void) {
self.context = context
self.titleUpdated = titleUpdated
self.iconUpdated = iconUpdated
self.iconColorUpdated = iconColorUpdated
self.isHiddenUpdated = isHiddenUpdated
self.openPremium = openPremium
@ -534,6 +554,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
self.fileId = 0
self.iconColor = ForumCreateTopicScreen.iconColors.randomElement() ?? 0x0
self.isHidden = false
iconColorUpdated(self.iconColor)
case let .edit(threadId, info, isHidden):
self.isGeneral = threadId == 1
self.title = info.title
@ -647,6 +668,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
self.iconColor = colors.first ?? 0
}
self.updated(transition: .immediate)
self.iconColorUpdated(self.iconColor)
self.updateEmojiContent()
}
@ -678,6 +700,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
mode: self.mode,
titleUpdated: self.titleUpdated,
iconUpdated: self.iconUpdated,
iconColorUpdated: self.iconColorUpdated,
isHiddenUpdated: self.isHiddenUpdated,
openPremium: self.openPremium
)
@ -753,6 +776,11 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight + titleBackground.size.height / 2.0))
)
var isEditing = false
if case .edit = context.component.mode {
isEditing = true
}
let titleField = titleField.update(
component: TitleFieldComponent(
context: context.component.context,
@ -764,6 +792,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
iconColor: state.iconColor,
text: state.title,
placeholderText: environment.strings.CreateTopic_EnterTopicTitlePlaceholder,
isEditing: isEditing,
textUpdated: { [weak state] text in
state?.updateTitle(text)
},
@ -999,8 +1028,8 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
private var doneBarItem: UIBarButtonItem?
private var state: (String, Int64?, Bool?) = ("", nil, nil)
public var completion: (String, Int64?, Bool?) -> Void = { _, _, _ in }
private var state: (title: String, icon: Int64?, iconColor: Int32, isHidden: Bool?) = ("", nil, 0, nil)
public var completion: (_ title: String, _ icon: Int64?, _ iconColor: Int32, _ isHidden: Bool?) -> Void = { _, _, _, _ in }
public var isInProgress: Bool = false {
didSet {
@ -1021,6 +1050,7 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
var titleUpdatedImpl: ((String) -> Void)?
var iconUpdatedImpl: ((Int64?) -> Void)?
var iconColorUpdatedImpl: ((Int32) -> Void)?
var isHiddenUpdatedImpl: ((Bool) -> Void)?
var openPremiumImpl: (() -> Void)?
@ -1028,6 +1058,8 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
titleUpdatedImpl?(title)
}, iconUpdated: { fileId in
iconUpdatedImpl?(fileId)
}, iconColorUpdated: { iconColor in
iconColorUpdatedImpl?(iconColor)
}, isHiddenUpdated: { isHidden in
isHiddenUpdatedImpl?(isHidden)
}, openPremium: {
@ -1045,7 +1077,7 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
title = presentationData.strings.CreateTopic_EditTitle
doneTitle = presentationData.strings.Common_Done
self.state = (topic.title, topic.icon, threadId == 1 ? isHidden : nil)
self.state = (topic.title, topic.icon, topic.iconColor, threadId == 1 ? isHidden : nil)
}
self.title = title
@ -1066,23 +1098,28 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
}
strongSelf.doneBarItem?.isEnabled = !title.isEmpty
strongSelf.state = (title, strongSelf.state.1, strongSelf.state.2)
strongSelf.state = (title, strongSelf.state.icon, strongSelf.state.iconColor, strongSelf.state.isHidden)
}
iconUpdatedImpl = { [weak self] fileId in
guard let strongSelf = self else {
return
}
strongSelf.state = (strongSelf.state.0, fileId, strongSelf.state.2)
strongSelf.state = (strongSelf.state.title, fileId, strongSelf.state.iconColor, strongSelf.state.isHidden)
}
iconColorUpdatedImpl = { [weak self] iconColor in
guard let strongSelf = self else {
return
}
strongSelf.state = (strongSelf.state.title, strongSelf.state.icon, iconColor, strongSelf.state.isHidden)
}
isHiddenUpdatedImpl = { [weak self] isHidden in
guard let strongSelf = self else {
return
}
strongSelf.state = (strongSelf.state.0, strongSelf.state.1, isHidden)
strongSelf.state = (strongSelf.state.title, strongSelf.state.icon, strongSelf.state.iconColor, isHidden)
}
openPremiumImpl = { [weak self] in
@ -1113,6 +1150,6 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
}
@objc private func createPressed() {
self.completion(self.state.0, self.state.1, self.state.2)
self.completion(self.state.title, self.state.icon, self.state.iconColor, self.state.isHidden)
}
}

View File

@ -2401,7 +2401,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
self.openChatWhenReady(accountId: accountId, peerId: peerId, threadId: threadId, messageId: messageId)
}
completionHandler()
} else if response.actionIdentifier == "reply", let (peerId, _) = peerIdFromNotification(response.notification), let accountId = accountId {
} else if response.actionIdentifier == "reply", let (peerId, threadId) = peerIdFromNotification(response.notification), let accountId = accountId {
guard let response = response as? UNTextInputNotificationResponse, !response.userText.isEmpty else {
completionHandler()
return
@ -2427,7 +2427,11 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
if let messageId = messageIdFromNotification(peerId: peerId, notification: response.notification) {
let _ = TelegramEngine(account: account).messages.applyMaxReadIndexInteractively(index: MessageIndex(id: messageId, timestamp: 0)).start()
}
return enqueueMessages(account: account, peerId: peerId, messages: [EnqueueMessage.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])])
var replyToMessageId: MessageId?
if let threadId {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))
}
return enqueueMessages(account: account, peerId: peerId, messages: [EnqueueMessage.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])])
|> map { messageIds -> MessageId? in
if messageIds.isEmpty {
return nil

View File

@ -3913,7 +3913,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(string: message.text), snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: inputText, snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in
return self?.getCaptionPanelView()
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
if let strongSelf = self {
@ -7891,7 +7892,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var webpageUrl: String?
for media in message.media {
if media is TelegramMediaImage || media is TelegramMediaFile {
inputTextMaxLength = strongSelf.context.currentLimitsConfiguration.with { $0 }.maxMediaCaptionLength
inputTextMaxLength = strongSelf.context.userLimits.maxCaptionLength
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
webpageUrl = content.url
}
@ -8128,16 +8129,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self, let peerId = strongSelf.chatLocation.peerId {
let presentationData = strongSelf.presentationData
let forwardOptions: Signal<ChatControllerSubject.ForwardOptions, NoError>
if peerId.namespace == Namespaces.Peer.SecretChat {
forwardOptions = .single(ChatControllerSubject.ForwardOptions(hideNames: true, hideCaptions: false))
} else {
forwardOptions = strongSelf.presentationInterfaceStatePromise.get()
|> map { state -> ChatControllerSubject.ForwardOptions in
return ChatControllerSubject.ForwardOptions(hideNames: state.interfaceState.forwardOptionsState?.hideNames ?? false, hideCaptions: state.interfaceState.forwardOptionsState?.hideCaptions ?? false)
let forwardOptions = strongSelf.presentationInterfaceStatePromise.get()
|> map { state -> ChatControllerSubject.ForwardOptions in
var hideNames = state.interfaceState.forwardOptionsState?.hideNames ?? false
if peerId.namespace == Namespaces.Peer.SecretChat {
hideNames = true
}
|> distinctUntilChanged
return ChatControllerSubject.ForwardOptions(hideNames: hideNames, hideCaptions: state.interfaceState.forwardOptionsState?.hideCaptions ?? false)
}
|> distinctUntilChanged
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .forwardedMessages(peerIds: [peerId], ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], options: forwardOptions), botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
@ -8197,88 +8197,90 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
let canHideNames = hasNotOwnMessages && hasOther
var canHideNames = hasNotOwnMessages && hasOther
if case let .peer(peerId) = strongSelf.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat {
canHideNames = false
}
let hideNames = forwardOptions.hideNames
let hideCaptions = forwardOptions.hideCaptions
if case let .peer(peerId) = strongSelf.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat {
if canHideNames {
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in
if hideNames {
return nil
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}
}, action: { [weak self] _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideNames = false
updated.hideCaptions = false
updated.unhideNamesOnCaptionChange = false
return updated
})
})))
} else {
if canHideNames {
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in
if hideNames {
return nil
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}
}, action: { [weak self] _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideNames = false
updated.hideCaptions = false
updated.unhideNamesOnCaptionChange = false
return updated
})
})))
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_HideSendersName : presentationData.strings.Conversation_ForwardOptions_HideSendersNames, icon: { theme in
if hideNames {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideNames = true
updated.unhideNamesOnCaptionChange = false
return updated
})
})))
items.append(.separator)
}
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_HideSendersName : presentationData.strings.Conversation_ForwardOptions_HideSendersNames, icon: { theme in
if hideNames {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideNames = true
updated.unhideNamesOnCaptionChange = false
return updated
})
})))
if hasCaptions {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in
if hideCaptions {
return nil
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}
}, action: { [weak self] _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideCaptions = false
items.append(.separator)
}
if hasCaptions {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in
if hideCaptions {
return nil
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}
}, action: { [weak self] _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideCaptions = false
if canHideNames {
if updated.unhideNamesOnCaptionChange {
updated.unhideNamesOnCaptionChange = false
updated.hideNames = false
}
return updated
})
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideCaption, icon: { theme in
if hideCaptions {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideCaptions = true
return updated
})
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideCaption, icon: { theme in
if hideCaptions {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, f in
self?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideCaptions = true
if canHideNames {
if !updated.hideNames {
updated.hideNames = true
updated.unhideNamesOnCaptionChange = true
}
return updated
})
})))
items.append(.separator)
}
}
return updated
})
})))
items.append(.separator)
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ChangeRecipient, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in
@ -11348,7 +11350,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
var layout = layout
if case .compact = layout.metrics.widthClass, let _ = self.attachmentController {
if case .compact = layout.metrics.widthClass, let attachmentController = self.attachmentController, attachmentController.window != nil {
layout = layout.withUpdatedInputHeight(nil)
}
@ -15989,7 +15991,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.dismiss()
let navigateToLocation: NavigateToChatControllerParams.Location
if let message = messages.first, let threadId = message.threadId, threadId != 1 || (message.peers[message.id.peerId] as? TelegramChannel)?.flags.contains(.isForum) == true {
if let message = messages.first, let threadId = message.threadId, let channel = message.peers[message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
} else {
navigateToLocation = .peer(peer)

View File

@ -438,7 +438,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
let dimensions = item.stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fitSize = item.large ? CGSize(width: 384.0, height: 384.0) : CGSize(width: 160.0, height: 160.0)
let fittedDimensions = dimensions.cgSize.aspectFitted(fitSize)
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: item.stickerItem.file.resource, isVideo: item.stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: item.stickerItem.file.resource, isVideo: item.stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
}
}
}

View File

@ -70,7 +70,6 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
self.maskForeground.masksToBounds = true
self.maskLayer.addSublayer(self.maskForeground)
self.addSubnode(self.interactiveFileNode)
self.addSubnode(self.interactiveVideoNode)
self.interactiveVideoNode.requestUpdateLayout = { [weak self] _ in
@ -285,14 +284,9 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
return (finalSize, { [weak self] animation, synchronousLoads, applyInfo in
if let strongSelf = self {
let firstTime = strongSelf.item == nil
strongSelf.item = item
strongSelf.isExpanded = isExpanded
if firstTime {
strongSelf.interactiveFileNode.isHidden = true
}
strongSelf.bubbleBackgroundNode?.layer.mask = strongSelf.maskLayer
if let bubbleBackdropNode = strongSelf.bubbleBackdropNode, bubbleBackdropNode.hasImage && strongSelf.backdropMaskForeground.superlayer == nil {
strongSelf.bubbleBackdropNode?.overrideMask = true

View File

@ -1601,7 +1601,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
let duration: Double = 0.2
node.alpha = 1.0
node.isHidden = false
if node.supernode == nil {
self.supernode?.insertSubnode(node, belowSubnode: self)
}
self.alpha = 0.0
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
@ -1715,7 +1717,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
node.alpha = 0.0
node.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, completion: { _ in
node.isHidden = true
node.removeFromSupernode()
})
node.waveformView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)

View File

@ -1315,7 +1315,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
strongSelf.animatedStickerNode = animatedStickerNode
let dimensions = updatedAnimatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0))
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: updatedAnimatedStickerFile.resource, isVideo: updatedAnimatedStickerFile.isVideo), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: updatedAnimatedStickerFile.resource, isVideo: updatedAnimatedStickerFile.isVideo), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
strongSelf.pinchContainerNode.contentNode.insertSubnode(animatedStickerNode, aboveSubnode: strongSelf.imageNode)
animatedStickerNode.visibility = strongSelf.visibility
}
@ -1687,8 +1687,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
state = .none
badgeContent = nil
} else if wideLayout {
if let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
if let size = file.size, size > 0 && size != .max {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
if let duration = file.duration, !message.flags.contains(.Unsent) {
let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
if isMediaStreamable(message: message, media: file) {
@ -1721,8 +1721,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
state = automaticPlayback ? .none : state
}
} else {
if isMediaStreamable(message: message, media: file), let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
if isMediaStreamable(message: message, media: file), let fileSize = file.size, fileSize > 0 && fileSize != .max {
let sizeString = "\(dataSizeString(Int64(Float(fileSize) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(fileSize, forceDecimal: true, formatting: formatting))"
if message.flags.contains(.Unsent), let duration = file.duration {
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
@ -1749,8 +1749,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if let duration = file.duration, !file.isAnimated {
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
if automaticPlayback, let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
if automaticPlayback, let fileSize = file.size, fileSize > 0 && fileSize != .max {
let sizeString = "\(dataSizeString(Int64(Float(fileSize) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(fileSize, forceDecimal: true, formatting: formatting))"
mediaDownloadState = .fetching(progress: progress)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active)
} else {
@ -1800,9 +1800,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
do {
let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : (file.duration ?? 0), position: playerPosition)
if wideLayout {
if isMediaStreamable(message: message, media: file) {
if isMediaStreamable(message: message, media: file), let fileSize = file.size, fileSize > 0 && fileSize != .max {
state = automaticPlayback ? .none : .play(messageTheme.mediaOverlayControlColors.foregroundColor)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: dataSizeString(file.size ?? 0, formatting: formatting), muted: muted, active: true)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: dataSizeString(fileSize, formatting: formatting), muted: muted, active: true)
mediaDownloadState = .remote
} else {
state = automaticPlayback ? .none : state

View File

@ -263,19 +263,16 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
} else if item.messages[0].id.peerId.namespace == Namespaces.Peer.CloudGroup {
isGroup = true
}
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
if isChannel {
switch kind {
case .image:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count))
case .video:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count))
case .file:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_DOCS_TEXT(Int32(item.messages.count))
default:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHANNEL_MESSAGES_TEXT(Int32(item.messages.count))
}
} else if isGroup, var author = item.messages[0].author {
@ -284,31 +281,23 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
}
switch kind {
case .image:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHAT_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle)
case .video:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHAT_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle)
case .file:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHAT_MESSAGE_DOCS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle)
default:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_CHAT_MESSAGES_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle)
}
} else {
switch kind {
case .image:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count))
case .video:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count))
case .file:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_MESSAGE_FILES_TEXT(Int32(item.messages.count))
default:
title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder)
messageText = presentationData.strings.PUSH_MESSAGES_TEXT(Int32(item.messages.count))
}
}
@ -325,6 +314,10 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
title = "📅 \(currentTitle)"
}
if let attribute = item.messages.first?.attributes.first(where: { $0 is NotificationInfoMessageAttribute }) as? NotificationInfoMessageAttribute, attribute.flags.contains(.muted), let currentTitle = title {
title = "\(currentTitle) 🔕"
}
let textFont = compact ? Font.regular(15.0) : Font.regular(16.0)
let textColor = presentationData.theme.inAppNotification.primaryTextColor
var attributedMessageText: NSAttributedString

View File

@ -183,7 +183,8 @@ final class PeerInfoScreenData {
let chatPeer: Peer?
let cachedData: CachedPeerData?
let status: PeerInfoStatusData?
let notificationSettings: TelegramPeerNotificationSettings?
let peerNotificationSettings: TelegramPeerNotificationSettings?
let threadNotificationSettings: TelegramPeerNotificationSettings?
let globalNotificationSettings: EngineGlobalNotificationSettings?
let isContact: Bool
let availablePanes: [PeerInfoPaneKey]
@ -204,7 +205,8 @@ final class PeerInfoScreenData {
chatPeer: Peer?,
cachedData: CachedPeerData?,
status: PeerInfoStatusData?,
notificationSettings: TelegramPeerNotificationSettings?,
peerNotificationSettings: TelegramPeerNotificationSettings?,
threadNotificationSettings: TelegramPeerNotificationSettings?,
globalNotificationSettings: EngineGlobalNotificationSettings?,
isContact: Bool,
availablePanes: [PeerInfoPaneKey],
@ -224,7 +226,8 @@ final class PeerInfoScreenData {
self.chatPeer = chatPeer
self.cachedData = cachedData
self.status = status
self.notificationSettings = notificationSettings
self.peerNotificationSettings = peerNotificationSettings
self.threadNotificationSettings = threadNotificationSettings
self.globalNotificationSettings = globalNotificationSettings
self.isContact = isContact
self.availablePanes = availablePanes
@ -521,7 +524,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
chatPeer: peer,
cachedData: peerView.cachedData,
status: nil,
notificationSettings: nil,
peerNotificationSettings: nil,
threadNotificationSettings: nil,
globalNotificationSettings: nil,
isContact: false,
availablePanes: [],
@ -550,7 +554,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
chatPeer: nil,
cachedData: nil,
status: nil,
notificationSettings: nil,
peerNotificationSettings: nil,
threadNotificationSettings: nil,
globalNotificationSettings: nil,
isContact: false,
availablePanes: [],
@ -683,7 +688,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
chatPeer: peerView.peers[peerId],
cachedData: peerView.cachedData,
status: status,
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
threadNotificationSettings: nil,
globalNotificationSettings: globalNotificationSettings,
isContact: peerView.peerIsContact,
availablePanes: availablePanes ?? [],
@ -761,7 +767,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
chatPeer: peerView.peers[peerId],
cachedData: peerView.cachedData,
status: status,
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
threadNotificationSettings: nil,
globalNotificationSettings: globalNotificationSettings,
isContact: peerView.peerIsContact,
availablePanes: availablePanes ?? [],
@ -948,12 +955,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
}
var notificationSettings: TelegramPeerNotificationSettings?
if let threadData = threadData {
notificationSettings = threadData.notificationSettings
} else {
notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings
}
let peerNotificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings
let threadNotificationSettings = threadData?.notificationSettings
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
@ -962,7 +965,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
chatPeer: peerView.peers[groupId],
cachedData: peerView.cachedData,
status: status,
notificationSettings: notificationSettings,
peerNotificationSettings: peerNotificationSettings,
threadNotificationSettings: threadNotificationSettings,
globalNotificationSettings: globalNotificationSettings,
isContact: peerView.peerIsContact,
availablePanes: availablePanes ?? [],
@ -1305,3 +1309,42 @@ func peerInfoCanEdit(peer: Peer?, chatLocation: ChatLocation, threadData: Messag
}
return false
}
func peerInfoIsChatMuted(peer: Peer?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?) -> Bool {
func isPeerMuted(peer: Peer?, peerNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?) -> Bool {
var peerIsMuted = false
if let peerNotificationSettings {
if case .muted = peerNotificationSettings.muteState {
peerIsMuted = true
} else if case .default = peerNotificationSettings.muteState, let globalNotificationSettings {
if let peer {
if peer is TelegramUser {
peerIsMuted = !globalNotificationSettings.privateChats.enabled
} else if peer is TelegramGroup {
peerIsMuted = !globalNotificationSettings.groupChats.enabled
} else if let channel = peer as? TelegramChannel {
switch channel.info {
case .group:
peerIsMuted = !globalNotificationSettings.groupChats.enabled
case .broadcast:
peerIsMuted = !globalNotificationSettings.channels.enabled
}
}
}
}
}
return peerIsMuted
}
var chatIsMuted = false
if let threadNotificationSettings {
if case .muted = threadNotificationSettings.muteState {
chatIsMuted = true
} else if let peerNotificationSettings {
chatIsMuted = isPeerMuted(peer: peer, peerNotificationSettings: peerNotificationSettings, globalNotificationSettings: globalNotificationSettings)
}
} else {
chatIsMuted = isPeerMuted(peer: peer, peerNotificationSettings: peerNotificationSettings, globalNotificationSettings: globalNotificationSettings)
}
return chatIsMuted
}

View File

@ -2542,7 +2542,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private var currentCredibilityIcon: CredibilityIcon?
private var currentPanelStatusData: PeerInfoStatusData?
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, notificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
self.state = state
self.peer = peer
self.threadData = threadData
@ -3456,28 +3456,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
}
buttonIcon = .voiceChat
case .mute:
var peerIsMuted = false
if let notificationSettings {
if case .muted = notificationSettings.muteState {
peerIsMuted = true
} else if case .default = notificationSettings.muteState, let globalNotificationSettings {
if let peer {
if peer is TelegramUser {
peerIsMuted = !globalNotificationSettings.privateChats.enabled
} else if peer is TelegramGroup {
peerIsMuted = !globalNotificationSettings.groupChats.enabled
} else if let channel = peer as? TelegramChannel {
switch channel.info {
case .group:
peerIsMuted = !globalNotificationSettings.groupChats.enabled
case .broadcast:
peerIsMuted = !globalNotificationSettings.channels.enabled
}
}
}
}
}
if peerIsMuted {
let chatIsMuted = peerInfoIsChatMuted(peer: peer, peerNotificationSettings: peerNotificationSettings, threadNotificationSettings: threadNotificationSettings, globalNotificationSettings: globalNotificationSettings)
if chatIsMuted {
buttonText = presentationData.strings.PeerInfo_ButtonUnmute
buttonIcon = .unmute
} else {

View File

@ -3053,7 +3053,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(threadId: threadId, threadInfo: threadData.info, isHidden: threadData.isHidden))
controller.navigationPresentation = .modal
let context = strongSelf.context
controller.completion = { [weak controller] title, fileId, isHidden in
controller.completion = { [weak controller] title, fileId, _, isHidden in
let _ = (context.engine.peers.editForumChannelTopic(id: peerId, threadId: threadId, title: title, iconFileId: fileId)
|> deliverOnMainQueue).start(completed: {
controller?.dismiss()
@ -4258,30 +4258,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self.requestCall(isVideo: false, gesture: gesture)
case .mute:
var displayCustomNotificationSettings = false
var peerIsMuted = false
if let notificationSettings = self.data?.notificationSettings {
if case .muted = notificationSettings.muteState {
peerIsMuted = true
} else if case .default = notificationSettings.muteState, let globalNotificationSettings = self.data?.globalNotificationSettings {
if let peer = self.data?.peer {
if peer is TelegramUser {
peerIsMuted = !globalNotificationSettings.privateChats.enabled
} else if peer is TelegramGroup {
peerIsMuted = !globalNotificationSettings.groupChats.enabled
} else if let channel = peer as? TelegramChannel {
switch channel.info {
case .group:
peerIsMuted = !globalNotificationSettings.groupChats.enabled
case .broadcast:
peerIsMuted = !globalNotificationSettings.channels.enabled
}
}
}
}
}
if peerIsMuted {
let chatIsMuted = peerInfoIsChatMuted(peer: self.data?.peer, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings)
if chatIsMuted {
} else {
displayCustomNotificationSettings = true
}
@ -4358,7 +4337,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
items.append(.separator)
var isSoundEnabled = true
if let notificationSettings = self.data?.notificationSettings {
let notificationSettings = self.data?.threadNotificationSettings ?? self.data?.peerNotificationSettings
if let notificationSettings {
switch notificationSettings.messageSound {
case .none:
isSoundEnabled = false
@ -4367,53 +4347,34 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
}
if let notificationSettings = self.data?.notificationSettings, case .muted = notificationSettings.muteState {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
guard let self else {
return
}
let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: self.chatLocation.threadId, muteInterval: nil).start()
let iconColor: UIColor = .white
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: self.presentationData.strings.PeerInfo_TooltipUnmuted, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
} else if !isSoundEnabled {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_EnableSound, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .default).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
} else {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_DisableSound, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .none).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
if !chatIsMuted {
if !isSoundEnabled {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_EnableSound, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .default).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
} else {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_DisableSound, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .none).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
}
}
let context = self.context
@ -4503,26 +4464,49 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
})
})))
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor)
}, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: Int32.max).start()
let iconColor: UIColor = .white
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
if chatIsMuted {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
guard let self else {
return
}
let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: self.chatLocation.threadId, muteInterval: 0).start()
let iconColor: UIColor = .white
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: self.presentationData.strings.PeerInfo_TooltipUnmuted, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
} else {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor)
}, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: Int32.max).start()
let iconColor: UIColor = .white
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
}
var tip: ContextController.Tip?
tip = nil
@ -8687,7 +8671,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let headerInset = sectionInset
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive)
if !self.isSettings && !self.state.isEditing {
headerHeight += 71.0
}
@ -9052,7 +9036,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let headerInset = sectionInset
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive)
}
let paneAreaExpansionDistance: CGFloat = 32.0
@ -10261,7 +10245,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
}
let headerInset = sectionInset
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, notificationSettings: self.screenNode.data?.notificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false)
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, peerNotificationSettings: self.screenNode.data?.peerNotificationSettings, threadNotificationSettings: self.screenNode.data?.threadNotificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: false)
}
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height

View File

@ -60,7 +60,7 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem {
return MessageMediaPlaylistItemStableId(stableId: message.stableId)
}
var playbackData: SharedMediaPlaybackData? {
lazy var playbackData: SharedMediaPlaybackData? = {
if let file = extractFileMedia(self.message) {
let fileReference = FileMediaReference.message(message: MessageReference(self.message), media: file)
let source = SharedMediaPlaybackDataSource.telegramFile(reference: fileReference, isCopyProtected: self.message.isCopyProtected())
@ -93,9 +93,9 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem {
}
}
return nil
}
}()
var displayData: SharedMediaPlaybackDisplayData? {
lazy var displayData: SharedMediaPlaybackDisplayData? = {
if let file = extractFileMedia(self.message) {
let text = self.message.text
var entities: [MessageTextEntity] = []
@ -108,40 +108,42 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem {
for attribute in file.attributes {
switch attribute {
case let .Audio(isVoice, duration, title, performer, _):
if isVoice {
return SharedMediaPlaybackDisplayData.voice(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId])
} else {
var updatedTitle = title
let updatedPerformer = performer
if (title ?? "").isEmpty && (performer ?? "").isEmpty {
updatedTitle = file.fileName ?? ""
}
let albumArt: SharedMediaPlaybackAlbumArt?
if file.fileName?.lowercased().hasSuffix(".ogg") == true {
albumArt = nil
} else {
albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false))
}
return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: CGFloat(duration) > 10.0 * 60.0, caption: caption)
case let .Audio(isVoice, duration, title, performer, _):
let displayData: SharedMediaPlaybackDisplayData
if isVoice {
displayData = SharedMediaPlaybackDisplayData.voice(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId])
} else {
var updatedTitle = title
let updatedPerformer = performer
if (title ?? "").isEmpty && (performer ?? "").isEmpty {
updatedTitle = file.fileName ?? ""
}
case let .Video(_, _, flags):
if flags.contains(.instantRoundVideo) {
return SharedMediaPlaybackDisplayData.instantVideo(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId], timestamp: self.message.timestamp)
let albumArt: SharedMediaPlaybackAlbumArt?
if file.fileName?.lowercased().hasSuffix(".ogg") == true {
albumArt = nil
} else {
return nil
albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false))
}
default:
break
displayData = SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: CGFloat(duration) > 10.0 * 60.0, caption: caption)
}
return displayData
case let .Video(_, _, flags):
if flags.contains(.instantRoundVideo) {
return SharedMediaPlaybackDisplayData.instantVideo(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId], timestamp: self.message.timestamp)
} else {
return nil
}
default:
break
}
}
return SharedMediaPlaybackDisplayData.music(title: file.fileName ?? "", performer: self.message.effectiveAuthor?.debugDisplayTitle ?? "", albumArt: nil, long: false, caption: caption)
}
return nil
}
}()
}
private enum NavigatedMessageFromViewPosition {

View File

@ -249,9 +249,11 @@ private final class PrefetchManagerInnerImpl {
self.preloadGreetingStickerDisposable.set((self.preloadedGreetingStickerPromise.get()
|> mapToSignal { sticker -> Signal<Void, NoError> in
if let sticker = sticker {
let _ = freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: sticker)).start()
return chatMessageAnimationData(mediaBox: account.postbox.mediaBox, resource: sticker.resource, fitzModifier: nil, isVideo: sticker.isVideoSticker, width: 384, height: 384, synchronousLoad: false)
|> mapToSignal { _ -> Signal<Void, NoError> in
return freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: sticker))
|> map { _ -> Void in
return Void()
}
|> `catch` { _ -> Signal<Void, NoError> in
return .complete()
}
} else {

View File

@ -295,7 +295,7 @@ public final class WebSearchController: ViewController {
let throttledSearchQuery = self.searchQueryPromise.get()
|> mapToSignal { query -> Signal<String, NoError> in
if !query.isEmpty {
return (.complete() |> delay(0.6, queue: Queue.mainQueue()))
return (.complete() |> delay(1.0, queue: Queue.mainQueue()))
|> then(.single(query))
} else {
return .single(query)

View File

@ -61,7 +61,7 @@
_dimensions = CGSizeMake(width, height);
if ((_frameRate > 60) || _animation->duration() > 7.0) {
if ((_frameRate > 60) || _animation->duration() > 9.0) {
return nil;
}
}