mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Cherry-pick more fixes
This commit is contained in:
parent
c92a855083
commit
158f92cf4e
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)"
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)";
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(", ")
|
||||
}
|
||||
|
@ -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(", ")
|
||||
}
|
||||
|
@ -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)
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
_dimensions = CGSizeMake(width, height);
|
||||
|
||||
if ((_frameRate > 60) || _animation->duration() > 7.0) {
|
||||
if ((_frameRate > 60) || _animation->duration() > 9.0) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user