mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Update API [skip ci]
This commit is contained in:
parent
21121e1924
commit
47ffcd2e4d
@ -8450,6 +8450,7 @@ Sorry for the inconvenience.";
|
||||
"UserInfo.SuggestPhoto" = "Suggest Photo for %@";
|
||||
"UserInfo.SetCustomPhoto" = "Set Photo for %@";
|
||||
"UserInfo.ResetCustomPhoto" = "Reset to Original Photo";
|
||||
"UserInfo.CustomPhotoInfo" = "You can replace %@’s photo with another photo that only you will see.";
|
||||
|
||||
"UserInfo.SuggestPhotoTitle" = "Do you want to suggest a profile picture for %@?";
|
||||
"UserInfo.SetCustomPhotoTitle" = "Do you want to set a custom profile picture for %@?";
|
||||
@ -8467,6 +8468,9 @@ Sorry for the inconvenience.";
|
||||
"UserInfo.CustomPhoto" = "photo set by you";
|
||||
"UserInfo.CustomVideo" = "video set by you";
|
||||
|
||||
"UserInfo.PublicPhoto" = "public photo";
|
||||
"UserInfo.PublicVideo" = "public video";
|
||||
|
||||
"UserInfo.ResetToOriginalAlertText" = "Are you sure you want to reset to %@ original photo?";
|
||||
"UserInfo.ResetToOriginalAlertReset" = "Reset";
|
||||
|
||||
@ -8491,3 +8495,12 @@ Sorry for the inconvenience.";
|
||||
|
||||
"PhotoEditor.SetAsMyPhoto" = "Set as My Photo";
|
||||
"PhotoEditor.SetAsMyVideo" = "Set as My Video";
|
||||
|
||||
"Notification.BotWriteAllowed" = "You allowed this bot to message you when you added it in the attachment menu.";
|
||||
|
||||
"Privacy.ProfilePhoto.SetPublicPhoto" = "Set Public Photo";
|
||||
"Privacy.ProfilePhoto.UpdatePublicPhoto" = "Update Public Photo";
|
||||
"Privacy.ProfilePhoto.RemovePublicPhoto" = "Remove Public Photo";
|
||||
"Privacy.ProfilePhoto.PublicPhotoInfo" = "You can upload a public photo for those who are restricted from viewing your real profile photo.";
|
||||
|
||||
"WebApp.AddToAttachmentAllowMessages" = "Allow **%@** to send me messages";
|
||||
|
@ -116,7 +116,7 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
|
||||
switch action.action {
|
||||
case let .photoUpdated(image), let .suggestedProfilePhoto(image):
|
||||
if let peer = messageMainPeer(EngineMessage(message)), let image = image {
|
||||
let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image.imageId, image.reference, image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), peer._asPeer(), message.timestamp, nil, message.id, image.immediateThumbnailData, "action")])
|
||||
let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image.imageId, image.reference, image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), peer._asPeer(), message.timestamp, nil, message.id, image.immediateThumbnailData, "action", false)])
|
||||
|
||||
let sourceCorners: AvatarGalleryController.SourceCorners
|
||||
if case .photoUpdated = action.action {
|
||||
|
@ -198,7 +198,7 @@ public func inviteRequestsController(context: AccountContext, updatedPresentatio
|
||||
} else {
|
||||
string = presentationData.strings.MemberRequests_UserAddedToGroup(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .invitedToVoiceChat(context: context, peer: peer, text: string, action: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .invitedToVoiceChat(context: context, peer: peer, text: string, action: nil, duration: 3), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -190,13 +190,13 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
|
||||
func animateFadeIn(animateCheckNode: Bool, animateSpoilerNode: Bool) {
|
||||
if animateCheckNode {
|
||||
self.checkNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.checkNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
self.gradientNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.typeIconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.durationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.gradientNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.typeIconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.durationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
if animateSpoilerNode {
|
||||
self.spoilerNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.spoilerNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,18 +285,18 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
self.isHidden = self.interaction?.hiddenMediaId == asset.uniqueIdentifier
|
||||
if !self.isHidden && wasHidden {
|
||||
if let checkNode = self.checkNode, checkNode.alpha > 0.0 {
|
||||
checkNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
checkNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
|
||||
if let durationTextNode = self.durationTextNode, durationTextNode.alpha > 0.0 {
|
||||
durationTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
durationTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
if let durationBackgroundNode = self.durationBackgroundNode, durationBackgroundNode.alpha > 0.0 {
|
||||
durationBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
durationBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
|
||||
if let spoilerNode = self.spoilerNode, spoilerNode.alpha > 0.0 {
|
||||
spoilerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
spoilerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,10 +37,16 @@ public func peerInfoProfilePhotos(context: AccountContext, peerId: EnginePeer.Id
|
||||
|> mapToSignal { peerView -> Signal<(Bool, [AvatarGalleryEntry])?, NoError>in
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
var secondEntry: TelegramMediaImage?
|
||||
if firstEntry.representations.first?.representation.isPersonal == true, let cachedData = peerView.cachedData as? CachedUserData, case let .known(photo) = cachedData.photo {
|
||||
secondEntry = photo
|
||||
var lastEntry: TelegramMediaImage?
|
||||
if let cachedData = peerView.cachedData as? CachedUserData {
|
||||
if firstEntry.representations.first?.representation.isPersonal == true, case let .known(photo) = cachedData.photo {
|
||||
secondEntry = photo
|
||||
}
|
||||
if case let .known(photo) = cachedData.fallbackPhoto {
|
||||
lastEntry = photo
|
||||
}
|
||||
}
|
||||
return fetchedAvatarGalleryEntries(engine: context.engine, account: context.account, peer: peer, firstEntry: firstEntry, secondEntry: secondEntry)
|
||||
return fetchedAvatarGalleryEntries(engine: context.engine, account: context.account, peer: peer, firstEntry: firstEntry, secondEntry: secondEntry, lastEntry: lastEntry)
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
return .single(nil)
|
||||
@ -74,7 +80,7 @@ public func peerInfoProfilePhotosWithCache(context: AccountContext, peerId: Peer
|
||||
|
||||
public enum AvatarGalleryEntry: Equatable {
|
||||
case topImage([ImageRepresentationWithReference], [VideoRepresentationWithReference], Peer?, GalleryItemIndexData?, Data?, String?)
|
||||
case image(MediaId, TelegramMediaImageReference?, [ImageRepresentationWithReference], [VideoRepresentationWithReference], Peer?, Int32?, GalleryItemIndexData?, MessageId?, Data?, String?)
|
||||
case image(MediaId, TelegramMediaImageReference?, [ImageRepresentationWithReference], [VideoRepresentationWithReference], Peer?, Int32?, GalleryItemIndexData?, MessageId?, Data?, String?, Bool)
|
||||
|
||||
public init(representation: TelegramMediaImageRepresentation, peer: Peer) {
|
||||
self = .topImage([ImageRepresentationWithReference(representation: representation, reference: MediaResourceReference.standalone(resource: representation.resource))], [], peer, nil, nil, nil)
|
||||
@ -87,7 +93,7 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
return .resource(last.representation.resource.id.stringRepresentation)
|
||||
}
|
||||
return .topImage
|
||||
case let .image(id, _, representations, _, _, _, _, _, _, _):
|
||||
case let .image(id, _, representations, _, _, _, _, _, _, _, _):
|
||||
if let last = representations.last {
|
||||
return .resource(last.representation.resource.id.stringRepresentation)
|
||||
}
|
||||
@ -99,7 +105,7 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
switch self {
|
||||
case let .topImage(_, _, peer, _, _, _):
|
||||
return peer
|
||||
case let .image(_, _, _, _, peer, _, _, _, _, _):
|
||||
case let .image(_, _, _, _, peer, _, _, _, _, _, _):
|
||||
return peer
|
||||
}
|
||||
}
|
||||
@ -108,7 +114,7 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
switch self {
|
||||
case let .topImage(representations, _, _, _, _, _):
|
||||
return representations
|
||||
case let .image(_, _, representations, _, _, _, _, _, _, _):
|
||||
case let .image(_, _, representations, _, _, _, _, _, _, _, _):
|
||||
return representations
|
||||
}
|
||||
}
|
||||
@ -117,7 +123,7 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
switch self {
|
||||
case let .topImage(_, _, _, _, immediateThumbnailData, _):
|
||||
return immediateThumbnailData
|
||||
case let .image(_, _, _, _, _, _, _, _, immediateThumbnailData, _):
|
||||
case let .image(_, _, _, _, _, _, _, _, immediateThumbnailData, _, _):
|
||||
return immediateThumbnailData
|
||||
}
|
||||
}
|
||||
@ -126,7 +132,7 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
switch self {
|
||||
case let .topImage(_, videoRepresentations, _, _, _, _):
|
||||
return videoRepresentations
|
||||
case let .image(_, _, _, videoRepresentations, _, _, _, _, _, _):
|
||||
case let .image(_, _, _, videoRepresentations, _, _, _, _, _, _, _):
|
||||
return videoRepresentations
|
||||
}
|
||||
}
|
||||
@ -135,7 +141,7 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
switch self {
|
||||
case let .topImage(_, _, _, indexData, _, _):
|
||||
return indexData
|
||||
case let .image(_, _, _, _, _, _, indexData, _, _, _):
|
||||
case let .image(_, _, _, _, _, _, indexData, _, _, _, _):
|
||||
return indexData
|
||||
}
|
||||
}
|
||||
@ -148,8 +154,8 @@ public enum AvatarGalleryEntry: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .image(lhsId, lhsImageReference, lhsRepresentations, lhsVideoRepresentations, lhsPeer, lhsDate, lhsIndexData, lhsMessageId, lhsImmediateThumbnailData, lhsCategory):
|
||||
if case let .image(rhsId, rhsImageReference, rhsRepresentations, rhsVideoRepresentations, rhsPeer, rhsDate, rhsIndexData, rhsMessageId, rhsImmediateThumbnailData, rhsCategory) = rhs, lhsId == rhsId, lhsImageReference == rhsImageReference, lhsRepresentations == rhsRepresentations, lhsVideoRepresentations == rhsVideoRepresentations, arePeersEqual(lhsPeer, rhsPeer), lhsDate == rhsDate, lhsIndexData == rhsIndexData, lhsMessageId == rhsMessageId, lhsImmediateThumbnailData == rhsImmediateThumbnailData, lhsCategory == rhsCategory {
|
||||
case let .image(lhsId, lhsImageReference, lhsRepresentations, lhsVideoRepresentations, lhsPeer, lhsDate, lhsIndexData, lhsMessageId, lhsImmediateThumbnailData, lhsCategory, lhsIsFallback):
|
||||
if case let .image(rhsId, rhsImageReference, rhsRepresentations, rhsVideoRepresentations, rhsPeer, rhsDate, rhsIndexData, rhsMessageId, rhsImmediateThumbnailData, rhsCategory, rhsIsFallback) = rhs, lhsId == rhsId, lhsImageReference == rhsImageReference, lhsRepresentations == rhsRepresentations, lhsVideoRepresentations == rhsVideoRepresentations, arePeersEqual(lhsPeer, rhsPeer), lhsDate == rhsDate, lhsIndexData == rhsIndexData, lhsMessageId == rhsMessageId, lhsImmediateThumbnailData == rhsImmediateThumbnailData, lhsCategory == rhsCategory, lhsIsFallback == rhsIsFallback {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -176,8 +182,8 @@ public func normalizeEntries(_ entries: [AvatarGalleryEntry]) -> [AvatarGalleryE
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: count)
|
||||
if case let .topImage(representations, videoRepresentations, peer, _, immediateThumbnailData, category) = entry {
|
||||
updatedEntries.append(.topImage(representations, videoRepresentations, peer, indexData, immediateThumbnailData, category))
|
||||
} else if case let .image(id, reference, representations, videoRepresentations, peer, date, _, messageId, immediateThumbnailData, category) = entry {
|
||||
updatedEntries.append(.image(id, reference, representations, videoRepresentations, peer, date, indexData, messageId, immediateThumbnailData, category))
|
||||
} else if case let .image(id, reference, representations, videoRepresentations, peer, date, _, messageId, immediateThumbnailData, category, isFallback) = entry {
|
||||
updatedEntries.append(.image(id, reference, representations, videoRepresentations, peer, date, indexData, messageId, immediateThumbnailData, category, isFallback))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
@ -203,7 +209,7 @@ public func initialAvatarGalleryEntries(account: Account, engine: TelegramEngine
|
||||
if photo.immediateThumbnailData == nil, let firstEntry = initialEntries.first, let firstRepresentation = firstEntry.representations.first {
|
||||
representations.insert(firstRepresentation, at: 0)
|
||||
}
|
||||
return [.image(photo.imageId, photo.reference, representations, photo.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, nil, nil, nil, photo.immediateThumbnailData, nil)]
|
||||
return [.image(photo.imageId, photo.reference, representations, photo.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, nil, nil, nil, photo.immediateThumbnailData, nil, false)]
|
||||
} else {
|
||||
if case .known = peerPhoto {
|
||||
return []
|
||||
@ -235,7 +241,7 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
if [Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel].contains(peer.id.namespace) {
|
||||
var initialMediaIds = Set<MediaId>()
|
||||
for entry in initialEntries {
|
||||
if case let .image(mediaId, _, _, _, _, _, _, _, _, _) = entry {
|
||||
if case let .image(mediaId, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||
initialMediaIds.insert(mediaId)
|
||||
}
|
||||
}
|
||||
@ -247,24 +253,24 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
photosCount += 1
|
||||
for entry in initialEntries {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photosCount))
|
||||
if case let .image(mediaId, imageReference, representations, videoRepresentations, peer, _, _, _, thumbnailData, _) = entry {
|
||||
result.append(.image(mediaId, imageReference, representations, videoRepresentations, peer, nil, indexData, nil, thumbnailData, nil))
|
||||
if case let .image(mediaId, imageReference, representations, videoRepresentations, peer, _, _, _, thumbnailData, _, _) = entry {
|
||||
result.append(.image(mediaId, imageReference, representations, videoRepresentations, peer, nil, indexData, nil, thumbnailData, nil, false))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photosCount))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false))
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
for photo in photos {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
|
||||
if result.isEmpty, let first = initialEntries.first {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false))
|
||||
} else {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
@ -276,7 +282,7 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account, peer: Peer, firstEntry: AvatarGalleryEntry, secondEntry: TelegramMediaImage?) -> Signal<(Bool, [AvatarGalleryEntry]), NoError> {
|
||||
public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account, peer: Peer, firstEntry: AvatarGalleryEntry, secondEntry: TelegramMediaImage?, lastEntry: TelegramMediaImage?) -> Signal<(Bool, [AvatarGalleryEntry]), NoError> {
|
||||
let initialEntries = [firstEntry]
|
||||
return Signal<(Bool, [AvatarGalleryEntry]), NoError>.single((false, initialEntries))
|
||||
|> then(
|
||||
@ -292,7 +298,7 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
if [Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel].contains(peer.id.namespace) {
|
||||
var initialMediaIds = Set<MediaId>()
|
||||
for entry in initialEntries {
|
||||
if case let .image(mediaId, _, _, _, _, _, _, _, _, _) = entry {
|
||||
if case let .image(mediaId, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||
initialMediaIds.insert(mediaId)
|
||||
}
|
||||
}
|
||||
@ -306,8 +312,8 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
photosCount += 1
|
||||
for entry in initialEntries {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photosCount))
|
||||
if case let .image(mediaId, imageReference, representations, videoRepresentations, peer, _, _, _, thumbnailData, _) = entry {
|
||||
result.append(.image(mediaId, imageReference, representations, videoRepresentations, peer, nil, indexData, nil, thumbnailData, nil))
|
||||
if case let .image(mediaId, imageReference, representations, videoRepresentations, peer, _, _, _, thumbnailData, _, _) = entry {
|
||||
result.append(.image(mediaId, imageReference, representations, videoRepresentations, peer, nil, indexData, nil, thumbnailData, nil, false))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -317,7 +323,7 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
}
|
||||
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photosCount))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false))
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
@ -325,12 +331,15 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
if let secondEntry {
|
||||
photos.insert(TelegramPeerPhoto(image: secondEntry, reference: secondEntry.reference, date: 0, index: 1, totalCount: 0, messageId: nil), at: 1)
|
||||
}
|
||||
if let lastEntry {
|
||||
photos.append(TelegramPeerPhoto(image: lastEntry, reference: lastEntry.reference, date: 0, index: photos.count, totalCount: 0, messageId: nil))
|
||||
}
|
||||
for photo in photos {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
|
||||
if result.isEmpty, let first = initialEntries.first {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false))
|
||||
} else {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, photo.image.id == lastEntry?.id))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
@ -441,8 +450,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
let isFirstTime = strongSelf.entries.isEmpty
|
||||
|
||||
var entries = entries
|
||||
if !isFirstTime, let updated = entries.first, case let .image(mediaId, imageReference, _, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption) = updated, !videoRepresentations.isEmpty, let previous = strongSelf.entries.first, case let .topImage(representations, _, _, _, _, _) = previous {
|
||||
let firstEntry = AvatarGalleryEntry.image(mediaId, imageReference, representations, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption)
|
||||
if !isFirstTime, let updated = entries.first, case let .image(mediaId, imageReference, _, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption, _) = updated, !videoRepresentations.isEmpty, let previous = strongSelf.entries.first, case let .topImage(representations, _, _, _, _, _) = previous {
|
||||
let firstEntry = AvatarGalleryEntry.image(mediaId, imageReference, representations, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption, false)
|
||||
entries.remove(at: 0)
|
||||
entries.insert(firstEntry, at: 0)
|
||||
}
|
||||
@ -758,13 +767,13 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
if self.peer.id == self.context.account.peerId {
|
||||
} else {
|
||||
}
|
||||
case let .image(_, reference, _, _, _, _, _, _, _, _):
|
||||
case let .image(_, reference, _, _, _, _, _, _, _, _, _):
|
||||
if self.peer.id == self.context.account.peerId, let peerReference = PeerReference(self.peer) {
|
||||
if let reference = reference {
|
||||
let _ = (self.context.engine.accountData.updatePeerPhotoExisting(reference: reference)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] photo in
|
||||
if let strongSelf = self, let photo = photo, let firstEntry = strongSelf.entries.first, case let .image(_, _, _, _, _, index, indexData, messageId, _, caption) = firstEntry {
|
||||
let updatedEntry = AvatarGalleryEntry.image(photo.imageId, photo.reference, photo.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), photo.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), strongSelf.peer, index, indexData, messageId, photo.immediateThumbnailData, caption)
|
||||
if let strongSelf = self, let photo = photo, let firstEntry = strongSelf.entries.first, case let .image(_, _, _, _, _, index, indexData, messageId, _, caption, _) = firstEntry {
|
||||
let updatedEntry = AvatarGalleryEntry.image(photo.imageId, photo.reference, photo.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), photo.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), strongSelf.peer, index, indexData, messageId, photo.immediateThumbnailData, caption, false)
|
||||
|
||||
for (lhs, rhs) in zip(firstEntry.representations, updatedEntry.representations) {
|
||||
if lhs.representation.dimensions == rhs.representation.dimensions {
|
||||
@ -882,7 +891,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .image(_, reference, _, _, _, _, _, messageId, _, _):
|
||||
case let .image(_, reference, _, _, _, _, _, messageId, _, _, _):
|
||||
if self.peer.id == self.context.account.peerId {
|
||||
if let reference = reference {
|
||||
let _ = self.context.engine.accountData.removeAccountPhoto(reference: reference).start()
|
||||
|
@ -107,7 +107,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode {
|
||||
var buttonText: String?
|
||||
var canShare = true
|
||||
switch entry {
|
||||
case let .image(_, _, _, videoRepresentations, peer, date, _, _, _, _):
|
||||
case let .image(_, _, _, videoRepresentations, peer, date, _, _, _, _, _):
|
||||
nameText = peer.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
|
||||
if let date = date {
|
||||
dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: date).string
|
||||
|
@ -106,7 +106,7 @@ class PeerAvatarImageGalleryItem: GalleryItem {
|
||||
switch self.entry {
|
||||
case let .topImage(representations, _, _, _, _, _):
|
||||
content = representations
|
||||
case let .image(_, _, representations, _, _, _, _, _, _, _):
|
||||
case let .image(_, _, representations, _, _, _, _, _, _, _, _):
|
||||
content = representations
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
var id: Int64
|
||||
var category: String?
|
||||
if case let .image(mediaId, _, _, _, _, _, _, _, _, categoryValue) = entry {
|
||||
if case let .image(mediaId, _, _, _, _, _, _, _, _, categoryValue, _) = entry {
|
||||
id = mediaId.id
|
||||
category = categoryValue
|
||||
} else {
|
||||
@ -608,7 +608,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
switch entry {
|
||||
case let .topImage(topRepresentations, _, _, _, _, _):
|
||||
representations = topRepresentations
|
||||
case let .image(_, _, imageRepresentations, _, _, _, _, _, _, _):
|
||||
case let .image(_, _, imageRepresentations, _, _, _, _, _, _, _, _):
|
||||
representations = imageRepresentations
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import GalleryUI
|
||||
import UniversalMediaPlayer
|
||||
import RadialStatusNode
|
||||
import TelegramUIPreferences
|
||||
import AvatarNode
|
||||
|
||||
private class PeerInfoAvatarListLoadingStripNode: ASImageNode {
|
||||
private var currentInHierarchy = false
|
||||
@ -90,7 +91,7 @@ private struct CustomListItemResourceId {
|
||||
public enum PeerInfoAvatarListItem: Equatable {
|
||||
case custom(ASDisplayNode)
|
||||
case topImage([ImageRepresentationWithReference], [VideoRepresentationWithReference], Data?)
|
||||
case image(TelegramMediaImageReference?, [ImageRepresentationWithReference], [VideoRepresentationWithReference], Data?)
|
||||
case image(TelegramMediaImageReference?, [ImageRepresentationWithReference], [VideoRepresentationWithReference], Data?, Bool)
|
||||
|
||||
var id: MediaResourceId {
|
||||
switch self {
|
||||
@ -99,7 +100,7 @@ public enum PeerInfoAvatarListItem: Equatable {
|
||||
case let .topImage(representations, _, _):
|
||||
let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation
|
||||
return representation.resource.id
|
||||
case let .image(_, representations, _, _):
|
||||
case let .image(_, representations, _, _, _):
|
||||
let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation
|
||||
return representation.resource.id
|
||||
}
|
||||
@ -114,7 +115,7 @@ public enum PeerInfoAvatarListItem: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else if case let .image(_, rhsRepresentations, _, _) = self {
|
||||
} else if case let .image(_, rhsRepresentations, _, _, _) = self {
|
||||
if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }),
|
||||
let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) {
|
||||
return lhsRepresentation.isSemanticallyEqual(to: rhsRepresentation)
|
||||
@ -124,7 +125,7 @@ public enum PeerInfoAvatarListItem: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else if case let .image(_, lhsRepresentations, _, _) = self {
|
||||
} else if case let .image(_, lhsRepresentations, _, _, _) = self {
|
||||
if case let .topImage(rhsRepresentations, _, _) = self {
|
||||
if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }),
|
||||
let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) {
|
||||
@ -132,7 +133,7 @@ public enum PeerInfoAvatarListItem: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else if case let .image(_, rhsRepresentations, _, _) = self {
|
||||
} else if case let .image(_, rhsRepresentations, _, _, _) = self {
|
||||
if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }),
|
||||
let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) {
|
||||
return lhsRepresentation.isSemanticallyEqual(to: rhsRepresentation)
|
||||
@ -153,7 +154,7 @@ public enum PeerInfoAvatarListItem: Equatable {
|
||||
return []
|
||||
case let .topImage(representations, _, _):
|
||||
return representations
|
||||
case let .image(_, representations, _, _):
|
||||
case let .image(_, representations, _, _, _):
|
||||
return representations
|
||||
}
|
||||
}
|
||||
@ -165,20 +166,29 @@ public enum PeerInfoAvatarListItem: Equatable {
|
||||
return []
|
||||
case let .topImage(_, videoRepresentations, _):
|
||||
return videoRepresentations
|
||||
case let .image(_, _, videoRepresentations, _):
|
||||
case let .image(_, _, videoRepresentations, _, _):
|
||||
return videoRepresentations
|
||||
}
|
||||
}
|
||||
|
||||
var isFallback: Bool {
|
||||
switch self {
|
||||
case .custom, .topImage:
|
||||
return false
|
||||
case let .image(_, _, _, _, isFallback):
|
||||
return isFallback
|
||||
}
|
||||
}
|
||||
|
||||
public init?(entry: AvatarGalleryEntry) {
|
||||
switch entry {
|
||||
case let .topImage(representations, videoRepresentations, _, _, immediateThumbnailData, _):
|
||||
self = .topImage(representations, videoRepresentations, immediateThumbnailData)
|
||||
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _):
|
||||
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _, isFallback):
|
||||
if representations.isEmpty {
|
||||
return nil
|
||||
}
|
||||
self = .image(reference, representations, videoRepresentations, immediateThumbnailData)
|
||||
self = .image(reference, representations, videoRepresentations, immediateThumbnailData, isFallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -441,7 +451,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
if let resource = videoRepresentations.first?.representation.resource as? CloudPhotoSizeMediaResource {
|
||||
id = id &+ resource.photoId
|
||||
}
|
||||
case let .image(reference, imageRepresentations, videoRepresentationsValue, immediateThumbnail):
|
||||
case let .image(reference, imageRepresentations, videoRepresentationsValue, immediateThumbnail, _):
|
||||
representations = imageRepresentations
|
||||
videoRepresentations = videoRepresentationsValue
|
||||
immediateThumbnailData = immediateThumbnail
|
||||
@ -523,6 +533,9 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
public let stripContainerNode: ASDisplayNode
|
||||
public let highlightContainerNode: ASDisplayNode
|
||||
private let setByYouNode: ImmediateTextNode
|
||||
private let setByYouImageNode: ImageNode
|
||||
private var setByYouTapRecognizer: UITapGestureRecognizer?
|
||||
|
||||
public private(set) var galleryEntries: [AvatarGalleryEntry] = []
|
||||
private var items: [PeerInfoAvatarListItem] = []
|
||||
private var itemNodes: [MediaResourceId: PeerInfoAvatarListItemNode] = [:]
|
||||
@ -694,6 +707,10 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
self.setByYouNode.alpha = 0.0
|
||||
self.setByYouNode.isUserInteractionEnabled = false
|
||||
|
||||
self.setByYouImageNode = ImageNode()
|
||||
self.setByYouImageNode.alpha = 0.0
|
||||
self.setByYouImageNode.isUserInteractionEnabled = false
|
||||
|
||||
self.controlsContainerNode = ASDisplayNode()
|
||||
self.controlsContainerNode.isUserInteractionEnabled = false
|
||||
|
||||
@ -764,6 +781,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
self.controlsClippingNode.addSubnode(self.controlsContainerNode)
|
||||
self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode)
|
||||
self.stripContainerNode.addSubnode(self.setByYouNode)
|
||||
self.stripContainerNode.addSubnode(self.setByYouImageNode)
|
||||
|
||||
self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
@ -830,6 +848,19 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
self.positionDisposable.dispose()
|
||||
}
|
||||
|
||||
public override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let setByYouTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.setByYouTapped))
|
||||
self.setByYouNode.isUserInteractionEnabled = true
|
||||
self.setByYouNode.view.addGestureRecognizer(setByYouTapRecognizer)
|
||||
self.setByYouTapRecognizer = setByYouTapRecognizer
|
||||
}
|
||||
|
||||
@objc private func setByYouTapped() {
|
||||
self.selectLastItem()
|
||||
}
|
||||
|
||||
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
@ -845,6 +876,17 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func selectLastItem() {
|
||||
let previousIndex = self.currentIndex
|
||||
self.currentIndex = self.items.count - 1
|
||||
if self.currentIndex != previousIndex {
|
||||
self.currentIndexUpdated?()
|
||||
}
|
||||
if let size = self.validLayout {
|
||||
self.updateItems(size: size, transition: .immediate, stripTransition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
public func updateEntryIsHidden(entry: AvatarGalleryEntry?) {
|
||||
if let entry = entry, let index = self.galleryEntries.firstIndex(of: entry) {
|
||||
self.currentItemNode?.isHidden = index == self.currentIndex
|
||||
@ -956,7 +998,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
func setMainItem(_ item: PeerInfoAvatarListItem) {
|
||||
guard case let .image(imageReference, _, _, _) = item else {
|
||||
guard case let .image(imageReference, _, _, _, _) = item else {
|
||||
return
|
||||
}
|
||||
var items: [PeerInfoAvatarListItem] = []
|
||||
@ -966,16 +1008,16 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
case let .topImage(representations, videoRepresentations, _, _, immediateThumbnailData, _):
|
||||
entries.append(entry)
|
||||
items.append(.topImage(representations, videoRepresentations, immediateThumbnailData))
|
||||
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _):
|
||||
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _, isFallback):
|
||||
if representations.isEmpty {
|
||||
continue
|
||||
}
|
||||
if imageReference == reference {
|
||||
entries.insert(entry, at: 0)
|
||||
items.insert(.image(reference, representations, videoRepresentations, immediateThumbnailData), at: 0)
|
||||
items.insert(.image(reference, representations, videoRepresentations, immediateThumbnailData, isFallback), at: 0)
|
||||
} else {
|
||||
entries.append(entry)
|
||||
items.append(.image(reference, representations, videoRepresentations, immediateThumbnailData))
|
||||
items.append(.image(reference, representations, videoRepresentations, immediateThumbnailData, isFallback))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -994,7 +1036,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
public func deleteItem(_ item: PeerInfoAvatarListItem) -> Bool {
|
||||
guard case let .image(imageReference, _, _, _) = item else {
|
||||
guard case let .image(imageReference, _, _, _, _) = item else {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1009,13 +1051,13 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
case let .topImage(representations, videoRepresentations, _, _, immediateThumbnailData, _):
|
||||
entries.append(entry)
|
||||
items.append(.topImage(representations, videoRepresentations, immediateThumbnailData))
|
||||
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _):
|
||||
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _, isFallback):
|
||||
if representations.isEmpty {
|
||||
continue
|
||||
}
|
||||
if imageReference != reference {
|
||||
entries.append(entry)
|
||||
items.append(.image(reference, representations, videoRepresentations, immediateThumbnailData))
|
||||
items.append(.image(reference, representations, videoRepresentations, immediateThumbnailData, isFallback))
|
||||
} else {
|
||||
deletedIndex = index
|
||||
}
|
||||
@ -1081,8 +1123,8 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var synchronous = false
|
||||
if !strongSelf.galleryEntries.isEmpty, let updated = entries.first, case let .image(mediaId, reference, _, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption) = updated, !videoRepresentations.isEmpty, let previous = strongSelf.galleryEntries.first, case let .topImage(representations, _, _, _, _, _) = previous {
|
||||
let firstEntry = AvatarGalleryEntry.image(mediaId, reference, representations, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption)
|
||||
if !strongSelf.galleryEntries.isEmpty, let updated = entries.first, case let .image(mediaId, reference, _, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption, _) = updated, !videoRepresentations.isEmpty, let previous = strongSelf.galleryEntries.first, case let .topImage(representations, _, _, _, _, _) = previous {
|
||||
let firstEntry = AvatarGalleryEntry.image(mediaId, reference, representations, videoRepresentations, peer, index, indexData, messageId, thumbnailData, caption, false)
|
||||
entries.remove(at: 0)
|
||||
entries.insert(firstEntry, at: 0)
|
||||
synchronous = true
|
||||
@ -1264,13 +1306,39 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
if !self.items.isEmpty, self.currentIndex >= 0 && self.currentIndex < self.items.count {
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let currentItem = self.items[self.currentIndex]
|
||||
|
||||
var photoTitle: String?
|
||||
var hasLink = false
|
||||
var fallbackImageSignal: Signal<UIImage?, NoError>?
|
||||
if let representation = currentItem.representations.first?.representation, representation.isPersonal {
|
||||
photoTitle = representation.hasVideo ? presentationData.strings.UserInfo_CustomVideo : presentationData.strings.UserInfo_CustomPhoto
|
||||
} else if currentItem.isFallback, let representation = currentItem.representations.first?.representation {
|
||||
photoTitle = representation.hasVideo ? presentationData.strings.UserInfo_PublicVideo : presentationData.strings.UserInfo_PublicPhoto
|
||||
} else if self.currentIndex == 0, let lastItem = self.items.last, lastItem.isFallback, let representation = lastItem.representations.first?.representation {
|
||||
photoTitle = representation.hasVideo ? presentationData.strings.UserInfo_PublicVideo : presentationData.strings.UserInfo_PublicPhoto
|
||||
hasLink = true
|
||||
if let peer = self.peer {
|
||||
fallbackImageSignal = peerAvatarCompleteImage(account: self.context.account, peer: EnginePeer(peer), forceProvidedRepresentation: true, representation: representation, size: CGSize(width: 28.0, height: 28.0))
|
||||
}
|
||||
}
|
||||
|
||||
if let photoTitle = photoTitle {
|
||||
transition.updateAlpha(node: self.setByYouNode, alpha: 0.7)
|
||||
self.setByYouNode.attributedText = NSAttributedString(string: representation.hasVideo ? presentationData.strings.UserInfo_CustomVideo : presentationData.strings.UserInfo_CustomPhoto, font: Font.regular(12.0), textColor: UIColor.white)
|
||||
self.setByYouNode.attributedText = NSAttributedString(string: photoTitle, font: Font.regular(12.0), textColor: UIColor.white)
|
||||
let setByYouSize = self.setByYouNode.updateLayout(size)
|
||||
self.setByYouNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - setByYouSize.width) / 2.0), y: 17.0), size: setByYouSize)
|
||||
self.setByYouNode.isUserInteractionEnabled = hasLink
|
||||
} else {
|
||||
transition.updateAlpha(node: self.setByYouNode, alpha: 0.0)
|
||||
self.setByYouNode.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
if let fallbackImageSignal = fallbackImageSignal {
|
||||
self.setByYouImageNode.setSignal(fallbackImageSignal)
|
||||
transition.updateAlpha(node: self.setByYouImageNode, alpha: 1.0)
|
||||
self.setByYouImageNode.frame = CGRect(origin: CGPoint(x: self.setByYouNode.frame.minX - 32.0, y: 11.0), size: CGSize(width: 28.0, height: 28.0))
|
||||
} else {
|
||||
transition.updateAlpha(node: self.setByYouImageNode, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ public final class QrCodeScanScreen: ViewController {
|
||||
public enum Subject {
|
||||
case authTransfer(activeSessionsContext: ActiveSessionsContext)
|
||||
case peer
|
||||
case custom(info: String)
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
@ -97,9 +98,12 @@ public final class QrCodeScanScreen: ViewController {
|
||||
}
|
||||
|
||||
public var showMyCode: () -> Void = {}
|
||||
public var completion: (String?) -> Void = { _ in }
|
||||
|
||||
private var codeResolved = false
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
public init(context: AccountContext, subject: QrCodeScanScreen.Subject) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
@ -126,7 +130,9 @@ public final class QrCodeScanScreen: ViewController {
|
||||
(strongSelf.displayNode as! QrCodeScanScreenNode).updateInForeground(inForeground)
|
||||
})
|
||||
|
||||
if case .peer = subject {
|
||||
if case .custom = subject {
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
} else if case .peer = subject {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Contacts_QrCode_MyCode, style: .plain, target: self, action: #selector(self.myCodePressed))
|
||||
} else {
|
||||
#if DEBUG
|
||||
@ -145,6 +151,16 @@ public final class QrCodeScanScreen: ViewController {
|
||||
self.approveDisposable.dispose()
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
guard let layout = self.validLayout else {
|
||||
return
|
||||
}
|
||||
self.completion(nil)
|
||||
self.controllerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: layout.size.height), duration: 0.2, removeOnCompletion: false, additive: true, completion: { _ in
|
||||
self.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
@objc private func myCodePressed() {
|
||||
self.showMyCode()
|
||||
}
|
||||
@ -153,6 +169,16 @@ public final class QrCodeScanScreen: ViewController {
|
||||
self.dismissWithSession(session: nil)
|
||||
}
|
||||
|
||||
private var animatedIn = false
|
||||
public override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if case .custom = self.subject, !self.animatedIn, let layout = self.validLayout {
|
||||
self.animatedIn = true
|
||||
self.controllerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: layout.size.height), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
}
|
||||
}
|
||||
|
||||
private func dismissWithSession(session: RecentAccountSession?) {
|
||||
guard case let .authTransfer(activeSessionsContext) = self.subject else {
|
||||
return
|
||||
@ -184,6 +210,14 @@ public final class QrCodeScanScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func completeWithCode(_ code: String) {
|
||||
guard case .custom = self.subject else {
|
||||
return
|
||||
}
|
||||
self.completion(code)
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = QrCodeScanScreenNode(context: self.context, presentationData: self.presentationData, controller: self, subject: self.subject)
|
||||
|
||||
@ -235,6 +269,8 @@ public final class QrCodeScanScreen: ViewController {
|
||||
}
|
||||
})
|
||||
}
|
||||
case .custom:
|
||||
strongSelf.completeWithCode(code)
|
||||
}
|
||||
})
|
||||
|
||||
@ -246,6 +282,8 @@ public final class QrCodeScanScreen: ViewController {
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
self.validLayout = layout
|
||||
|
||||
(self.displayNode as! QrCodeScanScreenNode).containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
}
|
||||
@ -344,6 +382,9 @@ private final class QrCodeScanScreenNode: ViewControllerTracingNode, UIScrollVie
|
||||
case .peer:
|
||||
title = ""
|
||||
text = ""
|
||||
case let .custom(info):
|
||||
title = presentationData.strings.AuthSessions_AddDevice_ScanTitle
|
||||
text = info
|
||||
}
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
@ -445,6 +486,8 @@ private final class QrCodeScanScreenNode: ViewControllerTracingNode, UIScrollVie
|
||||
filteredCodes = codes.filter { $0.message.hasPrefix("tg://") }
|
||||
case .peer:
|
||||
filteredCodes = codes.filter { $0.message.hasPrefix("https://t.me/") || $0.message.hasPrefix("t.me/") }
|
||||
case .custom:
|
||||
filteredCodes = codes
|
||||
}
|
||||
if let code = filteredCodes.first, CGRect(x: 0.3, y: 0.3, width: 0.4, height: 0.4).contains(code.boundingBox.center) {
|
||||
if strongSelf.codeWithError != code.message {
|
||||
|
@ -614,7 +614,22 @@ class PrivacyAndSecurityControllerImpl: ItemListController, ASAuthorizationContr
|
||||
}
|
||||
}
|
||||
|
||||
public func privacyAndSecurityController(context: AccountContext, initialSettings: AccountPrivacySettings? = nil, updatedSettings: ((AccountPrivacySettings?) -> Void)? = nil, updatedBlockedPeers: ((BlockedPeersContext?) -> Void)? = nil, updatedHasTwoStepAuth: ((Bool) -> Void)? = nil, focusOnItemTag: PrivacyAndSecurityEntryTag? = nil, activeSessionsContext: ActiveSessionsContext? = nil, webSessionsContext: WebSessionsContext? = nil, blockedPeersContext: BlockedPeersContext? = nil, hasTwoStepAuth: Bool? = nil, loginEmailPattern: Signal<String?, NoError>? = nil, updatedTwoStepAuthData: (() -> Void)? = nil) -> ViewController {
|
||||
public func privacyAndSecurityController(
|
||||
context: AccountContext,
|
||||
initialSettings: AccountPrivacySettings? = nil,
|
||||
updatedSettings: ((AccountPrivacySettings?) -> Void)? = nil,
|
||||
updatedBlockedPeers: ((BlockedPeersContext?) -> Void)? = nil,
|
||||
updatedHasTwoStepAuth: ((Bool) -> Void)? = nil,
|
||||
focusOnItemTag: PrivacyAndSecurityEntryTag? = nil,
|
||||
activeSessionsContext: ActiveSessionsContext? = nil,
|
||||
webSessionsContext: WebSessionsContext? = nil,
|
||||
blockedPeersContext: BlockedPeersContext? = nil,
|
||||
hasTwoStepAuth: Bool? = nil,
|
||||
loginEmailPattern: Signal<String?, NoError>? = nil,
|
||||
updatedTwoStepAuthData: (() -> Void)? = nil,
|
||||
requestPublicPhotoSetup: (() -> Void)? = nil,
|
||||
requestPublicPhotoRemove: (() -> Void)? = nil
|
||||
) -> ViewController {
|
||||
let statePromise = ValuePromise(PrivacyAndSecurityControllerState(), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: PrivacyAndSecurityControllerState())
|
||||
let updateState: ((PrivacyAndSecurityControllerState) -> PrivacyAndSecurityControllerState) -> Void = { f in
|
||||
@ -804,7 +819,11 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
|> deliverOnMainQueue
|
||||
currentInfoDisposable.set(signal.start(next: { [weak currentInfoDisposable] info in
|
||||
if let info = info {
|
||||
pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .profilePhoto, current: info.profilePhoto, updated: { updated, _, _ in
|
||||
pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .profilePhoto, current: info.profilePhoto, requestPublicPhotoSetup: {
|
||||
requestPublicPhotoSetup?()
|
||||
}, requestPublicPhotoRemove: {
|
||||
requestPublicPhotoRemove?()
|
||||
}, updated: { updated, _, _ in
|
||||
if let currentInfoDisposable = currentInfoDisposable {
|
||||
let applySetting: Signal<Void, NoError> = privacySettingsPromise.get()
|
||||
|> filter { $0 != nil }
|
||||
|
@ -10,6 +10,7 @@ import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import UndoUI
|
||||
import ItemListPeerActionItem
|
||||
|
||||
enum SelectivePrivacySettingsKind {
|
||||
case presence
|
||||
@ -54,7 +55,10 @@ private final class SelectivePrivacySettingsControllerArguments {
|
||||
let updatePhoneDiscovery: ((Bool) -> Void)?
|
||||
let copyPhoneLink: ((String) -> Void)?
|
||||
|
||||
init(context: AccountContext, updateType: @escaping (SelectivePrivacySettingType) -> Void, openSelective: @escaping (SelectivePrivacySettingsPeerTarget, Bool) -> Void, updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?, updateCallIntegrationEnabled: ((Bool) -> Void)?, updatePhoneDiscovery: ((Bool) -> Void)?, copyPhoneLink: ((String) -> Void)?) {
|
||||
let setPublicPhoto: (() -> Void)?
|
||||
let removePublicPhoto: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, updateType: @escaping (SelectivePrivacySettingType) -> Void, openSelective: @escaping (SelectivePrivacySettingsPeerTarget, Bool) -> Void, updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?, updateCallIntegrationEnabled: ((Bool) -> Void)?, updatePhoneDiscovery: ((Bool) -> Void)?, copyPhoneLink: ((String) -> Void)?, setPublicPhoto: (() -> Void)?, removePublicPhoto: (() -> Void)?) {
|
||||
self.context = context
|
||||
self.updateType = updateType
|
||||
self.openSelective = openSelective
|
||||
@ -63,12 +67,16 @@ private final class SelectivePrivacySettingsControllerArguments {
|
||||
self.updateCallIntegrationEnabled = updateCallIntegrationEnabled
|
||||
self.updatePhoneDiscovery = updatePhoneDiscovery
|
||||
self.copyPhoneLink = copyPhoneLink
|
||||
|
||||
self.setPublicPhoto = setPublicPhoto
|
||||
self.removePublicPhoto = removePublicPhoto
|
||||
}
|
||||
}
|
||||
|
||||
private enum SelectivePrivacySettingsSection: Int32 {
|
||||
case forwards
|
||||
case setting
|
||||
case photo
|
||||
case peers
|
||||
case callsP2P
|
||||
case callsP2PPeers
|
||||
@ -96,6 +104,9 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
case contacts(PresentationTheme, String, Bool)
|
||||
case nobody(PresentationTheme, String, Bool)
|
||||
case settingInfo(PresentationTheme, String, String)
|
||||
case setPublicPhoto(PresentationTheme, String)
|
||||
case removePublicPhoto(PresentationTheme, String, EnginePeer, TelegramMediaImage?)
|
||||
case publicPhotoInfo(PresentationTheme, String)
|
||||
case exceptionsHeader(PresentationTheme, String)
|
||||
case disableFor(PresentationTheme, String, String)
|
||||
case enableFor(PresentationTheme, String, String)
|
||||
@ -121,6 +132,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
return SelectivePrivacySettingsSection.forwards.rawValue
|
||||
case .settingHeader, .everybody, .contacts, .nobody, .settingInfo:
|
||||
return SelectivePrivacySettingsSection.setting.rawValue
|
||||
case .setPublicPhoto, .removePublicPhoto, .publicPhotoInfo:
|
||||
return SelectivePrivacySettingsSection.photo.rawValue
|
||||
case .exceptionsHeader, .disableFor, .enableFor, .peersInfo:
|
||||
return SelectivePrivacySettingsSection.peers.rawValue
|
||||
case .callsP2PHeader, .callsP2PAlways, .callsP2PContacts, .callsP2PNever, .callsP2PInfo:
|
||||
@ -150,42 +163,48 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
return 5
|
||||
case .settingInfo:
|
||||
return 6
|
||||
case .phoneDiscoveryHeader:
|
||||
case .setPublicPhoto:
|
||||
return 7
|
||||
case .phoneDiscoveryEverybody:
|
||||
case .removePublicPhoto:
|
||||
return 8
|
||||
case .phoneDiscoveryMyContacts:
|
||||
case .publicPhotoInfo:
|
||||
return 9
|
||||
case .phoneDiscoveryInfo:
|
||||
case .phoneDiscoveryHeader:
|
||||
return 10
|
||||
case .exceptionsHeader:
|
||||
case .phoneDiscoveryEverybody:
|
||||
return 11
|
||||
case .disableFor:
|
||||
case .phoneDiscoveryMyContacts:
|
||||
return 12
|
||||
case .enableFor:
|
||||
case .phoneDiscoveryInfo:
|
||||
return 13
|
||||
case .peersInfo:
|
||||
case .exceptionsHeader:
|
||||
return 14
|
||||
case .callsP2PHeader:
|
||||
case .disableFor:
|
||||
return 15
|
||||
case .callsP2PAlways:
|
||||
case .enableFor:
|
||||
return 16
|
||||
case .callsP2PContacts:
|
||||
case .peersInfo:
|
||||
return 17
|
||||
case .callsP2PNever:
|
||||
case .callsP2PHeader:
|
||||
return 18
|
||||
case .callsP2PInfo:
|
||||
case .callsP2PAlways:
|
||||
return 19
|
||||
case .callsP2PDisableFor:
|
||||
case .callsP2PContacts:
|
||||
return 20
|
||||
case .callsP2PEnableFor:
|
||||
case .callsP2PNever:
|
||||
return 21
|
||||
case .callsP2PPeersInfo:
|
||||
case .callsP2PInfo:
|
||||
return 22
|
||||
case .callsIntegrationEnabled:
|
||||
case .callsP2PDisableFor:
|
||||
return 23
|
||||
case .callsIntegrationInfo:
|
||||
case .callsP2PEnableFor:
|
||||
return 24
|
||||
case .callsP2PPeersInfo:
|
||||
return 25
|
||||
case .callsIntegrationEnabled:
|
||||
return 26
|
||||
case .callsIntegrationInfo:
|
||||
return 27
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,7 +241,25 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
return false
|
||||
}
|
||||
case let .nobody(lhsTheme, lhsText, lhsValue):
|
||||
if case let nobody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
if case let .nobody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .setPublicPhoto(lhsTheme, lhsText):
|
||||
if case let .setPublicPhoto(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .removePublicPhoto(lhsTheme, lhsText, lhsPeer, lhsRep):
|
||||
if case let .removePublicPhoto(rhsTheme, rhsText, rhsPeer, rhsRep) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsPeer == rhsPeer, lhsRep == rhsRep {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .publicPhotoInfo(lhsTheme, lhsText):
|
||||
if case let .publicPhotoInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -373,6 +410,17 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
|
||||
arguments.copyPhoneLink?(link)
|
||||
})
|
||||
case let .setPublicPhoto(theme, text):
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addPhotoIcon(theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: {
|
||||
arguments.setPublicPhoto?()
|
||||
})
|
||||
case let .removePublicPhoto(theme, text, _, _):
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.deleteIconImage(theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: {
|
||||
arguments.removePublicPhoto?()
|
||||
})
|
||||
case let .publicPhotoInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
|
||||
})
|
||||
case let .exceptionsHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .disableFor(_, title, value):
|
||||
@ -539,7 +587,7 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func selectivePrivacySettingsControllerEntries(presentationData: PresentationData, kind: SelectivePrivacySettingsKind, state: SelectivePrivacySettingsControllerState, peerName: String, phoneNumber: String) -> [SelectivePrivacySettingsEntry] {
|
||||
private func selectivePrivacySettingsControllerEntries(presentationData: PresentationData, kind: SelectivePrivacySettingsKind, state: SelectivePrivacySettingsControllerState, peerName: String, phoneNumber: String, peer: EnginePeer?, publicPhoto: TelegramMediaImage?) -> [SelectivePrivacySettingsEntry] {
|
||||
var entries: [SelectivePrivacySettingsEntry] = []
|
||||
|
||||
let settingTitle: String
|
||||
@ -628,6 +676,16 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
entries.append(.phoneDiscoveryInfo(presentationData.theme, state.phoneDiscoveryEnabled != false ? presentationData.strings.PrivacyPhoneNumberSettings_CustomPublicLink("+\(phoneNumber)").string : presentationData.strings.PrivacyPhoneNumberSettings_CustomDisabledHelp, phoneLink))
|
||||
}
|
||||
|
||||
if case .profilePhoto = kind, let peer = peer {
|
||||
if let publicPhoto = publicPhoto {
|
||||
entries.append(.setPublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_UpdatePublicPhoto))
|
||||
entries.append(.removePublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_RemovePublicPhoto, peer, publicPhoto))
|
||||
} else {
|
||||
entries.append(.setPublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_SetPublicPhoto))
|
||||
}
|
||||
entries.append(.publicPhotoInfo(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_PublicPhotoInfo))
|
||||
}
|
||||
|
||||
entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_Exceptions))
|
||||
|
||||
switch state.setting {
|
||||
@ -671,7 +729,18 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
return entries
|
||||
}
|
||||
|
||||
func selectivePrivacySettingsController(context: AccountContext, kind: SelectivePrivacySettingsKind, current: SelectivePrivacySettings, callSettings: (SelectivePrivacySettings, VoiceCallSettings)? = nil, phoneDiscoveryEnabled: Bool? = nil, voipConfiguration: VoipConfiguration? = nil, callIntegrationAvailable: Bool? = nil, updated: @escaping (SelectivePrivacySettings, (SelectivePrivacySettings, VoiceCallSettings)?, Bool?) -> Void) -> ViewController {
|
||||
func selectivePrivacySettingsController(
|
||||
context: AccountContext,
|
||||
kind: SelectivePrivacySettingsKind,
|
||||
current: SelectivePrivacySettings,
|
||||
callSettings: (SelectivePrivacySettings, VoiceCallSettings)? = nil,
|
||||
phoneDiscoveryEnabled: Bool? = nil,
|
||||
voipConfiguration: VoipConfiguration? = nil,
|
||||
callIntegrationAvailable: Bool? = nil,
|
||||
requestPublicPhotoSetup: (() -> Void)? = nil,
|
||||
requestPublicPhotoRemove: (() -> Void)? = nil,
|
||||
updated: @escaping (SelectivePrivacySettings, (SelectivePrivacySettings, VoiceCallSettings)?, Bool?) -> Void
|
||||
) -> ViewController {
|
||||
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||
|
||||
var initialEnableFor: [PeerId: SelectivePrivacyPeer] = [:]
|
||||
@ -965,12 +1034,29 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}, setPublicPhoto: {
|
||||
requestPublicPhotoSetup?()
|
||||
}, removePublicPhoto: {
|
||||
requestPublicPhotoRemove?()
|
||||
})
|
||||
|
||||
let peer = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
let peer = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
let publicPhoto = context.account.postbox.peerView(id: context.account.peerId)
|
||||
|> map { view -> TelegramMediaImage? in
|
||||
if let cachedUserData = view.cachedData as? CachedUserData, case let .known(photo) = cachedUserData.fallbackPhoto {
|
||||
return photo
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peer) |> deliverOnMainQueue
|
||||
|> map { presentationData, state, peer -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let signal = combineLatest(
|
||||
context.sharedContext.presentationData,
|
||||
statePromise.get(),
|
||||
peer,
|
||||
publicPhoto
|
||||
) |> deliverOnMainQueue
|
||||
|> map { presentationData, state, peer, publicPhoto -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let peerName = peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
var phoneNumber = ""
|
||||
if case let .user(user) = peer {
|
||||
@ -995,7 +1081,7 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
|
||||
title = presentationData.strings.Privacy_VoiceMessages
|
||||
}
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber), style: .blocks, animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber, peer: peer, publicPhoto: publicPhoto), style: .blocks, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
} |> afterDisposed {
|
||||
|
@ -427,6 +427,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[940666592] = { return Api.Message.parse_message($0) }
|
||||
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
|
||||
dict[721967202] = { return Api.Message.parse_messageService($0) }
|
||||
dict[-404267113] = { return Api.MessageAction.parse_messageActionAttachMenuBotAllowed($0) }
|
||||
dict[-1410748418] = { return Api.MessageAction.parse_messageActionBotAllowed($0) }
|
||||
dict[-1781355374] = { return Api.MessageAction.parse_messageActionChannelCreate($0) }
|
||||
dict[-365344535] = { return Api.MessageAction.parse_messageActionChannelMigrateFrom($0) }
|
||||
@ -886,7 +887,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
|
||||
dict[-1885878744] = { return Api.User.parse_user($0) }
|
||||
dict[-742634630] = { return Api.User.parse_userEmpty($0) }
|
||||
dict[-328384029] = { return Api.UserFull.parse_userFull($0) }
|
||||
dict[-120378643] = { return Api.UserFull.parse_userFull($0) }
|
||||
dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) }
|
||||
dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) }
|
||||
dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) }
|
||||
|
@ -988,6 +988,7 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum MessageAction: TypeConstructorDescription {
|
||||
case messageActionAttachMenuBotAllowed
|
||||
case messageActionBotAllowed(domain: String)
|
||||
case messageActionChannelCreate(title: String)
|
||||
case messageActionChannelMigrateFrom(title: String, chatId: Int64)
|
||||
@ -1027,6 +1028,12 @@ public extension Api {
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .messageActionAttachMenuBotAllowed:
|
||||
if boxed {
|
||||
buffer.appendInt32(-404267113)
|
||||
}
|
||||
|
||||
break
|
||||
case .messageActionBotAllowed(let domain):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1410748418)
|
||||
@ -1302,6 +1309,8 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .messageActionAttachMenuBotAllowed:
|
||||
return ("messageActionAttachMenuBotAllowed", [])
|
||||
case .messageActionBotAllowed(let domain):
|
||||
return ("messageActionBotAllowed", [("domain", String(describing: domain))])
|
||||
case .messageActionChannelCreate(let title):
|
||||
@ -1377,6 +1386,9 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_messageActionAttachMenuBotAllowed(_ reader: BufferReader) -> MessageAction? {
|
||||
return Api.MessageAction.messageActionAttachMenuBotAllowed
|
||||
}
|
||||
public static func parse_messageActionBotAllowed(_ reader: BufferReader) -> MessageAction? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
|
@ -586,13 +586,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum UserFull: TypeConstructorDescription {
|
||||
case userFull(flags: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, premiumGifts: [Api.PremiumGiftOption]?)
|
||||
case userFull(flags: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, premiumGifts: [Api.PremiumGiftOption]?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .userFull(let flags, let id, let about, let settings, let personalPhoto, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts):
|
||||
case .userFull(let flags, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts):
|
||||
if boxed {
|
||||
buffer.appendInt32(-328384029)
|
||||
buffer.appendInt32(-120378643)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
@ -600,6 +600,7 @@ public extension Api {
|
||||
settings.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 21) != 0 {personalPhoto!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {profilePhoto!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 22) != 0 {fallbackPhoto!.serialize(buffer, true)}
|
||||
notifySettings.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 3) != 0 {botInfo!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
|
||||
@ -621,8 +622,8 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .userFull(let flags, let id, let about, let settings, let personalPhoto, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts):
|
||||
return ("userFull", [("flags", String(describing: flags)), ("id", String(describing: id)), ("about", String(describing: about)), ("settings", String(describing: settings)), ("personalPhoto", String(describing: personalPhoto)), ("profilePhoto", String(describing: profilePhoto)), ("notifySettings", String(describing: notifySettings)), ("botInfo", String(describing: botInfo)), ("pinnedMsgId", String(describing: pinnedMsgId)), ("commonChatsCount", String(describing: commonChatsCount)), ("folderId", String(describing: folderId)), ("ttlPeriod", String(describing: ttlPeriod)), ("themeEmoticon", String(describing: themeEmoticon)), ("privateForwardName", String(describing: privateForwardName)), ("botGroupAdminRights", String(describing: botGroupAdminRights)), ("botBroadcastAdminRights", String(describing: botBroadcastAdminRights)), ("premiumGifts", String(describing: premiumGifts))])
|
||||
case .userFull(let flags, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts):
|
||||
return ("userFull", [("flags", String(describing: flags)), ("id", String(describing: id)), ("about", String(describing: about)), ("settings", String(describing: settings)), ("personalPhoto", String(describing: personalPhoto)), ("profilePhoto", String(describing: profilePhoto)), ("fallbackPhoto", String(describing: fallbackPhoto)), ("notifySettings", String(describing: notifySettings)), ("botInfo", String(describing: botInfo)), ("pinnedMsgId", String(describing: pinnedMsgId)), ("commonChatsCount", String(describing: commonChatsCount)), ("folderId", String(describing: folderId)), ("ttlPeriod", String(describing: ttlPeriod)), ("themeEmoticon", String(describing: themeEmoticon)), ("privateForwardName", String(describing: privateForwardName)), ("botGroupAdminRights", String(describing: botGroupAdminRights)), ("botBroadcastAdminRights", String(describing: botBroadcastAdminRights)), ("premiumGifts", String(describing: premiumGifts))])
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,37 +646,41 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||
_6 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||
} }
|
||||
var _7: Api.PeerNotifySettings?
|
||||
var _7: Api.Photo?
|
||||
if Int(_1!) & Int(1 << 22) != 0 {if let signature = reader.readInt32() {
|
||||
_7 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||
} }
|
||||
var _8: Api.PeerNotifySettings?
|
||||
if let signature = reader.readInt32() {
|
||||
_7 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
||||
}
|
||||
var _8: Api.BotInfo?
|
||||
var _9: Api.BotInfo?
|
||||
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.BotInfo
|
||||
_9 = Api.parse(reader, signature: signature) as? Api.BotInfo
|
||||
} }
|
||||
var _9: Int32?
|
||||
if Int(_1!) & Int(1 << 6) != 0 {_9 = reader.readInt32() }
|
||||
var _10: Int32?
|
||||
_10 = reader.readInt32()
|
||||
if Int(_1!) & Int(1 << 6) != 0 {_10 = reader.readInt32() }
|
||||
var _11: Int32?
|
||||
if Int(_1!) & Int(1 << 11) != 0 {_11 = reader.readInt32() }
|
||||
_11 = reader.readInt32()
|
||||
var _12: Int32?
|
||||
if Int(_1!) & Int(1 << 14) != 0 {_12 = reader.readInt32() }
|
||||
var _13: String?
|
||||
if Int(_1!) & Int(1 << 15) != 0 {_13 = parseString(reader) }
|
||||
if Int(_1!) & Int(1 << 11) != 0 {_12 = reader.readInt32() }
|
||||
var _13: Int32?
|
||||
if Int(_1!) & Int(1 << 14) != 0 {_13 = reader.readInt32() }
|
||||
var _14: String?
|
||||
if Int(_1!) & Int(1 << 16) != 0 {_14 = parseString(reader) }
|
||||
var _15: Api.ChatAdminRights?
|
||||
if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
|
||||
_15 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
|
||||
} }
|
||||
if Int(_1!) & Int(1 << 15) != 0 {_14 = parseString(reader) }
|
||||
var _15: String?
|
||||
if Int(_1!) & Int(1 << 16) != 0 {_15 = parseString(reader) }
|
||||
var _16: Api.ChatAdminRights?
|
||||
if Int(_1!) & Int(1 << 18) != 0 {if let signature = reader.readInt32() {
|
||||
if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
|
||||
_16 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
|
||||
} }
|
||||
var _17: [Api.PremiumGiftOption]?
|
||||
var _17: Api.ChatAdminRights?
|
||||
if Int(_1!) & Int(1 << 18) != 0 {if let signature = reader.readInt32() {
|
||||
_17 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
|
||||
} }
|
||||
var _18: [Api.PremiumGiftOption]?
|
||||
if Int(_1!) & Int(1 << 19) != 0 {if let _ = reader.readInt32() {
|
||||
_17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PremiumGiftOption.self)
|
||||
_18 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PremiumGiftOption.self)
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
@ -683,19 +688,20 @@ public extension Api {
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 21) == 0) || _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
|
||||
let _c7 = _7 != nil
|
||||
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
||||
let _c10 = _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 11) == 0) || _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 14) == 0) || _12 != nil
|
||||
let _c13 = (Int(_1!) & Int(1 << 15) == 0) || _13 != nil
|
||||
let _c14 = (Int(_1!) & Int(1 << 16) == 0) || _14 != nil
|
||||
let _c15 = (Int(_1!) & Int(1 << 17) == 0) || _15 != nil
|
||||
let _c16 = (Int(_1!) & Int(1 << 18) == 0) || _16 != nil
|
||||
let _c17 = (Int(_1!) & Int(1 << 19) == 0) || _17 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 {
|
||||
return Api.UserFull.userFull(flags: _1!, id: _2!, about: _3, settings: _4!, personalPhoto: _5, profilePhoto: _6, notifySettings: _7!, botInfo: _8, pinnedMsgId: _9, commonChatsCount: _10!, folderId: _11, ttlPeriod: _12, themeEmoticon: _13, privateForwardName: _14, botGroupAdminRights: _15, botBroadcastAdminRights: _16, premiumGifts: _17)
|
||||
let _c7 = (Int(_1!) & Int(1 << 22) == 0) || _7 != nil
|
||||
let _c8 = _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 3) == 0) || _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 6) == 0) || _10 != nil
|
||||
let _c11 = _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 11) == 0) || _12 != nil
|
||||
let _c13 = (Int(_1!) & Int(1 << 14) == 0) || _13 != nil
|
||||
let _c14 = (Int(_1!) & Int(1 << 15) == 0) || _14 != nil
|
||||
let _c15 = (Int(_1!) & Int(1 << 16) == 0) || _15 != nil
|
||||
let _c16 = (Int(_1!) & Int(1 << 17) == 0) || _16 != nil
|
||||
let _c17 = (Int(_1!) & Int(1 << 18) == 0) || _17 != nil
|
||||
let _c18 = (Int(_1!) & Int(1 << 19) == 0) || _18 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 {
|
||||
return Api.UserFull.userFull(flags: _1!, id: _2!, about: _3, settings: _4!, personalPhoto: _5, profilePhoto: _6, fallbackPhoto: _7, notifySettings: _8!, botInfo: _9, pinnedMsgId: _10, commonChatsCount: _11!, folderId: _12, ttlPeriod: _13, themeEmoticon: _14, privateForwardName: _15, botGroupAdminRights: _16, botBroadcastAdminRights: _17, premiumGifts: _18)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -6559,12 +6559,13 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func toggleBotInAttachMenu(bot: Api.InputUser, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
static func toggleBotInAttachMenu(flags: Int32, bot: Api.InputUser, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(451818415)
|
||||
buffer.appendInt32(1777704297)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
bot.serialize(buffer, true)
|
||||
enabled.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "messages.toggleBotInAttachMenu", parameters: [("bot", String(describing: bot)), ("enabled", String(describing: enabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
return (FunctionDescription(name: "messages.toggleBotInAttachMenu", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("enabled", String(describing: enabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -7548,11 +7549,12 @@ public extension Api.functions.photos {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.photos {
|
||||
static func updateProfilePhoto(id: Api.InputPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.photos.Photo>) {
|
||||
static func updateProfilePhoto(flags: Int32, id: Api.InputPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.photos.Photo>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1926525996)
|
||||
buffer.appendInt32(473782614)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
id.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "photos.updateProfilePhoto", parameters: [("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in
|
||||
return (FunctionDescription(name: "photos.updateProfilePhoto", parameters: [("flags", String(describing: flags)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.photos.Photo?
|
||||
if let signature = reader.readInt32() {
|
||||
|
@ -1254,7 +1254,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: EnginePeer(participant.peer), text: text, action: nil), action: { _ in return false })
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: EnginePeer(participant.peer), text: text, action: nil, duration: 3), action: { _ in return false })
|
||||
}
|
||||
} else {
|
||||
if case let .channel(groupPeer) = groupPeer, let listenerLink = inviteLinks?.listenerLink, !groupPeer.hasPermission(.inviteMembers) {
|
||||
@ -1362,7 +1362,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text, action: nil), action: { _ in return false })
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text, action: nil, duration: 3), action: { _ in return false })
|
||||
}
|
||||
}))
|
||||
} else if case let .legacyGroup(groupPeer) = groupPeer {
|
||||
@ -1430,7 +1430,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text, action: nil), action: { _ in return false })
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text, action: nil, duration: 3), action: { _ in return false })
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -2262,7 +2262,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
return
|
||||
}
|
||||
let text = strongSelf.presentationData.strings.VoiceChat_PeerJoinedText(EnginePeer(event.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: EnginePeer(event.peer), text: text, action: nil), action: { _ in return false })
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: EnginePeer(event.peer), text: text, action: nil, duration: 3), action: { _ in return false })
|
||||
}
|
||||
}))
|
||||
|
||||
@ -2277,7 +2277,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_DisplayAsSuccess(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: EnginePeer(peer), text: text, action: nil), action: { _ in return false })
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: EnginePeer(peer), text: text, action: nil, duration: 3), action: { _ in return false })
|
||||
}))
|
||||
|
||||
self.stateVersionDisposable.set((self.call.stateVersion
|
||||
|
@ -76,6 +76,9 @@ extension ReplyMarkupMessageAttribute {
|
||||
if (markupFlags & (1 << 2)) != 0 {
|
||||
flags.insert(.personal)
|
||||
}
|
||||
if (markupFlags & (1 << 4)) != 0 {
|
||||
flags.insert(.persistent)
|
||||
}
|
||||
placeholder = apiPlaceholder
|
||||
case let .replyInlineMarkup(apiRows):
|
||||
rows = apiRows.map { ReplyMarkupRow(apiRow: $0) }
|
||||
|
@ -205,7 +205,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
||||
}
|
||||
|
||||
switch action {
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto:
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionAttachMenuBotAllowed:
|
||||
break
|
||||
case let .messageActionChannelMigrateFrom(_, chatId):
|
||||
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId)))
|
||||
|
@ -106,6 +106,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return TelegramMediaAction(action: .topicEdited(components: components))
|
||||
case let.messageActionSuggestProfilePhoto(photo):
|
||||
return TelegramMediaAction(action: .suggestedProfilePhoto(image: telegramMediaImageFromApiPhoto(photo)))
|
||||
case .messageActionAttachMenuBotAllowed:
|
||||
return TelegramMediaAction(action: .attachMenuBotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
public let themeEmoticon: String?
|
||||
public let photo: CachedPeerProfilePhoto
|
||||
public let personalPhoto: CachedPeerProfilePhoto
|
||||
public let fallbackPhoto: CachedPeerProfilePhoto
|
||||
public let premiumGiftOptions: [CachedPremiumGiftOption]
|
||||
public let voiceMessagesAvailable: Bool
|
||||
|
||||
@ -176,13 +177,14 @@ public final class CachedUserData: CachedPeerData {
|
||||
self.themeEmoticon = nil
|
||||
self.photo = .unknown
|
||||
self.personalPhoto = .unknown
|
||||
self.fallbackPhoto = .unknown
|
||||
self.premiumGiftOptions = []
|
||||
self.voiceMessagesAvailable = true
|
||||
self.peerIds = Set()
|
||||
self.messageIds = Set()
|
||||
}
|
||||
|
||||
public init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, premiumGiftOptions: [CachedPremiumGiftOption], voiceMessagesAvailable: Bool) {
|
||||
public init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, premiumGiftOptions: [CachedPremiumGiftOption], voiceMessagesAvailable: Bool) {
|
||||
self.about = about
|
||||
self.botInfo = botInfo
|
||||
self.peerStatusSettings = peerStatusSettings
|
||||
@ -198,6 +200,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
self.themeEmoticon = themeEmoticon
|
||||
self.photo = photo
|
||||
self.personalPhoto = personalPhoto
|
||||
self.fallbackPhoto = fallbackPhoto
|
||||
self.premiumGiftOptions = premiumGiftOptions
|
||||
self.voiceMessagesAvailable = voiceMessagesAvailable
|
||||
|
||||
@ -237,6 +240,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
|
||||
self.photo = decoder.decodeObjectForKey("phv", decoder: CachedPeerProfilePhoto.init(decoder:)) as? CachedPeerProfilePhoto ?? .unknown
|
||||
self.personalPhoto = decoder.decodeObjectForKey("pphv", decoder: CachedPeerProfilePhoto.init(decoder:)) as? CachedPeerProfilePhoto ?? .unknown
|
||||
self.fallbackPhoto = decoder.decodeObjectForKey("fphv", decoder: CachedPeerProfilePhoto.init(decoder:)) as? CachedPeerProfilePhoto ?? .unknown
|
||||
|
||||
self.premiumGiftOptions = decoder.decodeObjectArrayWithDecoderForKey("pgo") as [CachedPremiumGiftOption]
|
||||
self.voiceMessagesAvailable = decoder.decodeInt32ForKey("vma", orElse: 0) != 0
|
||||
@ -291,6 +295,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
|
||||
encoder.encodeObject(self.photo, forKey: "phv")
|
||||
encoder.encodeObject(self.personalPhoto, forKey: "pphv")
|
||||
encoder.encodeObject(self.fallbackPhoto, forKey: "fphv")
|
||||
|
||||
encoder.encodeObjectArray(self.premiumGiftOptions, forKey: "pgo")
|
||||
encoder.encodeInt32(self.voiceMessagesAvailable ? 1 : 0, forKey: "vma")
|
||||
@ -308,74 +313,78 @@ public final class CachedUserData: CachedPeerData {
|
||||
return false
|
||||
}
|
||||
|
||||
return other.about == self.about && other.botInfo == self.botInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.voiceCallsAvailable == other.voiceCallsAvailable && self.videoCallsAvailable == other.videoCallsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.themeEmoticon == other.themeEmoticon && self.photo == other.photo && self.personalPhoto == other.personalPhoto && self.premiumGiftOptions == other.premiumGiftOptions && self.voiceMessagesAvailable == other.voiceMessagesAvailable
|
||||
return other.about == self.about && other.botInfo == self.botInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.voiceCallsAvailable == other.voiceCallsAvailable && self.videoCallsAvailable == other.videoCallsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.themeEmoticon == other.themeEmoticon && self.photo == other.photo && self.personalPhoto == other.personalPhoto && self.fallbackPhoto == other.fallbackPhoto && self.premiumGiftOptions == other.premiumGiftOptions && self.voiceMessagesAvailable == other.voiceMessagesAvailable
|
||||
}
|
||||
|
||||
public func withUpdatedAbout(_ about: String?) -> CachedUserData {
|
||||
return CachedUserData(about: about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedBotInfo(_ botInfo: BotInfo?) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedIsBlocked(_ isBlocked: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedCommonGroupCount(_ commonGroupCount: Int32) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedVoiceCallsAvailable(_ voiceCallsAvailable: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedVideoCallsAvailable(_ videoCallsAvailable: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedCallsPrivate(_ callsPrivate: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedCanPinMessages(_ canPinMessages: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedAutoremoveTimeout(_ autoremoveTimeout: CachedPeerAutoremoveTimeout) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedThemeEmoticon(_ themeEmoticon: String?) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedPhoto(_ photo: CachedPeerProfilePhoto) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedPersonalPhoto(_ personalPhoto: CachedPeerProfilePhoto) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedFallbackPhoto(_ fallbackPhoto: CachedPeerProfilePhoto) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedPremiumGiftOptions(_ premiumGiftOptions: [CachedPremiumGiftOption]) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable)
|
||||
}
|
||||
|
||||
public func withUpdatedVoiceMessagesAvailable(_ voiceMessagesAvailable: Bool) -> CachedUserData {
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: voiceMessagesAvailable)
|
||||
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: voiceMessagesAvailable)
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +158,7 @@ public struct ReplyMarkupMessageFlags: OptionSet {
|
||||
public static let setupReply = ReplyMarkupMessageFlags(rawValue: 1 << 2)
|
||||
public static let inline = ReplyMarkupMessageFlags(rawValue: 1 << 3)
|
||||
public static let fit = ReplyMarkupMessageFlags(rawValue: 1 << 4)
|
||||
public static let persistent = ReplyMarkupMessageFlags(rawValue: 1 << 5)
|
||||
}
|
||||
|
||||
public class ReplyMarkupMessageAttribute: MessageAttribute, Equatable {
|
||||
|
@ -99,6 +99,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case topicCreated(title: String, iconColor: Int32, iconFileId: Int64?)
|
||||
case topicEdited(components: [ForumTopicEditComponent])
|
||||
case suggestedProfilePhoto(image: TelegramMediaImage?)
|
||||
case attachMenuBotAllowed
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
||||
@ -175,6 +176,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
self = .topicEdited(components: decoder.decodeObjectArrayWithDecoderForKey("components"))
|
||||
case 30:
|
||||
self = .suggestedProfilePhoto(image: decoder.decodeObjectForKey("image") as? TelegramMediaImage)
|
||||
case 31:
|
||||
self = .attachMenuBotAllowed
|
||||
default:
|
||||
self = .unknown
|
||||
}
|
||||
@ -326,6 +329,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
if let image = image {
|
||||
encoder.encodeObject(image, forKey: "image")
|
||||
}
|
||||
case .attachMenuBotAllowed:
|
||||
encoder.encodeInt32(31, forKey: "_rawValue")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public extension TelegramEngine {
|
||||
}
|
||||
|
||||
public func updateAccountPhoto(resource: MediaResource?, videoResource: MediaResource?, videoStartTimestamp: Double?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return _internal_updateAccountPhoto(account: self.account, resource: resource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
return _internal_updateAccountPhoto(account: self.account, resource: resource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, fallback: false, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
}
|
||||
|
||||
public func updatePeerPhotoExisting(reference: TelegramMediaImageReference) -> Signal<TelegramMediaImage?, NoError> {
|
||||
@ -52,7 +52,15 @@ public extension TelegramEngine {
|
||||
}
|
||||
|
||||
public func removeAccountPhoto(reference: TelegramMediaImageReference?) -> Signal<Void, NoError> {
|
||||
return _internal_removeAccountPhoto(network: self.account.network, reference: reference)
|
||||
return _internal_removeAccountPhoto(account: self.account, reference: reference, fallback: false)
|
||||
}
|
||||
|
||||
public func updateFallbackPhoto(resource: MediaResource?, videoResource: MediaResource?, videoStartTimestamp: Double?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return _internal_updateAccountPhoto(account: self.account, resource: resource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, fallback: true, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
}
|
||||
|
||||
public func removeFallbackPhoto(reference: TelegramMediaImageReference?) -> Signal<Void, NoError> {
|
||||
return _internal_removeAccountPhoto(account: self.account, reference: reference, fallback: true)
|
||||
}
|
||||
|
||||
public func setEmojiStatus(file: TelegramMediaFile?, expirationDate: Int32?) -> Signal<Never, NoError> {
|
||||
|
@ -11,6 +11,7 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
case botIcons
|
||||
case peerTypes
|
||||
case hasSettings
|
||||
case flags
|
||||
}
|
||||
|
||||
public enum IconName: Int32, Codable {
|
||||
@ -38,6 +39,21 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct Flags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public init() {
|
||||
self.rawValue = 0
|
||||
}
|
||||
|
||||
public static let hasSettings = Flags(rawValue: 1 << 0)
|
||||
public static let requiresWriteAccess = Flags(rawValue: 1 << 1)
|
||||
}
|
||||
|
||||
public struct PeerFlags: OptionSet, Codable {
|
||||
public var rawValue: UInt32
|
||||
|
||||
@ -94,20 +110,20 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
public let name: String
|
||||
public let icons: [IconName: TelegramMediaFile]
|
||||
public let peerTypes: PeerFlags
|
||||
public let hasSettings: Bool
|
||||
public let flags: Flags
|
||||
|
||||
public init(
|
||||
peerId: PeerId,
|
||||
name: String,
|
||||
icons: [IconName: TelegramMediaFile],
|
||||
peerTypes: PeerFlags,
|
||||
hasSettings: Bool
|
||||
flags: Flags
|
||||
) {
|
||||
self.peerId = peerId
|
||||
self.name = name
|
||||
self.icons = icons
|
||||
self.peerTypes = peerTypes
|
||||
self.hasSettings = hasSettings
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
public static func ==(lhs: Bot, rhs: Bot) -> Bool {
|
||||
@ -123,7 +139,7 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
if lhs.peerTypes != rhs.peerTypes {
|
||||
return false
|
||||
}
|
||||
if lhs.hasSettings != rhs.hasSettings {
|
||||
if lhs.flags != rhs.flags {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@ -147,7 +163,12 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
let value = try container.decodeIfPresent(Int32.self, forKey: .peerTypes) ?? Int32(PeerFlags.default.rawValue)
|
||||
self.peerTypes = PeerFlags(rawValue: UInt32(value))
|
||||
|
||||
self.hasSettings = try container.decodeIfPresent(Bool.self, forKey: .hasSettings) ?? false
|
||||
if let flags = try container.decodeIfPresent(Int32.self, forKey: .flags) {
|
||||
self.flags = Flags(rawValue: flags)
|
||||
} else {
|
||||
let hasSettings = try container.decodeIfPresent(Bool.self, forKey: .hasSettings) ?? false
|
||||
self.flags = hasSettings ? [.hasSettings] : []
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -164,7 +185,7 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
|
||||
try container.encode(Int32(self.peerTypes.rawValue), forKey: .peerTypes)
|
||||
|
||||
try container.encode(self.hasSettings, forKey: .hasSettings)
|
||||
try container.encode(Int32(self.flags.rawValue), forKey: .flags)
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,7 +297,7 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network, force:
|
||||
var resultBots: [AttachMenuBots.Bot] = []
|
||||
for bot in bots {
|
||||
switch bot {
|
||||
case let .attachMenuBot(flags, botId, name, apiPeerTypes, botIcons):
|
||||
case let .attachMenuBot(apiFlags, botId, name, apiPeerTypes, botIcons):
|
||||
var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:]
|
||||
for icon in botIcons {
|
||||
switch icon {
|
||||
@ -302,7 +323,14 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network, force:
|
||||
peerTypes.insert(.channel)
|
||||
}
|
||||
}
|
||||
resultBots.append(AttachMenuBots.Bot(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), name: name, icons: icons, peerTypes: peerTypes, hasSettings: (flags & (1 << 1)) != 0))
|
||||
var flags: AttachMenuBots.Bot.Flags = []
|
||||
if (apiFlags & (1 << 1)) != 0 {
|
||||
flags.insert(.hasSettings)
|
||||
}
|
||||
if (apiFlags & (1 << 2)) != 0 {
|
||||
flags.insert(.requiresWriteAccess)
|
||||
}
|
||||
resultBots.append(AttachMenuBots.Bot(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), name: name, icons: icons, peerTypes: peerTypes, flags: flags))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,12 +368,16 @@ public enum AddBotToAttachMenuError {
|
||||
}
|
||||
|
||||
|
||||
func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, botId: PeerId) -> Signal<Bool, AddBotToAttachMenuError> {
|
||||
func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, botId: PeerId, allowWrite: Bool) -> Signal<Bool, AddBotToAttachMenuError> {
|
||||
return postbox.transaction { transaction -> Signal<Bool, AddBotToAttachMenuError> in
|
||||
guard let peer = transaction.getPeer(botId), let inputUser = apiInputUser(peer) else {
|
||||
return .complete()
|
||||
}
|
||||
return network.request(Api.functions.messages.toggleBotInAttachMenu(bot: inputUser, enabled: .boolTrue))
|
||||
var flags: Int32 = 0
|
||||
if allowWrite {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
return network.request(Api.functions.messages.toggleBotInAttachMenu(flags: flags, bot: inputUser, enabled: .boolTrue))
|
||||
|> map { value -> Bool in
|
||||
switch value {
|
||||
case .boolTrue:
|
||||
@ -379,7 +411,7 @@ func _internal_removeBotFromAttachMenu(postbox: Postbox, network: Network, botId
|
||||
guard let peer = transaction.getPeer(botId), let inputUser = apiInputUser(peer) else {
|
||||
return .complete()
|
||||
}
|
||||
return network.request(Api.functions.messages.toggleBotInAttachMenu(bot: inputUser, enabled: .boolFalse))
|
||||
return network.request(Api.functions.messages.toggleBotInAttachMenu(flags: 0, bot: inputUser, enabled: .boolFalse))
|
||||
|> map { value -> Bool in
|
||||
switch value {
|
||||
case .boolTrue:
|
||||
@ -406,14 +438,14 @@ public struct AttachMenuBot {
|
||||
public let shortName: String
|
||||
public let icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile]
|
||||
public let peerTypes: AttachMenuBots.Bot.PeerFlags
|
||||
public let hasSettings: Bool
|
||||
public let flags: AttachMenuBots.Bot.Flags
|
||||
|
||||
init(peer: Peer, shortName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], peerTypes: AttachMenuBots.Bot.PeerFlags, hasSettings: Bool) {
|
||||
init(peer: Peer, shortName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], peerTypes: AttachMenuBots.Bot.PeerFlags, flags: AttachMenuBots.Bot.Flags) {
|
||||
self.peer = peer
|
||||
self.shortName = shortName
|
||||
self.icons = icons
|
||||
self.peerTypes = peerTypes
|
||||
self.hasSettings = hasSettings
|
||||
self.flags = flags
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,7 +457,7 @@ func _internal_attachMenuBots(postbox: Postbox) -> Signal<[AttachMenuBot], NoErr
|
||||
var resultBots: [AttachMenuBot] = []
|
||||
for bot in cachedBots {
|
||||
if let peer = transaction.getPeer(bot.peerId) {
|
||||
resultBots.append(AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, hasSettings: bot.hasSettings))
|
||||
resultBots.append(AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, flags: bot.flags))
|
||||
}
|
||||
}
|
||||
return resultBots
|
||||
@ -440,7 +472,7 @@ public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId
|
||||
return postbox.transaction { transaction -> Signal<AttachMenuBot, GetAttachMenuBotError> in
|
||||
if cached, let cachedBots = cachedAttachMenuBots(transaction: transaction)?.bots {
|
||||
if let bot = cachedBots.first(where: { $0.peerId == botId }), let peer = transaction.getPeer(bot.peerId) {
|
||||
return .single(AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, hasSettings: bot.hasSettings))
|
||||
return .single(AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, flags: bot.flags))
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +506,7 @@ public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId
|
||||
}
|
||||
|
||||
switch bot {
|
||||
case let .attachMenuBot(flags, _, name, apiPeerTypes, botIcons):
|
||||
case let .attachMenuBot(apiFlags, _, name, apiPeerTypes, botIcons):
|
||||
var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:]
|
||||
for icon in botIcons {
|
||||
switch icon {
|
||||
@ -499,7 +531,14 @@ public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId
|
||||
peerTypes.insert(.channel)
|
||||
}
|
||||
}
|
||||
return .single(AttachMenuBot(peer: peer, shortName: name, icons: icons, peerTypes: peerTypes, hasSettings: (flags & (1 << 1)) != 0))
|
||||
var flags: AttachMenuBots.Bot.Flags = []
|
||||
if (apiFlags & (1 << 1)) != 0 {
|
||||
flags.insert(.hasSettings)
|
||||
}
|
||||
if (apiFlags & (1 << 2)) != 0 {
|
||||
flags.insert(.requiresWriteAccess)
|
||||
}
|
||||
return .single(AttachMenuBot(peer: peer, shortName: name, icons: icons, peerTypes: peerTypes, flags: flags))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,8 +395,8 @@ public extension TelegramEngine {
|
||||
return _internal_sendWebViewData(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, botId: botId, buttonText: buttonText, data: data)
|
||||
}
|
||||
|
||||
public func addBotToAttachMenu(botId: PeerId) -> Signal<Bool, AddBotToAttachMenuError> {
|
||||
return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, botId: botId)
|
||||
public func addBotToAttachMenu(botId: PeerId, allowWrite: Bool) -> Signal<Bool, AddBotToAttachMenuError> {
|
||||
return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, botId: botId, allowWrite: allowWrite)
|
||||
}
|
||||
|
||||
public func removeBotFromAttachMenu(botId: PeerId) -> Signal<Bool, NoError> {
|
||||
|
@ -14,8 +14,8 @@ public enum UploadPeerPhotoError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_updateAccountPhoto(account: Account, resource: MediaResource?, videoResource: MediaResource?, videoStartTimestamp: Double?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return _internal_updatePeerPhoto(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: account.peerId, photo: resource.flatMap({ _internal_uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: $0) }), video: videoResource.flatMap({ _internal_uploadedPeerVideo(postbox: account.postbox, network: account.network, messageMediaPreuploadManager: account.messageMediaPreuploadManager, resource: $0) |> map(Optional.init) }), videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
func _internal_updateAccountPhoto(account: Account, resource: MediaResource?, videoResource: MediaResource?, videoStartTimestamp: Double?, fallback: Bool, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return _internal_updatePeerPhoto(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: account.peerId, photo: resource.flatMap({ _internal_uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: $0) }), video: videoResource.flatMap({ _internal_uploadedPeerVideo(postbox: account.postbox, network: account.network, messageMediaPreuploadManager: account.messageMediaPreuploadManager, resource: $0) |> map(Optional.init) }), videoStartTimestamp: videoStartTimestamp, fallback: fallback, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
}
|
||||
|
||||
public enum SetCustomPeerPhotoMode {
|
||||
@ -76,11 +76,11 @@ func _internal_uploadedPeerVideo(postbox: Postbox, network: Network, messageMedi
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updatePeerPhoto(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peerId: PeerId, photo: Signal<UploadedPeerPhotoData, NoError>?, video: Signal<UploadedPeerPhotoData?, NoError>? = nil, videoStartTimestamp: Double? = nil, customPeerPhotoMode: SetCustomPeerPhotoMode? = nil, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return _internal_updatePeerPhotoInternal(postbox: postbox, network: network, stateManager: stateManager, accountPeerId: accountPeerId, peer: postbox.loadedPeerWithId(peerId), photo: photo, video: video, videoStartTimestamp: videoStartTimestamp, customPeerPhotoMode: customPeerPhotoMode, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
func _internal_updatePeerPhoto(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peerId: PeerId, photo: Signal<UploadedPeerPhotoData, NoError>?, video: Signal<UploadedPeerPhotoData?, NoError>? = nil, videoStartTimestamp: Double? = nil, fallback: Bool = false, customPeerPhotoMode: SetCustomPeerPhotoMode? = nil, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return _internal_updatePeerPhotoInternal(postbox: postbox, network: network, stateManager: stateManager, accountPeerId: accountPeerId, peer: postbox.loadedPeerWithId(peerId), photo: photo, video: video, videoStartTimestamp: videoStartTimestamp, fallback: fallback, customPeerPhotoMode: customPeerPhotoMode, mapResourceToAvatarSizes: mapResourceToAvatarSizes)
|
||||
}
|
||||
|
||||
func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peer: Signal<Peer, NoError>, photo: Signal<UploadedPeerPhotoData, NoError>?, video: Signal<UploadedPeerPhotoData?, NoError>?, videoStartTimestamp: Double?, customPeerPhotoMode: SetCustomPeerPhotoMode? = nil, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peer: Signal<Peer, NoError>, photo: Signal<UploadedPeerPhotoData, NoError>?, video: Signal<UploadedPeerPhotoData?, NoError>?, videoStartTimestamp: Double?, fallback: Bool = false, customPeerPhotoMode: SetCustomPeerPhotoMode? = nil, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
|
||||
return peer
|
||||
|> mapError { _ -> UploadPeerPhotoError in }
|
||||
|> mapToSignal { peer -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||
@ -150,9 +150,11 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
flags |= (1 << 2)
|
||||
}
|
||||
}
|
||||
|
||||
let request: Signal<Api.photos.Photo, MTRpcError>
|
||||
if peer.id == accountPeerId {
|
||||
if fallback {
|
||||
flags |= (1 << 3)
|
||||
}
|
||||
request = network.request(Api.functions.photos.uploadProfilePhoto(flags: flags, file: file, video: videoFile, videoStartTs: videoStartTimestamp))
|
||||
} else if let inputUser = apiInputUser(peer) {
|
||||
if let customPeerPhotoMode = customPeerPhotoMode {
|
||||
@ -177,8 +179,10 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
|> mapToSignal { photo -> Signal<(UpdatePeerPhotoStatus, MediaResource?, MediaResource?), UploadPeerPhotoError> in
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
var videoRepresentations: [TelegramMediaImage.VideoRepresentation] = []
|
||||
var image: TelegramMediaImage?
|
||||
switch photo {
|
||||
case let .photo(apiPhoto, _):
|
||||
image = telegramMediaImageFromApiPhoto(apiPhoto)
|
||||
switch apiPhoto {
|
||||
case .photoEmpty:
|
||||
break
|
||||
@ -225,7 +229,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
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 {
|
||||
if customPeerPhotoMode == .suggest || fallback {
|
||||
return peer
|
||||
} else {
|
||||
return peer.withUpdatedPhoto(representations)
|
||||
@ -234,6 +238,16 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
return peer
|
||||
}
|
||||
})
|
||||
|
||||
if fallback {
|
||||
transaction.updatePeerCachedData(peerIds: Set([peer.id])) { peerId, cachedPeerData in
|
||||
if let cachedPeerData = cachedPeerData as? CachedUserData {
|
||||
return cachedPeerData.withUpdatedFallbackPhoto(.known(image))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (.complete(representations), photoResult.resource, videoResult?.resource)
|
||||
} |> mapError { _ -> UploadPeerPhotoError in }
|
||||
@ -327,7 +341,11 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
if let _ = peer as? TelegramUser {
|
||||
let request: Signal<Api.photos.Photo, MTRpcError>
|
||||
if peer.id == accountPeerId {
|
||||
request = network.request(Api.functions.photos.updateProfilePhoto(id: Api.InputPhoto.inputPhotoEmpty))
|
||||
var flags: Int32 = 0
|
||||
if fallback {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
request = network.request(Api.functions.photos.updateProfilePhoto(flags: flags, id: Api.InputPhoto.inputPhotoEmpty))
|
||||
} else if let inputUser = apiInputUser(peer) {
|
||||
let flags: Int32 = (1 << 4)
|
||||
request = network.request(Api.functions.photos.uploadContactProfilePhoto(flags: flags, userId: inputUser, file: nil, video: nil, videoStartTs: nil))
|
||||
@ -350,6 +368,15 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
updatePeers(transaction: transaction, peers: updatedUsers, update: { (_, updatedPeer) -> Peer? in
|
||||
return updatedPeer
|
||||
})
|
||||
if fallback {
|
||||
transaction.updatePeerCachedData(peerIds: Set([peer.id])) { peerId, cachedPeerData in
|
||||
if let cachedPeerData = cachedPeerData as? CachedUserData {
|
||||
return cachedPeerData.withUpdatedFallbackPhoto(.known(nil))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return .complete([])
|
||||
} |> mapError { _ -> UploadPeerPhotoError in }
|
||||
}
|
||||
@ -405,7 +432,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
func _internal_updatePeerPhotoExisting(network: Network, reference: TelegramMediaImageReference) -> Signal<TelegramMediaImage?, NoError> {
|
||||
switch reference {
|
||||
case let .cloud(imageId, accessHash, fileReference):
|
||||
return network.request(Api.functions.photos.updateProfilePhoto(id: .inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))))
|
||||
return network.request(Api.functions.photos.updateProfilePhoto(flags: 0, id: .inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))))
|
||||
|> `catch` { _ -> Signal<Api.photos.Photo, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
@ -419,12 +446,12 @@ func _internal_updatePeerPhotoExisting(network: Network, reference: TelegramMedi
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_removeAccountPhoto(network: Network, reference: TelegramMediaImageReference?) -> Signal<Void, NoError> {
|
||||
func _internal_removeAccountPhoto(account: Account, reference: TelegramMediaImageReference?, fallback: Bool) -> Signal<Void, NoError> {
|
||||
if let reference = reference {
|
||||
switch reference {
|
||||
case let .cloud(imageId, accessHash, fileReference):
|
||||
if let fileReference = fileReference {
|
||||
return network.request(Api.functions.photos.deletePhotos(id: [.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))]))
|
||||
return account.network.request(Api.functions.photos.deletePhotos(id: [.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))]))
|
||||
|> `catch` { _ -> Signal<[Int64], NoError> in
|
||||
return .single([])
|
||||
}
|
||||
@ -436,7 +463,29 @@ func _internal_removeAccountPhoto(network: Network, reference: TelegramMediaImag
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let api = Api.functions.photos.updateProfilePhoto(id: Api.InputPhoto.inputPhotoEmpty)
|
||||
return network.request(api) |> map { _ in } |> retryRequest
|
||||
var flags: Int32 = 0
|
||||
if fallback {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
let api = Api.functions.photos.updateProfilePhoto(flags: flags, id: Api.InputPhoto.inputPhotoEmpty)
|
||||
return account.network.request(api)
|
||||
|> map { _ in }
|
||||
|> retryRequest
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
if fallback {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
transaction.updatePeerCachedData(peerIds: Set([account.peerId]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedFallbackPhoto(.known(nil))
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
})
|
||||
return Void()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
}
|
||||
|
||||
switch fullUser {
|
||||
case let .userFull(_, _, _, _, _, _, userFullNotifySettings, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .userFull(_, _, _, _, _, _, _, userFullNotifySettings, _, _, _, _, _, _, _, _, _, _):
|
||||
updatePeers(transaction: transaction, peers: peers, update: { previous, updated -> Peer in
|
||||
if previous?.id == accountPeerId, let accountUser = accountUser, let user = TelegramUser.merge(previous as? TelegramUser, rhs: accountUser) {
|
||||
return user
|
||||
@ -230,7 +230,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
previous = CachedUserData()
|
||||
}
|
||||
switch fullUser {
|
||||
case let .userFull(userFullFlags, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon, _, _, _, userPremiumGiftOptions):
|
||||
case let .userFull(userFullFlags, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, fallbackPhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon, _, _, _, userPremiumGiftOptions):
|
||||
let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:))
|
||||
let isBlocked = (userFullFlags & (1 << 0)) != 0
|
||||
let voiceCallsAvailable = (userFullFlags & (1 << 4)) != 0
|
||||
@ -250,6 +250,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
|
||||
let personalPhoto = personalPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
|
||||
let photo = profilePhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
|
||||
let fallbackPhoto = fallbackPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
|
||||
|
||||
let premiumGiftOptions: [CachedPremiumGiftOption]
|
||||
if let userPremiumGiftOptions = userPremiumGiftOptions {
|
||||
@ -270,6 +271,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
|
||||
.withUpdatedPhoto(.known(photo))
|
||||
.withUpdatedPersonalPhoto(.known(personalPhoto))
|
||||
.withUpdatedFallbackPhoto(.known(fallbackPhoto))
|
||||
.withUpdatedPremiumGiftOptions(premiumGiftOptions)
|
||||
.withUpdatedVoiceMessagesAvailable(voiceMessagesAvailable)
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case itemListCreateGroupIcon
|
||||
case itemListAddExceptionIcon
|
||||
case itemListAddPhoneIcon
|
||||
case itemListAddPhotoIcon
|
||||
case itemListClearInputIcon
|
||||
case itemListStickerItemUnreadDot
|
||||
case itemListVerifiedPeerIcon
|
||||
|
@ -169,6 +169,12 @@ public struct PresentationResourcesItemList {
|
||||
})
|
||||
}
|
||||
|
||||
public static func addPhotoIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListAddPhotoIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Settings/SetAvatar"), color: theme.list.itemAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func itemListClearInputIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListClearInputIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.list.inputClearButtonColor)
|
||||
|
@ -831,6 +831,8 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
} else {
|
||||
attributedString = NSAttributedString(string: strings.Notification_SuggestedProfileVideo, font: titleFont, textColor: primaryTextColor)
|
||||
}
|
||||
case .attachMenuBotAllowed:
|
||||
attributedString = NSAttributedString(string: strings.Notification_BotWriteAllowed, font: titleFont, textColor: primaryTextColor)
|
||||
case .unknown:
|
||||
attributedString = nil
|
||||
}
|
||||
|
@ -9518,7 +9518,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let hapticFeedback = HapticFeedback()
|
||||
hapticFeedback.impact()
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.Conversation_SendMesageAsPremiumInfo, action: strongSelf.presentationData.strings.EmojiInput_PremiumEmojiToast_Action), elevatedLayout: false, action: { [weak self] action in
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.Conversation_SendMesageAsPremiumInfo, action: strongSelf.presentationData.strings.EmojiInput_PremiumEmojiToast_Action, duration: 3), elevatedLayout: false, action: { [weak self] action in
|
||||
guard let strongSelf = self else {
|
||||
return true
|
||||
}
|
||||
@ -12063,8 +12063,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let _ = (context.engine.messages.getAttachMenuBot(botId: botId)
|
||||
|> deliverOnMainQueue).start(next: { bot in
|
||||
let peer = EnginePeer(bot.peer)
|
||||
let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, completion: {
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: botId)
|
||||
|
||||
let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { allowWrite in
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: botId, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
|
||||
}, completed: {
|
||||
|
@ -1993,7 +1993,9 @@ private final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
||||
let _ = strongSelf.controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets)
|
||||
}
|
||||
|
||||
if let chatPeerId = strongSelf.chatPeerId {
|
||||
let isLocked = file.isPremiumSticker && !hasPremium
|
||||
|
||||
if let chatPeerId = strongSelf.chatPeerId, !isLocked {
|
||||
if chatPeerId != strongSelf.context.account.peerId && chatPeerId.namespace != Namespaces.Peer.SecretChat {
|
||||
menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_SendMessage_SendSilently, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
|
||||
@ -2093,8 +2095,8 @@ private final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
||||
guard let view = view else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: {
|
||||
|
||||
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked && !isStarred, menu: menuItems, openPremiumIntro: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -632,8 +632,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
let choose = filterChooseTypes(choose, peerTypes: bot.peerTypes)
|
||||
|
||||
let botPeer = EnginePeer(bot.peer)
|
||||
let controller = addWebAppToAttachmentController(context: context, peerName: botPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, completion: {
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: peerId)
|
||||
let controller = addWebAppToAttachmentController(context: context, peerName: botPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { allowWrite in
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: peerId, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
presentError(presentationData.strings.WebApp_AddToAttachmentUnavailableError)
|
||||
}, completed: {
|
||||
|
@ -399,7 +399,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
if peer.isDeleted {
|
||||
overrideImage = .deletedIcon
|
||||
} else if let previousItem = previousItem, item == nil {
|
||||
if case let .image(_, representations, _, _) = previousItem, let rep = representations.last {
|
||||
if case let .image(_, representations, _, _, _) = previousItem, let rep = representations.last {
|
||||
self.removedPhotoResourceIds.insert(rep.representation.resource.id.stringRepresentation)
|
||||
}
|
||||
overrideImage = AvatarNodeImageOverride.none
|
||||
@ -499,7 +499,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
if let resource = videoRepresentations.first?.representation.resource as? CloudPhotoSizeMediaResource {
|
||||
videoId = videoId &+ resource.photoId
|
||||
}
|
||||
case let .image(reference, imageRepresentations, videoRepresentationsValue, immediateThumbnail):
|
||||
case let .image(reference, imageRepresentations, videoRepresentationsValue, immediateThumbnail, _):
|
||||
representations = imageRepresentations
|
||||
videoRepresentations = videoRepresentationsValue
|
||||
immediateThumbnailData = immediateThumbnail
|
||||
@ -784,7 +784,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
|
||||
if canEdit, peer.profileImageRepresentations.isEmpty {
|
||||
overrideImage = .editAvatarIcon(forceNone: true)
|
||||
} else if let previousItem = previousItem, item == nil {
|
||||
if case let .image(_, representations, _, _) = previousItem, let rep = representations.last {
|
||||
if case let .image(_, representations, _, _, _) = previousItem, let rep = representations.last {
|
||||
self.removedPhotoResourceIds.insert(rep.representation.resource.id.stringRepresentation)
|
||||
}
|
||||
overrideImage = canEdit ? .editAvatarIcon(forceNone: true) : AvatarNodeImageOverride.none
|
||||
@ -831,7 +831,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
|
||||
if let resource = videoRepresentations.first?.representation.resource as? CloudPhotoSizeMediaResource {
|
||||
id = id &+ resource.photoId
|
||||
}
|
||||
case let .image(reference, imageRepresentations, videoRepresentationsValue, immediateThumbnail):
|
||||
case let .image(reference, imageRepresentations, videoRepresentationsValue, immediateThumbnail, _):
|
||||
representations = imageRepresentations
|
||||
videoRepresentations = videoRepresentationsValue
|
||||
immediateThumbnailData = immediateThumbnail
|
||||
|
@ -1359,7 +1359,8 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
|
||||
let ItemSuggest = 0
|
||||
let ItemCustom = 1
|
||||
let ItemReset = 2
|
||||
let ItemDelete = 3
|
||||
let ItemInfo = 3
|
||||
let ItemDelete = 4
|
||||
|
||||
let compactName = EnginePeer(user).compactDisplayTitle
|
||||
|
||||
@ -1381,6 +1382,7 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
|
||||
interaction.resetCustomPhoto()
|
||||
}))
|
||||
}
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemInfo, text: presentationData.strings.UserInfo_CustomPhotoInfo(compactName).string))
|
||||
|
||||
if data.isContact {
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemDelete, text: presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: {
|
||||
@ -3476,7 +3478,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
var currentIsVideo = false
|
||||
let item = strongSelf.headerNode.avatarListNode.listContainerNode.currentItemNode?.item
|
||||
if let item = item, case let .image(_, _, videoRepresentations, _) = item {
|
||||
if let item = item, case let .image(_, _, videoRepresentations, _, _) = item {
|
||||
currentIsVideo = !videoRepresentations.isEmpty
|
||||
}
|
||||
|
||||
@ -6754,7 +6756,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: mode == .custom ? true : false)
|
||||
|
||||
if case .suggest = mode {
|
||||
if [.suggest, .fallback].contains(mode) {
|
||||
} else {
|
||||
self.state = self.state.withUpdatingAvatar(.image(representation))
|
||||
}
|
||||
@ -6767,9 +6769,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let postbox = self.context.account.postbox
|
||||
let signal: Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError>
|
||||
if self.isSettings {
|
||||
signal = self.context.engine.accountData.updateAccountPhoto(resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
if case .fallback = mode {
|
||||
signal = self.context.engine.accountData.updateFallbackPhoto(resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} else {
|
||||
signal = self.context.engine.accountData.updateAccountPhoto(resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
}
|
||||
} else if case .custom = mode {
|
||||
signal = self.context.engine.contacts.updateContactPhoto(peerId: self.peerId, resource: resource, videoResource: nil, videoStartTimestamp: nil, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
@ -6803,7 +6811,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
if let strongSelf = self, let peer {
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessPhotoText(peer.compactDisplayTitle).string, action: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessPhotoText(peer.compactDisplayTitle).string, action: nil, duration: 5), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -6826,7 +6834,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: mode == .custom ? true : false)
|
||||
|
||||
if case .suggest = mode {
|
||||
if [.suggest, .fallback].contains(mode) {
|
||||
} else {
|
||||
self.state = self.state.withUpdatingAvatar(.image(representation))
|
||||
}
|
||||
@ -6927,9 +6935,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.updateAvatarDisposable.set((signal
|
||||
|> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||
if isSettings {
|
||||
return context.engine.accountData.updateAccountPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
if case .fallback = mode {
|
||||
return context.engine.accountData.updateFallbackPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} else {
|
||||
return context.engine.accountData.updateAccountPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
}
|
||||
} else if case .custom = mode {
|
||||
return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
@ -6962,7 +6976,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
if let strongSelf = self, let peer {
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessVideoText(peer.compactDisplayTitle).string, action: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessVideoText(peer.compactDisplayTitle).string, action: nil, duration: 5), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -6973,16 +6987,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
case generic
|
||||
case suggest
|
||||
case custom
|
||||
case fallback
|
||||
}
|
||||
|
||||
private func openAvatarForEditing(mode: AvatarEditingMode = .generic, fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
fileprivate func openAvatarForEditing(mode: AvatarEditingMode = .generic, fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
guard let peer = self.data?.peer, mode != .generic || canEditPeerInfo(context: self.context, peer: peer, chatLocation: self.chatLocation, threadData: self.data?.threadData) else {
|
||||
return
|
||||
}
|
||||
|
||||
var currentIsVideo = false
|
||||
let item = self.headerNode.avatarListNode.listContainerNode.currentItemNode?.item
|
||||
if let item = item, case let .image(_, _, videoRepresentations, _) = item {
|
||||
if let item = item, case let .image(_, _, videoRepresentations, _, _) = item {
|
||||
currentIsVideo = !videoRepresentations.isEmpty
|
||||
}
|
||||
|
||||
@ -7009,7 +7024,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
legacyController.bind(controller: navigationController)
|
||||
|
||||
strongSelf.view.endEditing(true)
|
||||
strongSelf.controller?.present(legacyController, in: .window(.root))
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.present(legacyController, in: .window(.root))
|
||||
|
||||
var hasPhotos = false
|
||||
if !peer.profileImageRepresentations.isEmpty {
|
||||
@ -7026,7 +7041,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.controller?.present(controller, in: .window(.root))
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root))
|
||||
return controller
|
||||
}
|
||||
|
||||
@ -7040,6 +7055,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
hasDeleteButton = hasPhotos && !fromGallery
|
||||
} else if case .custom = mode {
|
||||
hasDeleteButton = peer.profileImageRepresentations.first?.isPersonal == true
|
||||
} else if case .fallback = mode {
|
||||
if let cachedData = strongSelf.data?.cachedData as? CachedUserData, case let .known(photo) = cachedData.fallbackPhoto {
|
||||
hasDeleteButton = photo != nil
|
||||
}
|
||||
}
|
||||
|
||||
let title: String?
|
||||
@ -7076,7 +7095,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self?.updateProfilePhoto(result, mode: mode)
|
||||
}))
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.controller?.push(controller)
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.push(controller)
|
||||
|
||||
if fromGallery {
|
||||
completion()
|
||||
@ -7088,7 +7107,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let controller = photoUpdateConfirmationController(context: strongSelf.context, peer: peer, image: image, text: confirmationTextPhoto, doneTitle: confirmationAction, commit: {
|
||||
commit?()
|
||||
})
|
||||
strongSelf.controller?.presentInGlobalOverlay(controller)
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7098,7 +7117,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let controller = photoUpdateConfirmationController(context: strongSelf.context, peer: peer, image: image, text: confirmationTextVideo, doneTitle: confirmationAction, commit: {
|
||||
commit?()
|
||||
})
|
||||
strongSelf.controller?.presentInGlobalOverlay(controller)
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7119,55 +7138,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
|
||||
let proceed = {
|
||||
if let item = item {
|
||||
strongSelf.deleteProfilePhoto(item)
|
||||
}
|
||||
|
||||
let _ = strongSelf.currentAvatarMixin.swap(nil)
|
||||
if let _ = peer.smallProfileImage {
|
||||
strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
}
|
||||
let postbox = strongSelf.context.account.postbox
|
||||
strongSelf.updateAvatarDisposable.set((strongSelf.context.engine.peers.updatePeerPhoto(peerId: strongSelf.peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case .complete:
|
||||
strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
let items: [ActionSheetItem] = [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Settings_RemoveConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
proceed()
|
||||
})
|
||||
]
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.controller?.present(actionSheet, in: .window(.root))
|
||||
strongSelf.openAvatarRemoval(mode: mode, peer: peer, item: item)
|
||||
}
|
||||
mixin.didDismiss = { [weak legacyController] in
|
||||
guard let strongSelf = self else {
|
||||
@ -7185,6 +7156,79 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
})
|
||||
}
|
||||
|
||||
fileprivate func openAvatarRemoval(mode: AvatarEditingMode, peer: EnginePeer? = nil, item: PeerInfoAvatarListItem? = nil) {
|
||||
let proceed = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let item = item {
|
||||
strongSelf.deleteProfilePhoto(item)
|
||||
}
|
||||
|
||||
let _ = strongSelf.currentAvatarMixin.swap(nil)
|
||||
if mode != .fallback {
|
||||
if let peer = peer, let _ = peer.smallProfileImage {
|
||||
strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
let postbox = strongSelf.context.account.postbox
|
||||
let signal: Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError>
|
||||
if case .custom = mode {
|
||||
signal = strongSelf.context.engine.contacts.updateContactPhoto(peerId: strongSelf.peerId, resource: nil, videoResource: nil, videoStartTimestamp: nil, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} else if case .fallback = mode {
|
||||
signal = strongSelf.context.engine.accountData.removeFallbackPhoto(reference: nil)
|
||||
|> castError(UploadPeerPhotoError.self)
|
||||
|> map { _ in
|
||||
return .complete([])
|
||||
}
|
||||
} else {
|
||||
signal = strongSelf.context.engine.peers.updatePeerPhoto(peerId: strongSelf.peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
}
|
||||
strongSelf.updateAvatarDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case .complete:
|
||||
strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
let presentationData = self.presentationData
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
let items: [ActionSheetItem] = [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Settings_RemoveConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
proceed()
|
||||
})
|
||||
]
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
(self.controller?.navigationController?.topViewController as? ViewController)?.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
|
||||
private func openAddMember() {
|
||||
guard let data = self.data, let groupPeer = data.peer, let controller = self.controller else {
|
||||
return
|
||||
@ -7290,6 +7334,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
)
|
||||
}
|
||||
}, requestPublicPhotoSetup: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openAvatarForEditing(mode: .fallback)
|
||||
}
|
||||
}, requestPublicPhotoRemove: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openAvatarRemoval(mode: .fallback)
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
@ -9322,18 +9374,18 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
}
|
||||
|
||||
func updateProfilePhoto(_ image: UIImage) {
|
||||
func updateProfilePhoto(_ image: UIImage, fallback: Bool = false) {
|
||||
if !self.isNodeLoaded {
|
||||
self.loadDisplayNode()
|
||||
}
|
||||
self.controllerNode.updateProfilePhoto(image, mode: .generic)
|
||||
self.controllerNode.updateProfilePhoto(image, mode: fallback ? .fallback : .generic)
|
||||
}
|
||||
|
||||
func updateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?) {
|
||||
func updateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?, fallback: Bool = false) {
|
||||
if !self.isNodeLoaded {
|
||||
self.loadDisplayNode()
|
||||
}
|
||||
self.controllerNode.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: .generic)
|
||||
self.controllerNode.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: fallback ? .fallback : .generic)
|
||||
}
|
||||
|
||||
static func displayChatNavigationMenu(context: AccountContext, chatNavigationStack: [ChatNavigationStackItem], nextFolderId: Int32?, parentController: ViewController, backButtonView: UIView, navigationController: NavigationController, gesture: ContextGesture) {
|
||||
|
@ -22,7 +22,7 @@ public enum UndoOverlayContent {
|
||||
case chatRemovedFromFolder(chatTitle: String, folderTitle: String)
|
||||
case messagesUnpinned(title: String, text: String, undo: Bool, isHidden: Bool)
|
||||
case setProximityAlert(title: String, text: String, cancelled: Bool)
|
||||
case invitedToVoiceChat(context: AccountContext, peer: EnginePeer, text: String, action: String?)
|
||||
case invitedToVoiceChat(context: AccountContext, peer: EnginePeer, text: String, action: String?, duration: Double)
|
||||
case linkCopied(text: String)
|
||||
case banned(text: String)
|
||||
case importedMessage(text: String)
|
||||
|
@ -518,7 +518,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 3
|
||||
case let .invitedToVoiceChat(context, peer, text, action):
|
||||
case let .invitedToVoiceChat(context, peer, text, action, duration):
|
||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 15.0))
|
||||
self.iconNode = nil
|
||||
self.iconCheckNode = nil
|
||||
@ -536,11 +536,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
if let action = action {
|
||||
displayUndo = true
|
||||
undoText = action
|
||||
self.originalRemainingSeconds = 5
|
||||
} else {
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 3
|
||||
}
|
||||
self.originalRemainingSeconds = duration
|
||||
case let .audioRate(slowdown, text):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = nil
|
||||
|
@ -28,6 +28,8 @@ swift_library(
|
||||
"//submodules/BotPaymentsUI:BotPaymentsUI",
|
||||
"//submodules/PromptUI:PromptUI",
|
||||
"//submodules/PhoneNumberFormat:PhoneNumberFormat",
|
||||
"//submodules/QrCodeUI:QrCodeUI",
|
||||
"//submodules/InstantPageUI:InstantPageUI",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -10,6 +10,16 @@ import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
import PhotoResources
|
||||
import CheckNode
|
||||
import Markdown
|
||||
|
||||
private let textFont = Font.regular(13.0)
|
||||
private let boldTextFont = Font.semibold(13.0)
|
||||
|
||||
private func formattedText(_ text: String, color: UIColor, textAlignment: NSTextAlignment = .natural) -> NSAttributedString {
|
||||
return parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: color), bold: MarkdownAttributeSet(font: boldTextFont, textColor: color), link: MarkdownAttributeSet(font: textFont, textColor: color), linkAttribute: { _ in return nil}), textAlignment: textAlignment)
|
||||
}
|
||||
|
||||
|
||||
private final class WebAppAlertContentNode: AlertContentNode {
|
||||
private let strings: PresentationStrings
|
||||
@ -20,6 +30,9 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
private let appIconNode: ASImageNode
|
||||
private let iconNode: ASImageNode
|
||||
|
||||
private let allowWriteCheckNode: InteractiveCheckNode
|
||||
private let allowWriteLabelNode: ASTextNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
@ -32,7 +45,13 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(account: Account, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, peerName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], actions: [TextAlertAction]) {
|
||||
var allowWriteAccess: Bool = true {
|
||||
didSet {
|
||||
self.allowWriteCheckNode.setSelected(self.allowWriteAccess, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
init(account: Account, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, peerName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], requestWriteAccess: Bool, actions: [TextAlertAction]) {
|
||||
self.strings = strings
|
||||
self.peerName = peerName
|
||||
|
||||
@ -54,6 +73,12 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
|
||||
self.allowWriteCheckNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: theme.accentColor, strokeColor: theme.contrastColor, borderColor: theme.controlBorderColor, overlayBorder: false, hasInset: false, hasShadow: false))
|
||||
self.allowWriteCheckNode.setSelected(true, animated: false)
|
||||
self.allowWriteLabelNode = ASTextNode()
|
||||
self.allowWriteLabelNode.maximumNumberOfLines = 4
|
||||
self.allowWriteLabelNode.isUserInteractionEnabled = true
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
@ -77,6 +102,12 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.appIconNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
|
||||
if requestWriteAccess {
|
||||
self.addSubnode(self.allowWriteCheckNode)
|
||||
self.addSubnode(self.allowWriteLabelNode)
|
||||
}
|
||||
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
@ -88,6 +119,12 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
|
||||
self.allowWriteCheckNode.valueChanged = { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.allowWriteAccess = !strongSelf.allowWriteAccess
|
||||
}
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
|
||||
if let peerIcon = self.peerIcon {
|
||||
@ -109,12 +146,26 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
self.iconDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.allowWriteLabelNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.allowWriteTap(_:))))
|
||||
}
|
||||
|
||||
@objc private func allowWriteTap(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||
if self.allowWriteCheckNode.isUserInteractionEnabled {
|
||||
self.allowWriteAccess = !self.allowWriteAccess
|
||||
}
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.textNode.attributedText = NSAttributedString(string: strings.WebApp_AddToAttachmentText(self.peerName).string, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
self.appIconNode.image = generateTintedImage(image: self.appIconNode.image, color: theme.accentColor)
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/BotPlus"), color: theme.accentColor)
|
||||
|
||||
self.allowWriteLabelNode.attributedText = formattedText(strings.WebApp_AddToAttachmentAllowMessages(self.peerName).string, color: theme.primaryColor)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
@ -146,6 +197,23 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
|
||||
let textSize = self.textNode.measure(size)
|
||||
var textFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize)
|
||||
origin.y += textSize.height
|
||||
|
||||
var entriesHeight: CGFloat = 0.0
|
||||
|
||||
if self.allowWriteLabelNode.supernode != nil {
|
||||
origin.y += 16.0
|
||||
entriesHeight += 16.0
|
||||
|
||||
let checkSize = CGSize(width: 22.0, height: 22.0)
|
||||
let condensedSize = CGSize(width: size.width - 76.0, height: size.height)
|
||||
|
||||
let allowWriteSize = self.allowWriteLabelNode.measure(condensedSize)
|
||||
transition.updateFrame(node: self.allowWriteLabelNode, frame: CGRect(origin: CGPoint(x: 46.0, y: origin.y), size: allowWriteSize))
|
||||
transition.updateFrame(node: self.allowWriteCheckNode, frame: CGRect(origin: CGPoint(x: 12.0, y: origin.y - 2.0), size: checkSize))
|
||||
origin.y += allowWriteSize.height
|
||||
entriesHeight += allowWriteSize.height
|
||||
}
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
@ -180,7 +248,7 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
}
|
||||
|
||||
let resultWidth = contentWidth + insets.left + insets.right
|
||||
let resultSize = CGSize(width: resultWidth, height: iconSize.height + textSize.height + actionsHeight + 17.0 + insets.top + insets.bottom)
|
||||
let resultSize = CGSize(width: resultWidth, height: iconSize.height + textSize.height + entriesHeight + actionsHeight + 17.0 + insets.top + insets.bottom)
|
||||
|
||||
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
|
||||
@ -227,7 +295,7 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
iconFrame.origin.x = floorToScreenPixels((resultSize.width - iconFrame.width) / 2.0) + 19.0
|
||||
iconFrame.origin.x = floorToScreenPixels((resultSize.width - iconFrame.width) / 2.0) + 21.0
|
||||
|
||||
transition.updateFrame(node: self.appIconNode, frame: CGRect(x: iconFrame.minX - 50.0, y: iconFrame.minY + 3.0, width: 42.0, height: 42.0))
|
||||
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||
@ -239,7 +307,7 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func addWebAppToAttachmentController(context: AccountContext, peerName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], completion: @escaping () -> Void) -> AlertController {
|
||||
public func addWebAppToAttachmentController(context: AccountContext, peerName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], requestWriteAccess: Bool, completion: @escaping (Bool) -> Void) -> AlertController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme
|
||||
let strings = presentationData.strings
|
||||
@ -251,10 +319,10 @@ public func addWebAppToAttachmentController(context: AccountContext, peerName: S
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_AddToAttachmentAdd, action: {
|
||||
dismissImpl?(true)
|
||||
|
||||
completion()
|
||||
completion(true)
|
||||
})]
|
||||
|
||||
contentNode = WebAppAlertContentNode(account: context.account, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peerName: peerName, icons: icons, actions: actions)
|
||||
contentNode = WebAppAlertContentNode(account: context.account, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peerName: peerName, icons: icons, requestWriteAccess: requestWriteAccess, actions: actions)
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode!)
|
||||
dismissImpl = { [weak controller] animated in
|
||||
|
@ -21,6 +21,8 @@ import MoreButtonNode
|
||||
import BotPaymentsUI
|
||||
import PromptUI
|
||||
import PhoneNumberFormat
|
||||
import QrCodeUI
|
||||
import InstantPageUI
|
||||
|
||||
private let durgerKingBotIds: [Int64] = [5104055776, 2200339955]
|
||||
|
||||
@ -680,10 +682,27 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
case "web_app_open_link":
|
||||
if let json = json, let url = json["url"] as? String {
|
||||
let tryInstantView = json["try_instant_view"] as? Bool ?? false
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0 {
|
||||
self.webView?.lastTouchTimestamp = nil
|
||||
self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
||||
if tryInstantView {
|
||||
let _ = (resolveInstantViewUrl(account: self.context.account, url: url)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .instantView(webPage, anchor):
|
||||
let controller = InstantPageController(context: strongSelf.context, webPage: webPage, sourcePeerType: .otherPrivate, anchor: anchor)
|
||||
strongSelf.controller?.getNavigationController()?.pushViewController(controller)
|
||||
default:
|
||||
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
||||
}
|
||||
}
|
||||
}
|
||||
case "web_app_setup_back_button":
|
||||
@ -799,8 +818,28 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
if let json = json, let needConfirmation = json["need_confirmation"] as? Bool {
|
||||
self.needDismissConfirmation = needConfirmation
|
||||
}
|
||||
case "web_app_request_phone":
|
||||
break
|
||||
case "web_app_open_scan_qr_popup":
|
||||
var info: String = ""
|
||||
if let json = json, let text = json["text"] as? String {
|
||||
info = text
|
||||
}
|
||||
let controller = QrCodeScanScreen(context: self.context, subject: .custom(info: info))
|
||||
controller.completion = { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
strongSelf.sendQrCodeScannedEvent(data: result)
|
||||
}
|
||||
}
|
||||
self.controller?.present(controller, in: .window(.root))
|
||||
case "web_app_read_text_from_clipboard":
|
||||
if let json = json, let requestId = json["req_id"] as? String {
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
var fillData = false
|
||||
if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0, self.controller?.url == nil {
|
||||
self.webView?.lastTouchTimestamp = nil
|
||||
fillData = true
|
||||
}
|
||||
self.sendClipboardTextEvent(requestId: requestId, fillData: fillData)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -930,6 +969,22 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
self.webView?.sendEvent(name: "phone_requested", data: paramsString)
|
||||
}
|
||||
|
||||
fileprivate func sendQrCodeScannedEvent(data: String?) {
|
||||
let paramsString = data.flatMap { "{data: \"\($0)\"}" } ?? "{}"
|
||||
self.webView?.sendEvent(name: "scan_qr_popup_closed", data: paramsString)
|
||||
}
|
||||
|
||||
fileprivate func sendClipboardTextEvent(requestId: String, fillData: Bool) {
|
||||
var paramsString: String
|
||||
if fillData {
|
||||
let data = UIPasteboard.general.string ?? ""
|
||||
paramsString = "{req_id: \"\(requestId)\", data: \"\(data)\"}"
|
||||
} else {
|
||||
paramsString = "{req_id: \"\(requestId)\"}"
|
||||
}
|
||||
self.webView?.sendEvent(name: "clipboard_text_received", data: paramsString)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var controllerNode: Node {
|
||||
@ -1067,7 +1122,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
|
||||
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId})
|
||||
|
||||
if self?.url == nil, let attachMenuBot = attachMenuBot, attachMenuBot.hasSettings {
|
||||
if self?.url == nil, let attachMenuBot = attachMenuBot, attachMenuBot.flags.contains(.hasSettings) {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Settings, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
|
Loading…
x
Reference in New Issue
Block a user