Various improvements

This commit is contained in:
Ilya Laktyushin 2024-09-01 10:32:03 +04:00
parent 707d5137ca
commit d761d9314c
13 changed files with 381 additions and 79 deletions

View File

@ -12880,3 +12880,6 @@ Sorry for the inconvenience.";
"BoostGift.PrepaidGiveawayStarsCount_1" = "%@ Telegram Premium";
"BoostGift.PrepaidGiveawayStarsCount_any" = "%@ Telegram Premium";
"BoostGift.PrepaidGiveawayStarsMonths" = "%@-month subscriptions";
"WebBrowser.ShowInstantView" = "Show Instant View";
"WebBrowser.HideInstantView" = "Hide Instant View";

View File

@ -1175,12 +1175,12 @@ public class BrowserScreen: ViewController, MinimizableController {
if case .webPage = contentState.contentType {
let isAvailable = contentState.hasInstantView
items.append(.action(ContextMenuActionItem(text: "Show Instant View", textColor: isAvailable ? .primary : .disabled, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Boost"), color: isAvailable ? theme.contextMenu.primaryColor : theme.contextMenu.primaryColor.withAlphaComponent(0.3)) }, action: isAvailable ? { (controller, action) in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.WebBrowser_ShowInstantView, textColor: isAvailable ? .primary : .disabled, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Boost"), color: isAvailable ? theme.contextMenu.primaryColor : theme.contextMenu.primaryColor.withAlphaComponent(0.3)) }, action: isAvailable ? { (controller, action) in
performAction.invoke(.toggleInstantView(true))
action(.default)
} : nil)))
} else if case .instantPage = contentState.contentType, contentState.isInnerInstantViewEnabled {
items.append(.action(ContextMenuActionItem(text: "Hide Instant View", textColor: .primary, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Boost"), color: theme.contextMenu.primaryColor) }, action: { (controller, action) in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.WebBrowser_HideInstantView, textColor: .primary, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Instant View/InstantViewOff"), color: theme.contextMenu.primaryColor) }, action: { (controller, action) in
performAction.invoke(.toggleInstantView(false))
action(.default)
})))

View File

