mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Merge commit '3f13dea5daa9e27a5e17210235d8ac87004de3fd' into experimental-3
This commit is contained in:
commit
d9061b0771
@ -8648,16 +8648,17 @@ Sorry for the inconvenience.";
|
|||||||
"RequestPeer.Requirement.Group.HasUsernameOff" = "The group should be private.";
|
"RequestPeer.Requirement.Group.HasUsernameOff" = "The group should be private.";
|
||||||
"RequestPeer.Requirement.Group.HasUsernameOn" = "The group should be public.";
|
"RequestPeer.Requirement.Group.HasUsernameOn" = "The group should be public.";
|
||||||
|
|
||||||
"RequestPeer.Requirement.Group.ForumOff" = "The group should have topics off.";
|
"RequestPeer.Requirement.Group.ForumOff" = "The group should have topics turned off.";
|
||||||
"RequestPeer.Requirement.Group.ForumOn" = "The group should have topics on.";
|
"RequestPeer.Requirement.Group.ForumOn" = "The group should have topics turned on.";
|
||||||
|
|
||||||
|
"RequestPeer.Requirement.Group.ParticipantOn" = "Bot should be in the group.";
|
||||||
"RequestPeer.Requirement.Group.CreatorOn" = "You should be the owner of the group.";
|
"RequestPeer.Requirement.Group.CreatorOn" = "You should be the owner of the group.";
|
||||||
|
|
||||||
"RequestPeer.Requirement.Group.Rights" = "You have the admin rights to %@.";
|
"RequestPeer.Requirement.Group.Rights" = "You have the admin rights to %@.";
|
||||||
"RequestPeer.Requirement.Group.Rights.Info" = "change group info";
|
"RequestPeer.Requirement.Group.Rights.Info" = "change group info";
|
||||||
"RequestPeer.Requirement.Group.Rights.Send" = "post messages";
|
"RequestPeer.Requirement.Group.Rights.Send" = "post messages";
|
||||||
"RequestPeer.Requirement.Group.Rights.Delete" = "delete messages";
|
"RequestPeer.Requirement.Group.Rights.Delete" = "delete messages";
|
||||||
"RequestPeer.Requirement.Group.Rights.Edit" = "delete messages";
|
"RequestPeer.Requirement.Group.Rights.Edit" = "edit messages";
|
||||||
"RequestPeer.Requirement.Group.Rights.Ban" = "ban users";
|
"RequestPeer.Requirement.Group.Rights.Ban" = "ban users";
|
||||||
"RequestPeer.Requirement.Group.Rights.Invite" = "invite users via link";
|
"RequestPeer.Requirement.Group.Rights.Invite" = "invite users via link";
|
||||||
"RequestPeer.Requirement.Group.Rights.Pin" = "pin messages";
|
"RequestPeer.Requirement.Group.Rights.Pin" = "pin messages";
|
||||||
@ -8672,10 +8673,10 @@ Sorry for the inconvenience.";
|
|||||||
"RequestPeer.Requirement.Channel.CreatorOn" = "You should be the owner of the channel.";
|
"RequestPeer.Requirement.Channel.CreatorOn" = "You should be the owner of the channel.";
|
||||||
|
|
||||||
"RequestPeer.Requirement.Channel.Rights" = "You have the admin rights to %@.";
|
"RequestPeer.Requirement.Channel.Rights" = "You have the admin rights to %@.";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Info" = "change group info";
|
"RequestPeer.Requirement.Channel.Rights.Info" = "change channel info";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Send" = "post messages";
|
"RequestPeer.Requirement.Channel.Rights.Send" = "post messages";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Delete" = "delete messages";
|
"RequestPeer.Requirement.Channel.Rights.Delete" = "delete messages";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Edit" = "delete messages";
|
"RequestPeer.Requirement.Channel.Rights.Edit" = "edit messages";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Ban" = "ban users";
|
"RequestPeer.Requirement.Channel.Rights.Ban" = "ban users";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Invite" = "invite users via link";
|
"RequestPeer.Requirement.Channel.Rights.Invite" = "invite users via link";
|
||||||
"RequestPeer.Requirement.Channel.Rights.Pin" = "pin messages";
|
"RequestPeer.Requirement.Channel.Rights.Pin" = "pin messages";
|
||||||
@ -8697,7 +8698,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Conversation.ViewInChannel" = "View in Channel";
|
"Conversation.ViewInChannel" = "View in Channel";
|
||||||
|
|
||||||
|
|
||||||
"Conversation.HoldForAudioOnly" = "Hold to record audio.";
|
"Conversation.HoldForAudioOnly" = "Hold to record audio.";
|
||||||
"Conversation.HoldForVideoOnly" = "Hold to record video.";
|
"Conversation.HoldForVideoOnly" = "Hold to record video.";
|
||||||
"Conversation.Translation.TranslateTo" = "Translate to %@";
|
"Conversation.Translation.TranslateTo" = "Translate to %@";
|
||||||
@ -8708,13 +8708,17 @@ Sorry for the inconvenience.";
|
|||||||
"Conversation.Translation.AddedToDoNotTranslateText" = "**%@** is added to the Do Not Translate list.";
|
"Conversation.Translation.AddedToDoNotTranslateText" = "**%@** is added to the Do Not Translate list.";
|
||||||
"Conversation.Translation.TranslationBarHiddenText" = "Translation bar is now hidden for this channel.";
|
"Conversation.Translation.TranslationBarHiddenText" = "Translation bar is now hidden for this channel.";
|
||||||
|
|
||||||
|
"ProfilePhoto.SetEmoji" = "Set Emoji";
|
||||||
|
|
||||||
"AvatarEditor.Background" = "BACKGROUND";
|
"AvatarEditor.Background" = "BACKGROUND";
|
||||||
"AvatarEditor.EmojiOrSticker" = "EMOJI OR STICKER";
|
"AvatarEditor.EmojiOrSticker" = "EMOJI OR STICKER";
|
||||||
"AvatarEditor.Emoji" = "EMOJI";
|
"AvatarEditor.Emoji" = "Emoji";
|
||||||
"AvatarEditor.Stickers" = "STICKERS";
|
"AvatarEditor.Stickers" = "Stickers";
|
||||||
"AvatarEditor.SwitchToEmoji" = "SWITCH TO EMOJI";
|
"AvatarEditor.SwitchToEmoji" = "SWITCH TO EMOJI";
|
||||||
"AvatarEditor.SwitchToStickers" = "SWITCH TO STICKERS";
|
"AvatarEditor.SwitchToStickers" = "SWITCH TO STICKERS";
|
||||||
|
|
||||||
"AvatarEditor.SetVideo" = "Set Video";
|
"AvatarEditor.SetProfilePhoto" = "Set as Profile Photo";
|
||||||
|
"AvatarEditor.SetGroupPhoto" = "Set as Group Photo";
|
||||||
|
"AvatarEditor.SetChannelPhoto" = "Set as Group Photo";
|
||||||
|
|
||||||
"AvatarEditor.Set" = "Set";
|
"AvatarEditor.Set" = "Set";
|
||||||
|
@ -194,7 +194,7 @@
|
|||||||
[itemViews addObject:galleryItem];
|
[itemViews addObject:galleryItem];
|
||||||
|
|
||||||
if (!_signup) {
|
if (!_signup) {
|
||||||
TGMenuSheetButtonItemView *viewItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:@"Emoji or Sticker" type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^
|
TGMenuSheetButtonItemView *viewItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"ProfilePhoto.SetEmoji") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^
|
||||||
{
|
{
|
||||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||||
if (strongSelf == nil)
|
if (strongSelf == nil)
|
||||||
|
@ -23,6 +23,7 @@ struct ParsedDialogs {
|
|||||||
let topMessageIds: [PeerId: MessageId]
|
let topMessageIds: [PeerId: MessageId]
|
||||||
let storeMessages: [StoreMessage]
|
let storeMessages: [StoreMessage]
|
||||||
let ttlPeriods: [PeerId: CachedPeerAutoremoveTimeout]
|
let ttlPeriods: [PeerId: CachedPeerAutoremoveTimeout]
|
||||||
|
let hiddenTranslations: [PeerId: Bool]
|
||||||
|
|
||||||
let lowerNonPinnedIndex: MessageIndex?
|
let lowerNonPinnedIndex: MessageIndex?
|
||||||
let referencedFolders: [PeerGroupId: PeerGroupUnreadCountersSummary]
|
let referencedFolders: [PeerGroupId: PeerGroupUnreadCountersSummary]
|
||||||
@ -55,6 +56,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
|
|||||||
var channelStates: [PeerId: Int32] = [:]
|
var channelStates: [PeerId: Int32] = [:]
|
||||||
var topMessageIds: [PeerId: MessageId] = [:]
|
var topMessageIds: [PeerId: MessageId] = [:]
|
||||||
var ttlPeriods: [PeerId: CachedPeerAutoremoveTimeout] = [:]
|
var ttlPeriods: [PeerId: CachedPeerAutoremoveTimeout] = [:]
|
||||||
|
var hiddenTranslations: [PeerId: Bool] = [:]
|
||||||
|
|
||||||
var storeMessages: [StoreMessage] = []
|
var storeMessages: [StoreMessage] = []
|
||||||
var nonPinnedDialogsTopMessageIds = Set<MessageId>()
|
var nonPinnedDialogsTopMessageIds = Set<MessageId>()
|
||||||
@ -112,6 +114,10 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
|
|||||||
|
|
||||||
ttlPeriods[peer.peerId] = .known(ttlPeriod.flatMap(CachedPeerAutoremoveTimeout.Value.init(peerValue:)))
|
ttlPeriods[peer.peerId] = .known(ttlPeriod.flatMap(CachedPeerAutoremoveTimeout.Value.init(peerValue:)))
|
||||||
|
|
||||||
|
if (flags & (1 << 6)) != 0 {
|
||||||
|
hiddenTranslations[peer.peerId] = true
|
||||||
|
}
|
||||||
|
|
||||||
let isPinned = (flags & (1 << 2)) != 0
|
let isPinned = (flags & (1 << 2)) != 0
|
||||||
if !isPinned {
|
if !isPinned {
|
||||||
nonPinnedDialogsTopMessageIds.insert(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: topMessage))
|
nonPinnedDialogsTopMessageIds.insert(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: topMessage))
|
||||||
@ -190,6 +196,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
|
|||||||
topMessageIds: topMessageIds,
|
topMessageIds: topMessageIds,
|
||||||
storeMessages: storeMessages,
|
storeMessages: storeMessages,
|
||||||
ttlPeriods: ttlPeriods,
|
ttlPeriods: ttlPeriods,
|
||||||
|
hiddenTranslations: hiddenTranslations,
|
||||||
|
|
||||||
lowerNonPinnedIndex: lowerNonPinnedIndex,
|
lowerNonPinnedIndex: lowerNonPinnedIndex,
|
||||||
referencedFolders: referencedFolders
|
referencedFolders: referencedFolders
|
||||||
@ -208,6 +215,7 @@ struct FetchedChatList {
|
|||||||
var channelStates: [PeerId: Int32]
|
var channelStates: [PeerId: Int32]
|
||||||
var storeMessages: [StoreMessage]
|
var storeMessages: [StoreMessage]
|
||||||
var topMessageIds: [PeerId: MessageId]
|
var topMessageIds: [PeerId: MessageId]
|
||||||
|
var hiddenTranslations: [PeerId: Bool]
|
||||||
|
|
||||||
var lowerNonPinnedIndex: MessageIndex?
|
var lowerNonPinnedIndex: MessageIndex?
|
||||||
|
|
||||||
@ -316,6 +324,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
|||||||
var channelStates: [PeerId: Int32] = [:]
|
var channelStates: [PeerId: Int32] = [:]
|
||||||
var storeMessages: [StoreMessage] = []
|
var storeMessages: [StoreMessage] = []
|
||||||
var topMessageIds: [PeerId: MessageId] = [:]
|
var topMessageIds: [PeerId: MessageId] = [:]
|
||||||
|
var hiddenTranslations: [PeerId: Bool] = [:]
|
||||||
|
|
||||||
peers.append(contentsOf: parsedRemoteChats.peers)
|
peers.append(contentsOf: parsedRemoteChats.peers)
|
||||||
peerPresences.merge(parsedRemoteChats.peerPresences, uniquingKeysWith: { _, updated in updated })
|
peerPresences.merge(parsedRemoteChats.peerPresences, uniquingKeysWith: { _, updated in updated })
|
||||||
@ -327,6 +336,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
|||||||
channelStates.merge(parsedRemoteChats.channelStates, uniquingKeysWith: { _, updated in updated })
|
channelStates.merge(parsedRemoteChats.channelStates, uniquingKeysWith: { _, updated in updated })
|
||||||
storeMessages.append(contentsOf: parsedRemoteChats.storeMessages)
|
storeMessages.append(contentsOf: parsedRemoteChats.storeMessages)
|
||||||
topMessageIds.merge(parsedRemoteChats.topMessageIds, uniquingKeysWith: { _, updated in updated })
|
topMessageIds.merge(parsedRemoteChats.topMessageIds, uniquingKeysWith: { _, updated in updated })
|
||||||
|
hiddenTranslations.merge(parsedRemoteChats.hiddenTranslations, uniquingKeysWith: { _, updated in updated })
|
||||||
|
|
||||||
if let parsedPinnedChats = parsedPinnedChats {
|
if let parsedPinnedChats = parsedPinnedChats {
|
||||||
peers.append(contentsOf: parsedPinnedChats.peers)
|
peers.append(contentsOf: parsedPinnedChats.peers)
|
||||||
@ -339,6 +349,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
|||||||
channelStates.merge(parsedPinnedChats.channelStates, uniquingKeysWith: { _, updated in updated })
|
channelStates.merge(parsedPinnedChats.channelStates, uniquingKeysWith: { _, updated in updated })
|
||||||
storeMessages.append(contentsOf: parsedPinnedChats.storeMessages)
|
storeMessages.append(contentsOf: parsedPinnedChats.storeMessages)
|
||||||
topMessageIds.merge(parsedPinnedChats.topMessageIds, uniquingKeysWith: { _, updated in updated })
|
topMessageIds.merge(parsedPinnedChats.topMessageIds, uniquingKeysWith: { _, updated in updated })
|
||||||
|
hiddenTranslations.merge(parsedPinnedChats.hiddenTranslations, uniquingKeysWith: { _, updated in updated })
|
||||||
}
|
}
|
||||||
|
|
||||||
var peerGroupIds: [PeerId: PeerGroupId] = [:]
|
var peerGroupIds: [PeerId: PeerGroupId] = [:]
|
||||||
@ -362,6 +373,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
|||||||
reactionTagSummaries.merge(folderChats.reactionTagSummaries, uniquingKeysWith: { _, updated in updated })
|
reactionTagSummaries.merge(folderChats.reactionTagSummaries, uniquingKeysWith: { _, updated in updated })
|
||||||
channelStates.merge(folderChats.channelStates, uniquingKeysWith: { _, updated in updated })
|
channelStates.merge(folderChats.channelStates, uniquingKeysWith: { _, updated in updated })
|
||||||
storeMessages.append(contentsOf: folderChats.storeMessages)
|
storeMessages.append(contentsOf: folderChats.storeMessages)
|
||||||
|
hiddenTranslations.merge(folderChats.hiddenTranslations, uniquingKeysWith: { _, updated in updated })
|
||||||
}
|
}
|
||||||
|
|
||||||
var pinnedItemIds: [PeerId]?
|
var pinnedItemIds: [PeerId]?
|
||||||
@ -398,6 +410,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
|||||||
channelStates: channelStates,
|
channelStates: channelStates,
|
||||||
storeMessages: storeMessages,
|
storeMessages: storeMessages,
|
||||||
topMessageIds: topMessageIds,
|
topMessageIds: topMessageIds,
|
||||||
|
hiddenTranslations: hiddenTranslations,
|
||||||
|
|
||||||
lowerNonPinnedIndex: parsedRemoteChats.lowerNonPinnedIndex,
|
lowerNonPinnedIndex: parsedRemoteChats.lowerNonPinnedIndex,
|
||||||
|
|
||||||
|
@ -835,6 +835,19 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (peerId, _) in fetchedChats.hiddenTranslations {
|
||||||
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||||
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
|
let current = (current as? CachedChannelData) ?? CachedChannelData()
|
||||||
|
var updatedFlags = current.flags
|
||||||
|
updatedFlags.insert(.translationHidden)
|
||||||
|
return current.withUpdatedFlags(updatedFlags)
|
||||||
|
} else {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
transaction.replaceChatListHole(groupId: groupId, index: hole.index, hole: fetchedChats.lowerNonPinnedIndex.flatMap(ChatListHole.init))
|
transaction.replaceChatListHole(groupId: groupId, index: hole.index, hole: fetchedChats.lowerNonPinnedIndex.flatMap(ChatListHole.init))
|
||||||
|
|
||||||
for peerId in fetchedChats.chatPeerIds {
|
for peerId in fetchedChats.chatPeerIds {
|
||||||
|
@ -19,6 +19,7 @@ public struct CachedChannelFlags: OptionSet {
|
|||||||
public static let canChangePeerGeoLocation = CachedChannelFlags(rawValue: 1 << 5)
|
public static let canChangePeerGeoLocation = CachedChannelFlags(rawValue: 1 << 5)
|
||||||
public static let canDeleteHistory = CachedChannelFlags(rawValue: 1 << 6)
|
public static let canDeleteHistory = CachedChannelFlags(rawValue: 1 << 6)
|
||||||
public static let antiSpamEnabled = CachedChannelFlags(rawValue: 1 << 7)
|
public static let antiSpamEnabled = CachedChannelFlags(rawValue: 1 << 7)
|
||||||
|
public static let translationHidden = CachedChannelFlags(rawValue: 1 << 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable {
|
public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable {
|
||||||
|
@ -77,6 +77,19 @@ func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id
|
|||||||
|
|
||||||
func _internal_togglePeerMessagesTranslationHidden(account: Account, peerId: EnginePeer.Id, hidden: Bool) -> Signal<Never, NoError> {
|
func _internal_togglePeerMessagesTranslationHidden(account: Account, peerId: EnginePeer.Id, hidden: Bool) -> Signal<Never, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||||
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
|
var updatedFlags = cachedData.flags
|
||||||
|
if hidden {
|
||||||
|
updatedFlags.insert(.translationHidden)
|
||||||
|
} else {
|
||||||
|
updatedFlags.remove(.translationHidden)
|
||||||
|
}
|
||||||
|
return cachedData.withUpdatedFlags(updatedFlags)
|
||||||
|
} else {
|
||||||
|
return cachedData
|
||||||
|
}
|
||||||
|
})
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
|
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
|
||||||
|
@ -375,7 +375,56 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
|||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|> mapToSignal { photo -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
|> mapToSignal { photo -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||||
if peer.id != accountPeerId {
|
if peer.id == accountPeerId {
|
||||||
|
var updatedImage: TelegramMediaImage?
|
||||||
|
var representations: [TelegramMediaImageRepresentation] = []
|
||||||
|
switch photo {
|
||||||
|
case let .photo(apiPhoto, _):
|
||||||
|
updatedImage = telegramMediaImageFromApiPhoto(apiPhoto)
|
||||||
|
switch apiPhoto {
|
||||||
|
case .photoEmpty:
|
||||||
|
break
|
||||||
|
case let .photo(_, id, _, _, _, sizes, _, dcId):
|
||||||
|
var sizes = sizes
|
||||||
|
if sizes.count == 3 {
|
||||||
|
sizes.remove(at: 1)
|
||||||
|
}
|
||||||
|
for size in sizes {
|
||||||
|
switch size {
|
||||||
|
case let .photoSize(_, w, h, _):
|
||||||
|
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: CloudPeerPhotoSizeMediaResource(datacenterId: dcId, photoId: id, sizeSpec: w <= 200 ? .small : .fullSize, volumeId: nil, localId: nil), progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false))
|
||||||
|
case let .photoSizeProgressive(_, w, h, sizes):
|
||||||
|
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: CloudPeerPhotoSizeMediaResource(datacenterId: dcId, photoId: id, sizeSpec: w <= 200 ? .small : .fullSize, volumeId: nil, localId: nil), progressiveSizes: sizes, immediateThumbnailData: nil, hasVideo: false, isPersonal: false))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return postbox.transaction { transaction -> UpdatePeerPhotoStatus in
|
||||||
|
if let peer = transaction.getPeer(peer.id) {
|
||||||
|
updatePeers(transaction: transaction, peers: [peer], update: { (_, peer) -> Peer? in
|
||||||
|
if let peer = peer as? TelegramUser {
|
||||||
|
if customPeerPhotoMode == .suggest || fallback {
|
||||||
|
return peer
|
||||||
|
} else {
|
||||||
|
return peer.withUpdatedPhoto(representations)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return peer
|
||||||
|
}
|
||||||
|
})
|
||||||
|
transaction.updatePeerCachedData(peerIds: Set([peer.id])) { peerId, cachedPeerData in
|
||||||
|
if let cachedPeerData = cachedPeerData as? CachedUserData {
|
||||||
|
return cachedPeerData.withUpdatedPersonalPhoto(.known(updatedImage))
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .complete([])
|
||||||
|
} |> mapError { _ -> UploadPeerPhotoError in }
|
||||||
|
} else {
|
||||||
var updatedUsers: [TelegramUser] = []
|
var updatedUsers: [TelegramUser] = []
|
||||||
switch photo {
|
switch photo {
|
||||||
case let .photo(_, apiUsers):
|
case let .photo(_, apiUsers):
|
||||||
@ -405,7 +454,6 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
|||||||
return .complete([])
|
return .complete([])
|
||||||
} |> mapError { _ -> UploadPeerPhotoError in }
|
} |> mapError { _ -> UploadPeerPhotoError in }
|
||||||
}
|
}
|
||||||
return .single(.complete([]))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let request: Signal<Api.Updates, MTRpcError>
|
let request: Signal<Api.Updates, MTRpcError>
|
||||||
|
@ -469,6 +469,9 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
if (flags2 & Int32(1 << 1)) != 0 {
|
if (flags2 & Int32(1 << 1)) != 0 {
|
||||||
channelFlags.insert(.antiSpamEnabled)
|
channelFlags.insert(.antiSpamEnabled)
|
||||||
}
|
}
|
||||||
|
if (flags2 & Int32(1 << 3)) != 0 {
|
||||||
|
channelFlags.insert(.translationHidden)
|
||||||
|
}
|
||||||
|
|
||||||
let sendAsPeerId = defaultSendAs?.peerId
|
let sendAsPeerId = defaultSendAs?.peerId
|
||||||
|
|
||||||
|
@ -74,17 +74,20 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let ready: Promise<Bool>
|
let ready: Promise<Bool>
|
||||||
|
let peerType: AvatarEditorScreen.PeerType
|
||||||
let initialFileId: Int64?
|
let initialFileId: Int64?
|
||||||
let initialBackgroundColors: [Int32]?
|
let initialBackgroundColors: [Int32]?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
ready: Promise<Bool>,
|
ready: Promise<Bool>,
|
||||||
|
peerType: AvatarEditorScreen.PeerType,
|
||||||
initialFileId: Int64?,
|
initialFileId: Int64?,
|
||||||
initialBackgroundColors: [Int32]?
|
initialBackgroundColors: [Int32]?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.ready = ready
|
self.ready = ready
|
||||||
|
self.peerType = peerType
|
||||||
self.initialFileId = initialFileId
|
self.initialFileId = initialFileId
|
||||||
self.initialBackgroundColors = initialBackgroundColors
|
self.initialBackgroundColors = initialBackgroundColors
|
||||||
}
|
}
|
||||||
@ -93,6 +96,9 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
if lhs.context !== rhs.context {
|
if lhs.context !== rhs.context {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.peerType != rhs.peerType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.initialFileId != rhs.initialFileId {
|
if lhs.initialFileId != rhs.initialFileId {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -241,6 +247,7 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let query = rawQuery.trimmingCharacters(in: .whitespacesAndNewlines)
|
let query = rawQuery.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
if query.isEmpty {
|
if query.isEmpty {
|
||||||
strongSelf.emojiSearchDisposable.set(nil)
|
strongSelf.emojiSearchDisposable.set(nil)
|
||||||
@ -351,7 +358,7 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
EmojiPagerContentComponent.ItemGroup(
|
EmojiPagerContentComponent.ItemGroup(
|
||||||
supergroupId: "search",
|
supergroupId: "search",
|
||||||
groupId: "emoji",
|
groupId: "emoji",
|
||||||
title: "Emoji",
|
title: presentationData.strings.AvatarEditor_Emoji,
|
||||||
subtitle: nil,
|
subtitle: nil,
|
||||||
actionButtonTitle: nil,
|
actionButtonTitle: nil,
|
||||||
isFeatured: false,
|
isFeatured: false,
|
||||||
@ -370,7 +377,7 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
EmojiPagerContentComponent.ItemGroup(
|
EmojiPagerContentComponent.ItemGroup(
|
||||||
supergroupId: "search",
|
supergroupId: "search",
|
||||||
groupId: "stickers",
|
groupId: "stickers",
|
||||||
title: "Stickers",
|
title: presentationData.strings.AvatarEditor_Stickers,
|
||||||
subtitle: nil,
|
subtitle: nil,
|
||||||
actionButtonTitle: nil,
|
actionButtonTitle: nil,
|
||||||
isFeatured: false,
|
isFeatured: false,
|
||||||
@ -1136,11 +1143,21 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
contentHeight += 16.0
|
contentHeight += 16.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let buttonText: String
|
||||||
|
switch component.peerType {
|
||||||
|
case .user:
|
||||||
|
buttonText = strings.AvatarEditor_SetProfilePhoto
|
||||||
|
case .group:
|
||||||
|
buttonText = strings.AvatarEditor_SetGroupPhoto
|
||||||
|
case .channel:
|
||||||
|
buttonText = strings.AvatarEditor_SetChannelPhoto
|
||||||
|
}
|
||||||
|
|
||||||
let buttonSize = self.buttonView.update(
|
let buttonSize = self.buttonView.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
SolidRoundedButtonComponent(
|
SolidRoundedButtonComponent(
|
||||||
title: strings.AvatarEditor_SetVideo,
|
title: buttonText,
|
||||||
theme: SolidRoundedButtonComponent.Theme(theme: environment.theme),
|
theme: SolidRoundedButtonComponent.Theme(theme: environment.theme),
|
||||||
fontSize: 17.0,
|
fontSize: 17.0,
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
@ -1179,7 +1196,7 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
entity.scale = 3.3
|
entity.scale = 3.3
|
||||||
|
|
||||||
var documentId: Int64 = 0
|
var documentId: Int64 = 0
|
||||||
if case let .file(file) = entity.content, !file.isCustomEmoji {
|
if case let .file(file) = entity.content, file.isCustomEmoji {
|
||||||
documentId = file.fileId.id
|
documentId = file.fileId.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1192,7 +1209,7 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
entitiesData: entitiesData,
|
entitiesData: entitiesData,
|
||||||
image: nil,
|
image: nil,
|
||||||
stillImage: nil,
|
stillImage: nil,
|
||||||
hasAnimation: true,
|
hasAnimation: entity.isAnimated,
|
||||||
stickers: []
|
stickers: []
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1238,6 +1255,11 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class AvatarEditorScreen: ViewControllerComponentContainer {
|
public final class AvatarEditorScreen: ViewControllerComponentContainer {
|
||||||
|
public enum PeerType {
|
||||||
|
case user
|
||||||
|
case group
|
||||||
|
case channel
|
||||||
|
}
|
||||||
fileprivate let context: AccountContext
|
fileprivate let context: AccountContext
|
||||||
|
|
||||||
private let readyValue = Promise<Bool>()
|
private let readyValue = Promise<Bool>()
|
||||||
@ -1247,16 +1269,18 @@ public final class AvatarEditorScreen: ViewControllerComponentContainer {
|
|||||||
|
|
||||||
public var completion: (UIImage, URL, TGVideoEditAdjustments, @escaping () -> Void) -> Void = { _, _, _, _ in }
|
public var completion: (UIImage, URL, TGVideoEditAdjustments, @escaping () -> Void) -> Void = { _, _, _, _ in }
|
||||||
|
|
||||||
public init(context: AccountContext, initialFileId: Int64?, initialBackgroundColors: [Int32]?) {
|
public init(context: AccountContext, peerType: PeerType, initialFileId: Int64?, initialBackgroundColors: [Int32]?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
let componentReady = Promise<Bool>()
|
let componentReady = Promise<Bool>()
|
||||||
super.init(context: context, component: AvatarEditorScreenComponent(context: context, ready: componentReady, initialFileId: initialFileId, initialBackgroundColors: initialBackgroundColors), navigationBarAppearance: .transparent)
|
super.init(context: context, component: AvatarEditorScreenComponent(context: context, ready: componentReady, peerType: peerType, initialFileId: initialFileId, initialBackgroundColors: initialBackgroundColors), navigationBarAppearance: .transparent)
|
||||||
self.navigationPresentation = .modal
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
self.readyValue.set(componentReady.get() |> timeout(0.3, queue: .mainQueue(), alternate: .single(true)))
|
self.readyValue.set(componentReady.get() |> timeout(0.3, queue: .mainQueue(), alternate: .single(true)))
|
||||||
|
|
||||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
||||||
|
|
||||||
|
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
|
@ -202,7 +202,7 @@ final class AvatarPreviewComponent: Component {
|
|||||||
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0))
|
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0))
|
||||||
let source = AnimatedStickerResourceSource(account: component.context.account, resource: file.resource, isVideo: file.isVideoSticker || file.mimeType == "video/webm")
|
let source = AnimatedStickerResourceSource(account: component.context.account, resource: file.resource, isVideo: file.isVideoSticker || file.mimeType == "video/webm")
|
||||||
self.animationNode?.setup(source: source, width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .count(2), mode: .direct(cachePathPrefix: nil))
|
self.animationNode?.setup(source: source, width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .count(1), mode: .direct(cachePathPrefix: nil))
|
||||||
self.animationNode?.visibility = true
|
self.animationNode?.visibility = true
|
||||||
|
|
||||||
self.cachedDisposable.set((source.cachedDataPath(width: 384, height: 384)
|
self.cachedDisposable.set((source.cachedDataPath(width: 384, height: 384)
|
||||||
|
@ -6699,11 +6699,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
self.translationStateDisposable = (chatTranslationState(context: self.context, peerId: peerId)
|
self.translationStateDisposable = combineLatest(
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] translationState in
|
queue: .mainQueue(),
|
||||||
|
chatTranslationState(context: self.context, peerId: peerId),
|
||||||
|
self.chatDisplayNode.historyNode.cachedPeerDataAndMessages
|
||||||
|
).start(next: { [weak self] translationState, cachedDataAndMessages in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
let (cachedData, _) = cachedDataAndMessages
|
||||||
|
var isHidden = false
|
||||||
|
if let cachedData = cachedData as? CachedChannelData, cachedData.flags.contains(.translationHidden) {
|
||||||
|
isHidden = true
|
||||||
|
}
|
||||||
var chatTranslationState: ChatPresentationTranslationState?
|
var chatTranslationState: ChatPresentationTranslationState?
|
||||||
if let translationState, translationState.isHidden != true && !translationState.fromLang.isEmpty {
|
if let translationState, !isHidden && !translationState.fromLang.isEmpty {
|
||||||
chatTranslationState = ChatPresentationTranslationState(isEnabled: translationState.isEnabled, fromLang: translationState.fromLang, toLang: translationState.toLang ?? strongSelf.presentationData.strings.baseLanguageCode)
|
chatTranslationState = ChatPresentationTranslationState(isEnabled: translationState.isEnabled, fromLang: translationState.fromLang, toLang: translationState.toLang ?? strongSelf.presentationData.strings.baseLanguageCode)
|
||||||
}
|
}
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: strongSelf.willAppear, interactive: strongSelf.willAppear, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: strongSelf.willAppear, interactive: strongSelf.willAppear, { state in
|
||||||
@ -10055,16 +10063,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
let _ = updateChatTranslationStateInteractively(engine: context.engine, peerId: peerId, { current in
|
let _ = context.engine.messages.togglePeerMessagesTranslationHidden(peerId: peerId, hidden: true).start()
|
||||||
return current?.withIsHidden(true)
|
|
||||||
}).start()
|
|
||||||
|
|
||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: .white)!, title: nil, text: presentationData.strings.Conversation_Translation_TranslationBarHiddenText, round: false, undoText: presentationData.strings.Undo_Undo), elevatedLayout: false, animateInAsReplacement: false, action: { action in
|
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: .white)!, title: nil, text: presentationData.strings.Conversation_Translation_TranslationBarHiddenText, round: false, undoText: presentationData.strings.Undo_Undo), elevatedLayout: false, animateInAsReplacement: false, action: { action in
|
||||||
if case .undo = action {
|
if case .undo = action {
|
||||||
let _ = updateChatTranslationStateInteractively(engine: context.engine, peerId: peerId, { current in
|
let _ = context.engine.messages.togglePeerMessagesTranslationHidden(peerId: peerId, hidden: false).start()
|
||||||
return current?.withIsHidden(false)
|
|
||||||
}).start()
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}), in: .current)
|
}), in: .current)
|
||||||
|
@ -444,31 +444,33 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
let copyTextWithEntities = {
|
var messageEntities: [MessageTextEntity]?
|
||||||
var messageEntities: [MessageTextEntity]?
|
var restrictedText: String?
|
||||||
var restrictedText: String?
|
for attribute in message.attributes {
|
||||||
for attribute in message.attributes {
|
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
messageEntities = attribute.entities
|
||||||
messageEntities = attribute.entities
|
|
||||||
}
|
|
||||||
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
|
||||||
restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
||||||
|
restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let restrictedText = restrictedText {
|
if let restrictedText = restrictedText {
|
||||||
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
||||||
|
} else {
|
||||||
|
if let translationState = chatPresentationInterfaceState.translationState, translationState.isEnabled,
|
||||||
|
let translation = message.attributes.first(where: { ($0 as? TranslationMessageAttribute)?.toLang == translationState.toLang }) as? TranslationMessageAttribute, !translation.text.isEmpty {
|
||||||
|
storeMessageTextInPasteboard(translation.text, entities: translation.entities)
|
||||||
} else {
|
} else {
|
||||||
storeMessageTextInPasteboard(message.text, entities: messageEntities)
|
storeMessageTextInPasteboard(message.text, entities: messageEntities)
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue.mainQueue().after(0.2, {
|
|
||||||
let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_MessageCopied)
|
|
||||||
controllerInteraction.displayUndo(content)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
copyTextWithEntities()
|
Queue.mainQueue().after(0.2, {
|
||||||
|
let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_MessageCopied)
|
||||||
|
controllerInteraction.displayUndo(content)
|
||||||
|
})
|
||||||
|
|
||||||
f(.default)
|
f(.default)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
@ -1093,7 +1095,12 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
if let restrictedText = restrictedText {
|
if let restrictedText = restrictedText {
|
||||||
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
||||||
} else {
|
} else {
|
||||||
storeMessageTextInPasteboard(messageText, entities: messageEntities)
|
if let translationState = chatPresentationInterfaceState.translationState, translationState.isEnabled,
|
||||||
|
let translation = message.attributes.first(where: { ($0 as? TranslationMessageAttribute)?.toLang == translationState.toLang }) as? TranslationMessageAttribute, !translation.text.isEmpty {
|
||||||
|
storeMessageTextInPasteboard(translation.text, entities: translation.entities)
|
||||||
|
} else {
|
||||||
|
storeMessageTextInPasteboard(messageText, entities: messageEntities)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue.mainQueue().after(0.2, {
|
Queue.mainQueue().after(0.2, {
|
||||||
@ -1160,7 +1167,12 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuSpeak, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuSpeak, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
controllerInteraction.performTextSelectionAction(!isCopyProtected, NSAttributedString(string: messageText), .speak)
|
var text = messageText
|
||||||
|
if let translationState = chatPresentationInterfaceState.translationState, translationState.isEnabled,
|
||||||
|
let translation = message.attributes.first(where: { ($0 as? TranslationMessageAttribute)?.toLang == translationState.toLang }) as? TranslationMessageAttribute, !translation.text.isEmpty {
|
||||||
|
text = translation.text
|
||||||
|
}
|
||||||
|
controllerInteraction.performTextSelectionAction(!isCopyProtected, NSAttributedString(string: text), .speak)
|
||||||
f(.default)
|
f(.default)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
@ -4849,31 +4849,37 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
items.insert(.separator, at: itemsCount)
|
items.insert(.separator, at: itemsCount)
|
||||||
}
|
}
|
||||||
} else if let channel = peer as? TelegramChannel {
|
} else if let channel = peer as? TelegramChannel {
|
||||||
if let cachedData = strongSelf.data?.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) {
|
if let cachedData = strongSelf.data?.cachedData as? CachedChannelData {
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChannelInfo_Stats, icon: { theme in
|
if cachedData.flags.contains(.canViewStats) {
|
||||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.contextMenu.primaryColor)
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChannelInfo_Stats, icon: { theme in
|
||||||
}, action: { [weak self] _, f in
|
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.contextMenu.primaryColor)
|
||||||
f(.dismissWithoutContent)
|
}, action: { [weak self] _, f in
|
||||||
|
f(.dismissWithoutContent)
|
||||||
self?.openStats()
|
|
||||||
})))
|
self?.openStats()
|
||||||
}
|
})))
|
||||||
|
}
|
||||||
if let _ = strongSelf.translationState {
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuTranslate, icon: { theme in
|
if cachedData.flags.contains(.translationHidden) {
|
||||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.contextMenu.primaryColor)
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuTranslate, icon: { theme in
|
||||||
}, action: { [weak self] _, f in
|
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.contextMenu.primaryColor)
|
||||||
f(.dismissWithoutContent)
|
}, action: { [weak self] _, f in
|
||||||
|
f(.dismissWithoutContent)
|
||||||
if let strongSelf = self {
|
|
||||||
Queue.mainQueue().after(0.3, {
|
if let strongSelf = self {
|
||||||
let _ = updateChatTranslationStateInteractively(engine: strongSelf.context.engine, peerId: strongSelf.peerId, { state in
|
let _ = updateChatTranslationStateInteractively(engine: strongSelf.context.engine, peerId: strongSelf.peerId, { current in
|
||||||
return state?.withIsHidden(false)
|
return current?.withIsEnabled(true)
|
||||||
}).start()
|
}).start()
|
||||||
})
|
|
||||||
self?.openChatForTranslation()
|
Queue.mainQueue().after(0.2, {
|
||||||
}
|
let _ = (strongSelf.context.engine.messages.togglePeerMessagesTranslationHidden(peerId: strongSelf.peerId, hidden: false)
|
||||||
})))
|
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
|
self?.openChatForTranslation()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var canReport = true
|
var canReport = true
|
||||||
@ -7263,7 +7269,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
guard let strongSelf = self, let completion else {
|
guard let strongSelf = self, let completion else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = AvatarEditorScreen(context: strongSelf.context, initialFileId: emojiMarkup?.fileId, initialBackgroundColors: emojiMarkup?.backgroundColors)
|
let peerType: AvatarEditorScreen.PeerType
|
||||||
|
if case .legacyGroup = peer {
|
||||||
|
peerType = .group
|
||||||
|
} else if case let .channel(channel) = peer {
|
||||||
|
if case .group = channel.info {
|
||||||
|
peerType = .group
|
||||||
|
} else {
|
||||||
|
peerType = .channel
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peerType = .user
|
||||||
|
}
|
||||||
|
let controller = AvatarEditorScreen(context: strongSelf.context, peerType: peerType, initialFileId: emojiMarkup?.fileId, initialBackgroundColors: emojiMarkup?.backgroundColors)
|
||||||
controller.completion = completion
|
controller.completion = completion
|
||||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.push(controller)
|
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.push(controller)
|
||||||
}
|
}
|
||||||
|
@ -1148,6 +1148,9 @@ private func stringForRequestPeerType(strings: PresentationStrings, peerType: Re
|
|||||||
append(strings.RequestPeer_Requirement_Group_ForumOff)
|
append(strings.RequestPeer_Requirement_Group_ForumOff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if group.botParticipant {
|
||||||
|
append(strings.RequestPeer_Requirement_Group_ParticipantOn)
|
||||||
|
}
|
||||||
if let adminRights = group.userAdminRights, !group.isCreator {
|
if let adminRights = group.userAdminRights, !group.isCreator {
|
||||||
var rights: [String] = []
|
var rights: [String] = []
|
||||||
if adminRights.rights.contains(.canChangeInfo) {
|
if adminRights.rights.contains(.canChangeInfo) {
|
||||||
|
@ -10,33 +10,25 @@ public struct ChatTranslationState: Codable {
|
|||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case baseLang
|
case baseLang
|
||||||
case fromLang
|
case fromLang
|
||||||
case forcedFromLang
|
|
||||||
case toLang
|
case toLang
|
||||||
case isEnabled
|
case isEnabled
|
||||||
case isHidden
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public let baseLang: String
|
public let baseLang: String
|
||||||
public let fromLang: String
|
public let fromLang: String
|
||||||
public let forcedFromLang: String?
|
|
||||||
public let toLang: String?
|
public let toLang: String?
|
||||||
public let isEnabled: Bool
|
public let isEnabled: Bool
|
||||||
public let isHidden: Bool?
|
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
baseLang: String,
|
baseLang: String,
|
||||||
fromLang: String,
|
fromLang: String,
|
||||||
forcedFromLang: String?,
|
|
||||||
toLang: String?,
|
toLang: String?,
|
||||||
isEnabled: Bool,
|
isEnabled: Bool
|
||||||
isHidden: Bool?
|
|
||||||
) {
|
) {
|
||||||
self.baseLang = baseLang
|
self.baseLang = baseLang
|
||||||
self.fromLang = fromLang
|
self.fromLang = fromLang
|
||||||
self.forcedFromLang = forcedFromLang
|
|
||||||
self.toLang = toLang
|
self.toLang = toLang
|
||||||
self.isEnabled = isEnabled
|
self.isEnabled = isEnabled
|
||||||
self.isHidden = isHidden
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
@ -44,10 +36,8 @@ public struct ChatTranslationState: Codable {
|
|||||||
|
|
||||||
self.baseLang = try container.decode(String.self, forKey: .baseLang)
|
self.baseLang = try container.decode(String.self, forKey: .baseLang)
|
||||||
self.fromLang = try container.decode(String.self, forKey: .fromLang)
|
self.fromLang = try container.decode(String.self, forKey: .fromLang)
|
||||||
self.forcedFromLang = try container.decodeIfPresent(String.self, forKey: .forcedFromLang)
|
|
||||||
self.toLang = try container.decodeIfPresent(String.self, forKey: .toLang)
|
self.toLang = try container.decodeIfPresent(String.self, forKey: .toLang)
|
||||||
self.isEnabled = try container.decode(Bool.self, forKey: .isEnabled)
|
self.isEnabled = try container.decode(Bool.self, forKey: .isEnabled)
|
||||||
self.isHidden = try container.decodeIfPresent(Bool.self, forKey: .isHidden)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -55,20 +45,16 @@ public struct ChatTranslationState: Codable {
|
|||||||
|
|
||||||
try container.encode(self.baseLang, forKey: .baseLang)
|
try container.encode(self.baseLang, forKey: .baseLang)
|
||||||
try container.encode(self.fromLang, forKey: .fromLang)
|
try container.encode(self.fromLang, forKey: .fromLang)
|
||||||
try container.encodeIfPresent(self.forcedFromLang, forKey: .forcedFromLang)
|
|
||||||
try container.encodeIfPresent(self.toLang, forKey: .toLang)
|
try container.encodeIfPresent(self.toLang, forKey: .toLang)
|
||||||
try container.encode(self.isEnabled, forKey: .isEnabled)
|
try container.encode(self.isEnabled, forKey: .isEnabled)
|
||||||
try container.encodeIfPresent(self.isHidden, forKey: .isHidden)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withToLang(_ toLang: String?) -> ChatTranslationState {
|
public func withToLang(_ toLang: String?) -> ChatTranslationState {
|
||||||
return ChatTranslationState(
|
return ChatTranslationState(
|
||||||
baseLang: self.baseLang,
|
baseLang: self.baseLang,
|
||||||
fromLang: self.fromLang,
|
fromLang: self.fromLang,
|
||||||
forcedFromLang: self.forcedFromLang,
|
|
||||||
toLang: toLang,
|
toLang: toLang,
|
||||||
isEnabled: self.isEnabled,
|
isEnabled: self.isEnabled
|
||||||
isHidden: self.isHidden
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,21 +62,8 @@ public struct ChatTranslationState: Codable {
|
|||||||
return ChatTranslationState(
|
return ChatTranslationState(
|
||||||
baseLang: self.baseLang,
|
baseLang: self.baseLang,
|
||||||
fromLang: self.fromLang,
|
fromLang: self.fromLang,
|
||||||
forcedFromLang: self.forcedFromLang,
|
|
||||||
toLang: self.toLang,
|
toLang: self.toLang,
|
||||||
isEnabled: isEnabled,
|
isEnabled: isEnabled
|
||||||
isHidden: self.isHidden
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func withIsHidden(_ isHidden: Bool) -> ChatTranslationState {
|
|
||||||
return ChatTranslationState(
|
|
||||||
baseLang: self.baseLang,
|
|
||||||
fromLang: self.fromLang,
|
|
||||||
forcedFromLang: self.forcedFromLang,
|
|
||||||
toLang: self.toLang,
|
|
||||||
isEnabled: self.isEnabled,
|
|
||||||
isHidden: isHidden
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +183,7 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let fromLang = mostFrequent?.0 ?? ""
|
let fromLang = mostFrequent?.0 ?? ""
|
||||||
let state = ChatTranslationState(baseLang: baseLang, fromLang: fromLang, forcedFromLang: nil, toLang: nil, isEnabled: false, isHidden: false)
|
let state = ChatTranslationState(baseLang: baseLang, fromLang: fromLang, toLang: nil, isEnabled: false)
|
||||||
let _ = updateChatTranslationState(engine: context.engine, peerId: peerId, state: state).start()
|
let _ = updateChatTranslationState(engine: context.engine, peerId: peerId, state: state).start()
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user