@ -93,17 +93,13 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.stringsPromise.set(.single(self.presentationData.strings))
var addNearbyImpl: (() -> Void)?
var inviteImpl: (() -> Void)?
let presentation = combineLatest(sortOrder, self.stringsPromise.get())
|> map { sortOrder, strings -> ContactListPresentation in
let options = [ContactListAdditionalOption(title: strings.Contacts_AddPeopleNearby, icon: .generic(UIImage(bundleImageName: "Contact List/PeopleNearbyIcon")!), action: {
addNearbyImpl?()
}), ContactListAdditionalOption(title: strings.Contacts_InviteFriends, icon: .generic(UIImage(bundleImageName: "Contact List/AddMemberIcon")!), action: {
let options = [ContactListAdditionalOption(title: strings.Contacts_InviteFriends, icon: .generic(UIImage(bundleImageName: "Contact List/AddMemberIcon")!), action: {
inviteImpl?()
})]
switch sortOrder {
case .presence:
return .orderedByPresence(options: options)
@ -145,13 +141,7 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
}
}
}).strict()
addNearbyImpl = { [weak self] in
if let strongSelf = self {
strongSelf.openPeopleNearby?()
}
}
inviteImpl = { [weak self] in
if let strongSelf = self {
strongSelf.openInvite?()

View File

@ -471,7 +471,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
default:
color = .blue
}
case let .stars(amount):
case let .stars(amount, _):
if amount <= 1000 {
color = .green
} else if amount < 2500 {
@ -777,7 +777,7 @@ private func createGiveawayControllerEntries(
case let .premium(months):
title = presentationData.strings.BoostGift_PrepaidGiveawayCount(prepaidGiveaway.quantity)
text = presentationData.strings.BoostGift_PrepaidGiveawayMonths("\(months)").string
case let .stars(stars):
case let .stars(stars, _):
//TODO:localize
title = "\(stars) Telegram Stars"
text = "among \(prepaidGiveaway.quantity) winners"
@ -1013,7 +1013,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
let initialStars: Int64
let initialWinners: Int32
if case let .prepaid(prepaidGiveaway) = subject {
if case let .stars(stars) = prepaidGiveaway.prize {
if case let .stars(stars, _) = prepaidGiveaway.prize {
initialStars = stars
} else {
initialStars = 500

View File

@ -1050,7 +1050,7 @@ private enum StatsEntry: ItemListNodeEntry {
default:
color = .blue
}
case let .stars(amount):
case let .stars(amount, _):
if amount <= 1000 {
color = .green
} else if amount < 2500 {
@ -1440,7 +1440,7 @@ private func boostsEntries(
case let .premium(months):
title = presentationData.strings.Stats_Boosts_PrepaidGiveawayCount(giveaway.quantity)
text = presentationData.strings.Stats_Boosts_PrepaidGiveawayMonths("\(months)").string
case let .stars(stars):
case let .stars(stars, _):
title = "\(stars) Telegram Stars"
text = "among \(giveaway.quantity) winners"
}

View File

@ -746,7 +746,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1958953753] = { return Api.PremiumGiftOption.parse_premiumGiftOption($0) }
dict[1596792306] = { return Api.PremiumSubscriptionOption.parse_premiumSubscriptionOption($0) }
dict[-1303143084] = { return Api.PrepaidGiveaway.parse_prepaidGiveaway($0) }
dict[-1973402371] = { return Api.PrepaidGiveaway.parse_prepaidStarsGiveaway($0) }
dict[-1700956192] = { return Api.PrepaidGiveaway.parse_prepaidStarsGiveaway($0) }
dict[-1534675103] = { return Api.PrivacyKey.parse_privacyKeyAbout($0) }
dict[1124062251] = { return Api.PrivacyKey.parse_privacyKeyAddedByPhone($0) }
dict[536913176] = { return Api.PrivacyKey.parse_privacyKeyBirthday($0) }

View File

@ -1013,7 +1013,7 @@ public extension Api {
public extension Api {
enum PrepaidGiveaway: TypeConstructorDescription {
case prepaidGiveaway(id: Int64, months: Int32, quantity: Int32, date: Int32)
case prepaidStarsGiveaway(id: Int64, stars: Int64, quantity: Int32, date: Int32)
case prepaidStarsGiveaway(id: Int64, stars: Int64, quantity: Int32, boosts: Int32, date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -1026,13 +1026,14 @@ public extension Api {
serializeInt32(quantity, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
case .prepaidStarsGiveaway(let id, let stars, let quantity, let date):
case .prepaidStarsGiveaway(let id, let stars, let quantity, let boosts, let date):
if boxed {
buffer.appendInt32(-1973402371)
buffer.appendInt32(-1700956192)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(stars, buffer: buffer, boxed: false)
serializeInt32(quantity, buffer: buffer, boxed: false)
serializeInt32(boosts, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
}
@ -1042,8 +1043,8 @@ public extension Api {
switch self {
case .prepaidGiveaway(let id, let months, let quantity, let date):
return ("prepaidGiveaway", [("id", id as Any), ("months", months as Any), ("quantity", quantity as Any), ("date", date as Any)])
case .prepaidStarsGiveaway(let id, let stars, let quantity, let date):
return ("prepaidStarsGiveaway", [("id", id as Any), ("stars", stars as Any), ("quantity", quantity as Any), ("date", date as Any)])
case .prepaidStarsGiveaway(let id, let stars, let quantity, let boosts, let date):
return ("prepaidStarsGiveaway", [("id", id as Any), ("stars", stars as Any), ("quantity", quantity as Any), ("boosts", boosts as Any), ("date", date as Any)])
}
}
@ -1076,12 +1077,15 @@ public extension Api {
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PrepaidGiveaway.prepaidStarsGiveaway(id: _1!, stars: _2!, quantity: _3!, date: _4!)
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.PrepaidGiveaway.prepaidStarsGiveaway(id: _1!, stars: _2!, quantity: _3!, boosts: _4!, date: _5!)
}
else {
return nil

View File

@ -91,7 +91,7 @@ public enum PremiumGiveawayInfo: Equatable {
public struct PrepaidGiveaway: Equatable {
public enum Prize: Equatable {
case premium(months: Int32)
case stars(stars: Int64)
case stars(stars: Int64, boosts: Int32)
}
public let id: Int64
@ -312,9 +312,9 @@ extension PrepaidGiveaway {
self.prize = .premium(months: months)
self.quantity = quantity
self.date = date
case let .prepaidStarsGiveaway(id, stars, quantity, date):
case let .prepaidStarsGiveaway(id, stars, quantity, boosts, date):
self.id = id
self.prize = .stars(stars: stars)
self.prize = .stars(stars: stars, boosts: boosts)
self.quantity = quantity
self.date = date
}

View File

@ -551,7 +551,7 @@ public final class ChatMessageAvatarHeaderNodeImpl: ListViewItemHeaderNode, Chat
}
public func setPeer(context: AccountContext, theme: PresentationTheme, synchronousLoad: Bool, peer: Peer, authorOfMessage: MessageReference?, emptyColor: UIColor) {
self.containerNode.isGestureEnabled = peer.smallProfileImage != nil
self.containerNode.isGestureEnabled = true
var overrideImage: AvatarNodeImageOverride?
if peer.isDeleted {

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "boostoff_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -306,11 +306,7 @@ public final class AccountContextImpl: AccountContext {
self.account.stateManager.starsContext = self.starsContext
if let locationManager = self.sharedContextImpl.locationManager, sharedContext.applicationBindings.isMainApp && !temp {
self.peersNearbyManager = PeersNearbyManagerImpl(account: account, engine: self.engine, locationManager: locationManager, inForeground: sharedContext.applicationBindings.applicationInForeground)
} else {
self.peersNearbyManager = nil
}
self.peersNearbyManager = nil
self.cachedGroupCallContexts = AccountGroupCallContextCacheImpl()

View File

@ -129,6 +129,7 @@ import PhoneNumberFormat
import OwnershipTransferController
import OldChannelsController
import BrowserUI
import NotificationPeerExceptionController
public enum ChatControllerPeekActions {
case standard
@ -3617,13 +3618,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let _ = (dataSignal
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer, message in
guard let strongSelf = self, let peer = peer, peer.smallProfileImage != nil else {
guard let strongSelf = self, let peer = peer else {
return
}
let galleryController = AvatarGalleryController(context: context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in
}, synchronousLoad: true)
galleryController.setHintWillBePresentedInPreviewingContext(true)
var isChannel = false
if case let .channel(peer) = peer, case .broadcast = peer.info {
@ -3681,7 +3678,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.canReadHistory.set(false)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ChatContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let source: ContextContentSource
if let _ = peer.smallProfileImage {
let galleryController = AvatarGalleryController(context: context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in
}, synchronousLoad: true)
galleryController.setHintWillBePresentedInPreviewingContext(true)
source = .controller(ChatContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false))
} else {
source = .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceView: node.view, insets: .zero))
}
let contextController = ContextController(presentationData: strongSelf.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
contextController.dismissed = { [weak self] in
self?.canReadHistory.set(true)
}
@ -4655,58 +4662,347 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .peer, .replyThread:
let avatarNode = ChatAvatarNavigationNode()
avatarNode.contextAction = { [weak self] node, gesture in
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil else {
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer else {
return
}
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: EnginePeer(peer), remoteEntries: nil, replaceRootController: { controller, ready in
}, synchronousLoad: true)
galleryController.setHintWillBePresentedInPreviewingContext(true)
let items: Signal<[ContextMenuItem], NoError> = context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: peer.id)
)
|> map { canViewStats -> [ContextMenuItem] in
var items: [ContextMenuItem] = [
.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, icon: { theme in
let items: Signal<[ContextMenuItem], NoError>
switch chatLocation {
case .peer:
items = context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: peer.id)
)
|> map { canViewStats -> [ContextMenuItem] in
var items: [ContextMenuItem] = []
let openText = strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile
items.append(.action(ContextMenuActionItem(text: openText, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
self?.navigationButtonAction(.openChatInfo(expandAvatar: true, recommendedChannels: false))
}))
]
if canViewStats {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChannelInfo_Stats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.actionSheet.primaryTextColor)
})))
if canViewStats {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChannelInfo_Stats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer else {
return
}
strongSelf.view.endEditing(true)
let statsController: ViewController
if let channel = peer as? TelegramChannel, case .group = channel.info {
statsController = groupStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id)
} else {
statsController = channelStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id)
}
strongSelf.push(statsController)
})))
}
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_Search, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer else {
return
}
strongSelf.view.endEditing(true)
let statsController: ViewController
if let channel = peer as? TelegramChannel, case .group = channel.info {
statsController = groupStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id)
} else {
statsController = channelStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id)
}
strongSelf.push(statsController)
self?.interfaceInteraction?.beginMessageSearch(.everything, "")
})))
return items
}
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_Search, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
self?.interfaceInteraction?.beginMessageSearch(.everything, "")
})))
return items
case let .replyThread(message):
let peerId = peer.id
let threadId = message.threadId
items = context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peerId),
TelegramEngine.EngineData.Item.Peer.ThreadData(id: peer.id, threadId: threadId),
TelegramEngine.EngineData.Item.NotificationSettings.Global()
)
|> map { peerNotificationSettings, threadData, globalNotificationSettings -> [ContextMenuItem] in
guard let channel = peer as? TelegramChannel else {
return []
}
guard let threadData = threadData else {
return []
}
var items: [ContextMenuItem] = []
var isMuted = false
switch threadData.notificationSettings.muteState {
case .muted:
isMuted = true
case .unmuted:
isMuted = false
case .default:
var peerIsMuted = false
if case let .muted(until) = peerNotificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
peerIsMuted = true
} else if case .default = peerNotificationSettings.muteState {
if case .group = channel.info {
peerIsMuted = !globalNotificationSettings.groupChats.enabled
}
}
isMuted = peerIsMuted
}
items.append(.action(ContextMenuActionItem(text: isMuted ? presentationData.strings.ChatList_Context_Unmute : presentationData.strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
if isMuted {
let _ = (context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: 0)
|> deliverOnMainQueue).startStandalone(completed: {
f(.default)
})
} else {
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteFor, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Mute2d"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
var subItems: [ContextMenuItem] = []
let presetValues: [Int32] = [
1 * 60 * 60,
8 * 60 * 60,
1 * 24 * 60 * 60,
7 * 24 * 60 * 60
]
for value in presetValues {
subItems.append(.action(ContextMenuActionItem(text: muteForIntervalString(strings: presentationData.strings, value: value), icon: { _ in
return nil
}, action: { _, f in
f(.default)
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: value).startStandalone()
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedFor(mutedForTimeIntervalString(strings: presentationData.strings, value: value)).string, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
}
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteForCustom, icon: { _ in
return nil
}, action: { _, f in
f(.default)
// if let chatListController = chatListController {
// openCustomMute(context: context, peerId: peerId, threadId: threadId, baseController: chatListController)
// }
})))
c?.setItems(.single(ContextController.Items(content: .list(subItems))), minHeight: nil, animated: true)
})))
items.append(.separator)
var isSoundEnabled = true
switch threadData.notificationSettings.messageSound {
case .none:
isSoundEnabled = false
default:
break
}
if case .muted = threadData.notificationSettings.muteState {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: nil).startStandalone()
let iconColor: UIColor = .white
self?.present(UndoOverlayController(presentationData: 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: 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: presentationData.strings.PeerInfo_EnableSound, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
let _ = context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: .default).startStandalone()
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
} else {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_DisableSound, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
let _ = context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: .none).startStandalone()
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_NotificationsCustomize, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.dismissWithoutContent)
let _ = (context.engine.data.get(
TelegramEngine.EngineData.Item.NotificationSettings.Global()
)
|> deliverOnMainQueue).startStandalone(next: { globalSettings in
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: sound) |> deliverOnMainQueue
}
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: muteInterval) |> deliverOnMainQueue
}
let updatePeerDisplayPreviews: (PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
peerId, displayPreviews in
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue
}
let updatePeerStoriesMuted: (PeerId, PeerStoryNotificationSettings.Mute) -> Signal<Void, NoError> = {
peerId, mute in
return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue
}
let updatePeerStoriesHideSender: (PeerId, PeerStoryNotificationSettings.HideSender) -> Signal<Void, NoError> = {
peerId, hideSender in
return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue
}
let updatePeerStorySound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
}
let defaultSound: PeerMessageSound
if case .broadcast = channel.info {
defaultSound = globalSettings.channels.sound._asMessageSound()
} else {
defaultSound = globalSettings.groupChats.sound._asMessageSound()
}
let canRemove = false
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: nil, peer: .channel(channel), threadId: threadId, isStories: nil, canRemove: canRemove, defaultSound: defaultSound, defaultStoriesSound: defaultSound, edit: true, updatePeerSound: { peerId, sound in
let _ = (updatePeerSound(peerId, sound)
|> deliverOnMainQueue).startStandalone(next: { _ in
})
}, updatePeerNotificationInterval: { [weak self] peerId, muteInterval in
let _ = (updatePeerNotificationInterval(peerId, muteInterval)
|> deliverOnMainQueue).startStandalone(next: { _ in
if let muteInterval = muteInterval, muteInterval == Int32.max {
let iconColor: UIColor = .white
self?.present(UndoOverlayController(presentationData: 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: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
}
})
}, updatePeerDisplayPreviews: { peerId, displayPreviews in
let _ = (updatePeerDisplayPreviews(peerId, displayPreviews)
|> deliverOnMainQueue).startStandalone(next: { _ in
})
}, updatePeerStoriesMuted: { peerId, mute in
let _ = (updatePeerStoriesMuted(peerId, mute)
|> deliverOnMainQueue).startStandalone()
}, updatePeerStoriesHideSender: { peerId, hideSender in
let _ = (updatePeerStoriesHideSender(peerId, hideSender)
|> deliverOnMainQueue).startStandalone()
}, updatePeerStorySound: { peerId, sound in
let _ = (updatePeerStorySound(peerId, sound)
|> deliverOnMainQueue).startStandalone()
}, removePeerFromExceptions: {
}, modifiedPeer: {
})
exceptionController.navigationPresentation = .modal
self?.push(exceptionController)
})
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor)
}, action: { _, f in
f(.default)
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: Int32.max).startStandalone()
let iconColor: UIColor = .white
self?.present(UndoOverlayController(presentationData: 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: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
c?.setItems(.single(ContextController.Items(content: .list(items))), minHeight: nil, animated: true)
}
})))
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_Search, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
self?.interfaceInteraction?.beginMessageSearch(.everything, "")
})))
if threadId != 1 {
var canOpenClose = false
if channel.flags.contains(.isCreator) {
canOpenClose = true
} else if channel.hasPermission(.manageTopics) {
canOpenClose = true
} else if threadData.isOwnedByMe {
canOpenClose = true
}
if canOpenClose {
items.append(.action(ContextMenuActionItem(text: threadData.isClosed ? presentationData.strings.ChatList_Context_ReopenTopic : presentationData.strings.ChatList_Context_CloseTopic, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: threadData.isClosed ? "Chat/Context Menu/Play": "Chat/Context Menu/Pause"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let _ = context.engine.peers.setForumChannelTopicClosed(id: peer.id, threadId: threadId, isClosed: !threadData.isClosed).startStandalone()
})))
}
// if channel.hasPermission(.deleteAllMessages) {
// items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak chatListController] _, f in
// f(.default)
//
// chatListController?.deletePeerThread(peerId: peerId, threadId: threadId)
// })))
// }
}
return items
}
default:
items = .single([])
}
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
strongSelf.canReadHistory.set(false)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ChatContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let source: ContextContentSource
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil {
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: EnginePeer(peer), remoteEntries: nil, replaceRootController: { controller, ready in
}, synchronousLoad: true)
galleryController.setHintWillBePresentedInPreviewingContext(true)
source = .controller(ChatContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false))
} else {
source = .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceView: node.view, insets: .zero))
}
let contextController = ContextController(presentationData: strongSelf.presentationData, source: source, items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
contextController.dismissed = { [weak self] in
self?.canReadHistory.set(true)
}
@ -5123,7 +5419,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
imageOverride = nil
}
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: EnginePeer(peer), overrideImage: imageOverride)
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.contextActionIsEnabled = strongSelf.chatLocation.threadId == nil && peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.contextActionIsEnabled = peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil
strongSelf.chatInfoNavigationButton?.buttonItem.accessibilityLabel = presentationInterfaceState.strings.Conversation_ContextMenuOpenProfile
strongSelf.storyStats = peerView.storyStats
@ -5660,7 +5956,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
} else if case let .replyThread(messagePromise) = self.chatLocationInfoData, let peerId = peerId {
self.reportIrrelvantGeoNoticePromise.set(.single(nil))
let replyThreadType: ChatTitleContent.ReplyThreadType
var replyThreadId: Int64?
switch chatLocation {
@ -6013,6 +6309,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if strongSelf.isNodeLoaded {
strongSelf.chatDisplayNode.overlayTitle = strongSelf.overlayTitle
}
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.contextActionIsEnabled = true
var peerDiscussionId: PeerId?
var peerGeoLocation: PeerGeoLocation?