mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Custom contact photos [skip ci]
This commit is contained in:
parent
d4e55712e5
commit
5788f4a1ac
@ -8446,3 +8446,26 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Channel.AdminLog.AntiSpamEnabled" = "%1$@ enabled anti-spam";
|
||||
"Channel.AdminLog.AntiSpamDisabled" = "%1$@ disabled anti-spam";
|
||||
|
||||
"UserInfo.SuggestPhoto" = "Suggest Photo for %@";
|
||||
"UserInfo.SetCustomPhoto" = "Set Photo for %@";
|
||||
"UserInfo.ResetCustomPhoto" = "Reset to Original Photo";
|
||||
|
||||
"UserInfo.SuggestPhotoTitle" = "Do you want to suggest a profile picture for %@?";
|
||||
"UserInfo.SetCustomPhotoTitle" = "Do you want to set a custom profile picture for %@?";
|
||||
|
||||
"UserInfo.SuggestPhoto.AlertPhotoText" = "Do you want to suggest %@ to set this photo for his/her profile?";
|
||||
"UserInfo.SuggestPhoto.AlertVideoText" = "Do you want to suggest %@ to set this video for his/her profile?";
|
||||
"UserInfo.SuggestPhoto.AlertSuggest" = "Suggest";
|
||||
|
||||
"UserInfo.SetCustomPhoto.AlertPhotoText" = "Do you want to set this photo for %@? Only you will see this photo and it will replace any photo %@ sets for themselves.";
|
||||
"UserInfo.SetCustomPhoto.AlertVideoText" = "Do you want to set this video for %@? Only you will see this video and it will replace any photo %@ sets for themselves.";
|
||||
"UserInfo.SetCustomPhoto.AlertSet" = "Set";
|
||||
"UserInfo.SetCustomPhoto.SuccessPhotoText" = "You will now always see this photo for **%@** account.";
|
||||
"UserInfo.SetCustomPhoto.SuccessVideoText" = "You will now always see this video for **%@** account.";
|
||||
|
||||
"UserInfo.CustomPhoto" = "photo set by you";
|
||||
"UserInfo.CustomVideo" = "video set by you";
|
||||
|
||||
"UserInfo.ResetToOriginalAlertText" = "Are you sure you want to reset to %@ original photo?";
|
||||
"UserInfo.ResetToOriginalAlertReset" = "Reset";
|
||||
|
@ -236,7 +236,7 @@ func addTemporaryKeyboardSnapshotView(navigationController: NavigationController
|
||||
keyboardWindow.addSubview(snapshotView)
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.45, {
|
||||
Queue.mainQueue().after(0.5, {
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
|
@ -84,7 +84,7 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?,
|
||||
}
|
||||
}
|
||||
|
||||
public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal<UIImage?, NoError> {
|
||||
public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forceProvidedRepresentation: Bool = false, representation: TelegramMediaImageRepresentation? = nil, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal<UIImage?, NoError> {
|
||||
let iconSignal: Signal<UIImage?, NoError>
|
||||
|
||||
let clipStyle: AvatarNodeClipStyle
|
||||
@ -97,7 +97,15 @@ public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, size: CG
|
||||
} else {
|
||||
clipStyle = .none
|
||||
}
|
||||
if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.first, displayDimensions: size, clipStyle: clipStyle, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
|
||||
|
||||
let thumbnailRepresentation: TelegramMediaImageRepresentation?
|
||||
if forceProvidedRepresentation {
|
||||
thumbnailRepresentation = representation
|
||||
} else {
|
||||
thumbnailRepresentation = peer.profileImageRepresentations.first
|
||||
}
|
||||
|
||||
if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: thumbnailRepresentation, displayDimensions: size, clipStyle: clipStyle, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
|
||||
if fullSize, let fullSizeSignal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) {
|
||||
iconSignal = combineLatest(.single(nil) |> then(signal), .single(nil) |> then(fullSizeSignal))
|
||||
|> mapToSignal { thumbnailImage, fullSizeImage -> Signal<UIImage?, NoError> in
|
||||
|
@ -178,6 +178,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
isForum = true
|
||||
}
|
||||
|
||||
var hasRemoveFromFolder = false
|
||||
if case let .chatList(currentFilter) = source {
|
||||
if let currentFilter = currentFilter, case let .filter(id, title, emoticon, data) = currentFilter {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
@ -201,119 +202,122 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
})
|
||||
})
|
||||
})))
|
||||
} else {
|
||||
var hasFolders = false
|
||||
hasRemoveFromFolder = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasRemoveFromFolder && peerGroup != nil {
|
||||
var hasFolders = false
|
||||
|
||||
for case let .filter(_, _, _, data) in filters {
|
||||
let predicate = chatListFilterPredicate(filter: data)
|
||||
if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
|
||||
var data = data
|
||||
if data.addIncludePeer(peerId: peer.id) {
|
||||
hasFolders = true
|
||||
break
|
||||
}
|
||||
for case let .filter(_, _, _, data) in filters {
|
||||
let predicate = chatListFilterPredicate(filter: data)
|
||||
if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
|
||||
if hasFolders {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Folder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
var updatedItems: [ContextMenuItem] = []
|
||||
var data = data
|
||||
if data.addIncludePeer(peerId: peer.id) {
|
||||
hasFolders = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for filter in filters {
|
||||
if case let .filter(_, title, _, data) = filter {
|
||||
let predicate = chatListFilterPredicate(filter: data)
|
||||
if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
if hasFolders {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Folder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
var updatedItems: [ContextMenuItem] = []
|
||||
|
||||
var data = data
|
||||
if !data.addIncludePeer(peerId: peer.id) {
|
||||
continue
|
||||
}
|
||||
|
||||
let filterType = chatListFilterType(data)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: title, icon: { theme in
|
||||
let imageName: String
|
||||
switch filterType {
|
||||
case .generic:
|
||||
imageName = "Chat/Context Menu/List"
|
||||
case .unmuted:
|
||||
imageName = "Chat/Context Menu/Unmute"
|
||||
case .unread:
|
||||
imageName = "Chat/Context Menu/MarkAsUnread"
|
||||
case .channels:
|
||||
imageName = "Chat/Context Menu/Channels"
|
||||
case .groups:
|
||||
imageName = "Chat/Context Menu/Groups"
|
||||
case .bots:
|
||||
imageName = "Chat/Context Menu/Bots"
|
||||
case .contacts:
|
||||
imageName = "Chat/Context Menu/User"
|
||||
case .nonContacts:
|
||||
imageName = "Chat/Context Menu/UnknownUser"
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
let isPremium = limitsData.0?.isPremium ?? false
|
||||
let (_, limits, premiumLimits) = limitsData
|
||||
|
||||
let limit = limits.maxFolderChatsCount
|
||||
let premiumLimit = premiumLimits.maxFolderChatsCount
|
||||
|
||||
let count = data.includePeers.peers.count - 1
|
||||
if count >= premiumLimit {
|
||||
let controller = PremiumLimitScreen(context: context, subject: .chatsPerFolder, count: Int32(count), action: {})
|
||||
chatListController?.push(controller)
|
||||
return
|
||||
} else if count >= limit && !isPremium {
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = PremiumLimitScreen(context: context, subject: .chatsPerFolder, count: Int32(count), action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .chatsPerFolder)
|
||||
replaceImpl?(controller)
|
||||
})
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
chatListController?.push(controller)
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == filter.id {
|
||||
if case let .filter(id, title, emoticon, data) = filter {
|
||||
var updatedData = data
|
||||
let _ = updatedData.addIncludePeer(peerId: peer.id)
|
||||
filters[i] = .filter(id: id, title: title, emoticon: emoticon, data: updatedData)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return filters
|
||||
}).start()
|
||||
|
||||
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
return false
|
||||
}), in: .current)
|
||||
})
|
||||
})))
|
||||
for filter in filters {
|
||||
if case let .filter(_, title, _, data) = filter {
|
||||
let predicate = chatListFilterPredicate(filter: data)
|
||||
if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
|
||||
var data = data
|
||||
if !data.addIncludePeer(peerId: peer.id) {
|
||||
continue
|
||||
}
|
||||
|
||||
let filterType = chatListFilterType(data)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: title, icon: { theme in
|
||||
let imageName: String
|
||||
switch filterType {
|
||||
case .generic:
|
||||
imageName = "Chat/Context Menu/List"
|
||||
case .unmuted:
|
||||
imageName = "Chat/Context Menu/Unmute"
|
||||
case .unread:
|
||||
imageName = "Chat/Context Menu/MarkAsUnread"
|
||||
case .channels:
|
||||
imageName = "Chat/Context Menu/Channels"
|
||||
case .groups:
|
||||
imageName = "Chat/Context Menu/Groups"
|
||||
case .bots:
|
||||
imageName = "Chat/Context Menu/Bots"
|
||||
case .contacts:
|
||||
imageName = "Chat/Context Menu/User"
|
||||
case .nonContacts:
|
||||
imageName = "Chat/Context Menu/UnknownUser"
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
let isPremium = limitsData.0?.isPremium ?? false
|
||||
let (_, limits, premiumLimits) = limitsData
|
||||
|
||||
let limit = limits.maxFolderChatsCount
|
||||
let premiumLimit = premiumLimits.maxFolderChatsCount
|
||||
|
||||
let count = data.includePeers.peers.count - 1
|
||||
if count >= premiumLimit {
|
||||
let controller = PremiumLimitScreen(context: context, subject: .chatsPerFolder, count: Int32(count), action: {})
|
||||
chatListController?.push(controller)
|
||||
return
|
||||
} else if count >= limit && !isPremium {
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = PremiumLimitScreen(context: context, subject: .chatsPerFolder, count: Int32(count), action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .chatsPerFolder)
|
||||
replaceImpl?(controller)
|
||||
})
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
chatListController?.push(controller)
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == filter.id {
|
||||
if case let .filter(id, title, emoticon, data) = filter {
|
||||
var updatedData = data
|
||||
let _ = updatedData.addIncludePeer(peerId: peer.id)
|
||||
filters[i] = .filter(id: id, title: title, emoticon: emoticon, data: updatedData)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return filters
|
||||
}).start()
|
||||
|
||||
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
return false
|
||||
}), in: .current)
|
||||
})
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
updatedItems.append(.separator)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
|
||||
})))
|
||||
|
||||
c.setItems(.single(ContextController.Items(content: .list(updatedItems))), minHeight: nil)
|
||||
updatedItems.append(.separator)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
|
||||
})))
|
||||
}
|
||||
|
||||
c.setItems(.single(ContextController.Items(content: .list(updatedItems))), minHeight: nil)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
if setup {
|
||||
text.referenceDrawingSize = self.size
|
||||
text.width = floor(self.size.width * 0.9)
|
||||
text.fontSize = 0.4
|
||||
text.fontSize = 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ struct DrawingState: Equatable {
|
||||
return DrawingState(
|
||||
selectedTool: .pen,
|
||||
tools: [
|
||||
.pen(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xffffff), size: 0.5, mode: .round)),
|
||||
.pen(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xffffff), size: 0.3, mode: .round)),
|
||||
.marker(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xfee21b), size: 0.5, mode: .round)),
|
||||
.neon(DrawingToolState.BrushState(color: DrawingColor(rgb: 0x34ffab), size: 0.5, mode: .round)),
|
||||
.pencil(DrawingToolState.BrushState(color: DrawingColor(rgb: 0x2570f0), size: 0.5, mode: .round)),
|
||||
|
@ -71,7 +71,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw
|
||||
|
||||
var tool: Tool = .pen
|
||||
var toolColor: DrawingColor = DrawingColor(color: .white)
|
||||
var toolBrushSize: CGFloat = 0.15
|
||||
var toolBrushSize: CGFloat = 0.35
|
||||
var toolHasArrow: Bool = false
|
||||
|
||||
var stateUpdated: (NavigationState) -> Void = { _ in }
|
||||
|
@ -42,8 +42,8 @@
|
||||
|
||||
@property (nonatomic, copy) void (^cameraPressed)(TGAttachmentCameraView *cameraView);
|
||||
@property (nonatomic, copy) void (^sendPressed)(TGMediaAsset *currentItem, bool asFiles, bool silentPosting, int32_t scheduleTime, bool isFromPicker);
|
||||
@property (nonatomic, copy) void (^avatarCompletionBlock)(UIImage *image);
|
||||
@property (nonatomic, copy) void (^avatarVideoCompletionBlock)(UIImage *image, id asset, TGVideoEditAdjustments *adjustments);
|
||||
@property (nonatomic, copy) void (^avatarCompletionBlock)(UIImage *image, void(^commit)(void));
|
||||
@property (nonatomic, copy) void (^avatarVideoCompletionBlock)(UIImage *image, id asset, TGVideoEditAdjustments *adjustments, void(^commit)(void));
|
||||
|
||||
@property (nonatomic, copy) void (^editorOpened)(void);
|
||||
@property (nonatomic, copy) void (^editorClosed)(void);
|
||||
|
@ -15,6 +15,9 @@ typedef void (^TGMediaAvatarPresentImpl)(id<LegacyComponentsContext>, void (^)(U
|
||||
|
||||
@property (nonatomic, assign) bool forceDark;
|
||||
|
||||
@property (nonatomic, copy) void (^willFinishWithImage)(UIImage *image, void (^)(void));
|
||||
@property (nonatomic, copy) void (^willFinishWithVideo)(UIImage *image, void (^)(void));
|
||||
|
||||
@property (nonatomic, copy) void (^didFinishWithImage)(UIImage *image);
|
||||
@property (nonatomic, copy) void (^didFinishWithVideo)(UIImage *image, AVAsset *asset, TGVideoEditAdjustments *adjustments);
|
||||
@property (nonatomic, copy) void (^didFinishWithDelete)(void);
|
||||
@ -27,7 +30,7 @@ typedef void (^TGMediaAvatarPresentImpl)(id<LegacyComponentsContext>, void (^)(U
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia;
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton personalPhoto:(bool)personalPhoto saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia;
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum;
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum title:(NSString *)title;
|
||||
- (TGMenuSheetController *)present;
|
||||
|
||||
@end
|
||||
|
@ -51,8 +51,8 @@ typedef enum {
|
||||
|
||||
@property (nonatomic, copy) void (^willFinishEditing)(id<TGMediaEditAdjustments> adjustments, id temporaryRep, bool hasChanges);
|
||||
@property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(UIImage *fullSizeImage);
|
||||
@property (nonatomic, copy) void (^didFinishEditing)(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges);
|
||||
@property (nonatomic, copy) void (^didFinishEditingVideo)(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges);
|
||||
@property (nonatomic, copy) void (^didFinishEditing)(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void));
|
||||
@property (nonatomic, copy) void (^didFinishEditingVideo)(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void));
|
||||
|
||||
@property (nonatomic, assign) bool skipInitialTransition;
|
||||
@property (nonatomic, assign) bool dontHideStatusBar;
|
||||
|
@ -933,11 +933,10 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
||||
};
|
||||
|
||||
__weak TGPhotoEditorController *weakController = controller;
|
||||
controller.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges)
|
||||
controller.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges, void(^commit)(void))
|
||||
{
|
||||
if (!hasChanges)
|
||||
return;
|
||||
|
||||
__strong TGAttachmentCarouselItemView *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
@ -970,13 +969,13 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
||||
}
|
||||
}
|
||||
if (strongSelf.avatarVideoCompletionBlock != nil)
|
||||
strongSelf.avatarVideoCompletionBlock(previewImage, [NSURL fileURLWithPath:filePath], videoAdjustments);
|
||||
strongSelf.avatarVideoCompletionBlock(previewImage, [NSURL fileURLWithPath:filePath], videoAdjustments, commit);
|
||||
} else {
|
||||
if (strongSelf.avatarCompletionBlock != nil)
|
||||
strongSelf.avatarCompletionBlock(resultImage);
|
||||
strongSelf.avatarCompletionBlock(resultImage, commit);
|
||||
}
|
||||
};
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void)) {
|
||||
if (!hasChanges)
|
||||
return;
|
||||
|
||||
@ -989,7 +988,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
||||
return;
|
||||
|
||||
if (strongSelf.avatarVideoCompletionBlock != nil)
|
||||
strongSelf.avatarVideoCompletionBlock(resultImage, asset, adjustments);
|
||||
strongSelf.avatarVideoCompletionBlock(resultImage, asset, adjustments, commit);
|
||||
};
|
||||
controller.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem)
|
||||
{
|
||||
|
@ -2014,7 +2014,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
return strongSelf->_previewView;
|
||||
};
|
||||
|
||||
controller.didFinishEditing = ^(PGPhotoEditorValues *editorValues, UIImage *resultImage, __unused UIImage *thumbnailImage, bool hasChanges)
|
||||
controller.didFinishEditing = ^(PGPhotoEditorValues *editorValues, UIImage *resultImage, __unused UIImage *thumbnailImage, bool hasChanges, void(^commit)(void))
|
||||
{
|
||||
if (!hasChanges)
|
||||
return;
|
||||
@ -2064,10 +2064,12 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
[strongController updateStatusBarAppearanceForDismiss];
|
||||
[strongSelf _dismissTransitionForResultController:(TGOverlayController *)strongController];
|
||||
}
|
||||
|
||||
commit();
|
||||
});
|
||||
};
|
||||
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void)) {
|
||||
if (!hasChanges)
|
||||
return;
|
||||
|
||||
@ -2086,6 +2088,8 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
[strongController updateStatusBarAppearanceForDismiss];
|
||||
[strongSelf _dismissTransitionForResultController:(TGOverlayController *)strongController];
|
||||
}
|
||||
|
||||
commit();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -451,7 +451,7 @@
|
||||
|
||||
[[strongSelf->_assetsLibrary saveAssetWithImage:resultImage] startWithNext:nil];
|
||||
};
|
||||
controller.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, bool hasChanges)
|
||||
controller.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, bool hasChanges, void(^commit)(void))
|
||||
{
|
||||
if (!hasChanges)
|
||||
return;
|
||||
@ -488,7 +488,7 @@
|
||||
[(TGMediaAssetsController *)strongSelf.navigationController completeWithAvatarImage:resultImage];
|
||||
}
|
||||
};
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void)) {
|
||||
if (!hasChanges)
|
||||
return;
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
bool _signup;
|
||||
bool _isVideo;
|
||||
bool _forum;
|
||||
NSString *_title;
|
||||
}
|
||||
@end
|
||||
|
||||
@ -39,10 +40,10 @@
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton personalPhoto:(bool)personalPhoto saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia
|
||||
{
|
||||
return [self initWithContext:context parentController:parentController hasSearchButton:false hasDeleteButton:hasDeleteButton hasViewButton:false personalPhoto:personalPhoto isVideo:false saveEditedPhotos:saveEditedPhotos saveCapturedMedia:saveCapturedMedia signup:false forum: false];
|
||||
return [self initWithContext:context parentController:parentController hasSearchButton:false hasDeleteButton:hasDeleteButton hasViewButton:false personalPhoto:personalPhoto isVideo:false saveEditedPhotos:saveEditedPhotos saveCapturedMedia:saveCapturedMedia signup:false forum:false title:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum title:(NSString *)title
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
@ -58,6 +59,7 @@
|
||||
_isVideo = isVideo;
|
||||
_signup = signup;
|
||||
_forum = forum;
|
||||
_title = title;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -92,6 +94,10 @@
|
||||
|
||||
NSMutableArray *itemViews = [[NSMutableArray alloc] init];
|
||||
|
||||
if (_title.length > 0) {
|
||||
[itemViews addObject:[[TGMenuSheetTitleItemView alloc] initWithTitle:nil subtitle:_title solidSubtitle:false]];
|
||||
}
|
||||
|
||||
TGAttachmentCarouselItemView *carouselItem = [[TGAttachmentCarouselItemView alloc] initWithContext:_context camera:true selfPortrait:_personalPhoto forProfilePhoto:true assetType:_signup ? TGMediaAssetPhotoType : TGMediaAssetAnyType saveEditedPhotos:_saveEditedPhotos allowGrouping:false];
|
||||
carouselItem.forum = _forum;
|
||||
carouselItem.stickersContext = _stickersContext;
|
||||
@ -112,7 +118,7 @@
|
||||
|
||||
[strongSelf _displayCameraWithView:cameraView menuController:strongController];
|
||||
};
|
||||
carouselItem.avatarCompletionBlock = ^(UIImage *resultImage)
|
||||
carouselItem.avatarCompletionBlock = ^(UIImage *resultImage, void(^commit)(void))
|
||||
{
|
||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
@ -122,12 +128,25 @@
|
||||
if (strongController == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
[strongController dismissAnimated:false];
|
||||
if (strongSelf.willFinishWithImage != nil) {
|
||||
strongSelf.willFinishWithImage(resultImage, ^{
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
commit();
|
||||
|
||||
[strongController dismissAnimated:false];
|
||||
});
|
||||
} else {
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
commit();
|
||||
|
||||
[strongController dismissAnimated:false];
|
||||
}
|
||||
};
|
||||
carouselItem.avatarVideoCompletionBlock = ^(UIImage *image, AVAsset *asset, TGVideoEditAdjustments *adjustments) {
|
||||
carouselItem.avatarVideoCompletionBlock = ^(UIImage *image, AVAsset *asset, TGVideoEditAdjustments *adjustments, void(^commit)(void)) {
|
||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
@ -139,6 +158,8 @@
|
||||
if (strongSelf.didFinishWithVideo != nil)
|
||||
strongSelf.didFinishWithVideo(image, asset, adjustments);
|
||||
|
||||
commit();
|
||||
|
||||
[strongController dismissAnimated:false];
|
||||
};
|
||||
[itemViews addObject:carouselItem];
|
||||
@ -314,10 +335,19 @@
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
[menuController dismissAnimated:false];
|
||||
if (strongSelf.willFinishWithImage != nil) {
|
||||
strongSelf.willFinishWithImage(resultImage, ^{
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
[menuController dismissAnimated:false];
|
||||
});
|
||||
} else {
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
[menuController dismissAnimated:false];
|
||||
}
|
||||
};
|
||||
|
||||
controller.finishedWithVideo = ^(__unused TGOverlayController *controller, NSURL *url, UIImage *previewImage, __unused NSTimeInterval duration, __unused CGSize dimensions, TGVideoEditAdjustments *adjustments, __unused NSAttributedString *caption, __unused NSArray *stickers, __unused NSNumber *timer){
|
||||
@ -431,13 +461,24 @@
|
||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
__strong TGMediaAssetsController *strongController = weakController;
|
||||
if (strongController != nil && strongController.dismissalBlock != nil)
|
||||
strongController.dismissalBlock();
|
||||
|
||||
if (strongSelf.willFinishWithImage != nil) {
|
||||
strongSelf.willFinishWithImage(resultImage, ^{
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
__strong TGMediaAssetsController *strongController = weakController;
|
||||
if (strongController != nil && strongController.dismissalBlock != nil)
|
||||
strongController.dismissalBlock();
|
||||
});
|
||||
} else {
|
||||
if (strongSelf.didFinishWithImage != nil)
|
||||
strongSelf.didFinishWithImage(resultImage);
|
||||
|
||||
__strong TGMediaAssetsController *strongController = weakController;
|
||||
if (strongController != nil && strongController.dismissalBlock != nil)
|
||||
strongController.dismissalBlock();
|
||||
}
|
||||
};
|
||||
controller.avatarVideoCompletionBlock = ^(UIImage *image, AVAsset *asset, TGVideoEditAdjustments *adjustments) {
|
||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||
|
@ -417,7 +417,7 @@
|
||||
};
|
||||
|
||||
void (^didFinishEditingItem)(id<TGMediaEditableItem>item, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage) = self.didFinishEditingItem;
|
||||
controller.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges)
|
||||
controller.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void))
|
||||
{
|
||||
__strong TGMediaPickerGalleryModel *strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
|
@ -73,7 +73,7 @@
|
||||
|
||||
- (CGFloat)preferredHeightForWidth:(CGFloat)width screenHeight:(CGFloat)__unused screenHeight
|
||||
{
|
||||
CGFloat height = 17.0f;
|
||||
CGFloat height = 16.0f;
|
||||
|
||||
if (_titleLabel.text.length > 0)
|
||||
{
|
||||
@ -91,19 +91,19 @@
|
||||
height += _subtitleLabel.frame.size.height;
|
||||
}
|
||||
|
||||
height += 15.0f;
|
||||
height += 8.0f;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
- (bool)requiresDivider
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
CGFloat topOffset = 17.0f;
|
||||
CGFloat topOffset = 16.0f;
|
||||
|
||||
if (_titleLabel.text.length > 0)
|
||||
{
|
||||
|
@ -952,7 +952,7 @@
|
||||
self.willFinishEditing(nil, [_currentTabController currentResultRepresentation], true);
|
||||
|
||||
if (self.didFinishEditing != nil)
|
||||
self.didFinishEditing(nil, nil, nil, true);
|
||||
self.didFinishEditing(nil, nil, nil, true, ^{});
|
||||
|
||||
if (completion != nil)
|
||||
completion(nil);
|
||||
@ -1059,7 +1059,7 @@
|
||||
else
|
||||
{
|
||||
void (^didFinishRenderingFullSizeImage)(UIImage *) = self.didFinishRenderingFullSizeImage;
|
||||
void (^didFinishEditing)(id<TGMediaEditAdjustments>, UIImage *, UIImage *, bool ) = self.didFinishEditing;
|
||||
void (^didFinishEditing)(id<TGMediaEditAdjustments>, UIImage *, UIImage *, bool , void(^)(void)) = self.didFinishEditing;
|
||||
|
||||
[[[[renderedImageSignal map:^id(UIImage *image)
|
||||
{
|
||||
@ -1119,7 +1119,7 @@
|
||||
}
|
||||
|
||||
if (!saveOnly && didFinishEditing != nil)
|
||||
didFinishEditing(editorValues, image, thumbnailImage, true);
|
||||
didFinishEditing(editorValues, image, thumbnailImage, true, ^{});
|
||||
} error:^(__unused id error)
|
||||
{
|
||||
TGLegacyLog(@"renderedImageSignal error");
|
||||
@ -1899,7 +1899,7 @@
|
||||
strongSelf.willFinishEditing(nil, nil, false);
|
||||
|
||||
if (strongSelf.didFinishEditing != nil)
|
||||
strongSelf.didFinishEditing(nil, nil, nil, false);
|
||||
strongSelf.didFinishEditing(nil, nil, nil, false, ^{});
|
||||
};
|
||||
|
||||
TGPaintingData *paintingData = nil;
|
||||
@ -2088,7 +2088,7 @@
|
||||
|
||||
TGDispatchOnMainThread(^{
|
||||
if (self.didFinishEditingVideo != nil)
|
||||
self.didFinishEditingVideo(asset, [adjustments editAdjustmentsWithPreset:preset videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true);
|
||||
self.didFinishEditingVideo(asset, [adjustments editAdjustmentsWithPreset:preset videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true, ^{});
|
||||
|
||||
[self dismissAnimated:true];
|
||||
});
|
||||
@ -2196,16 +2196,16 @@
|
||||
if (self.willFinishEditing != nil)
|
||||
self.willFinishEditing(hasChanges ? adjustments : nil, nil, hasChanges);
|
||||
|
||||
if (self.didFinishEditing != nil)
|
||||
self.didFinishEditing(hasChanges ? adjustments : nil, nil, nil, hasChanges);
|
||||
|
||||
if ([self presentedForAvatarCreation]) {
|
||||
[self dismissAnimated:true];
|
||||
} else {
|
||||
[self transitionOutSaving:saving completion:^
|
||||
{
|
||||
[self dismiss];
|
||||
}];
|
||||
if (self.didFinishEditing != nil) {
|
||||
self.didFinishEditing(hasChanges ? adjustments : nil, nil, nil, hasChanges, ^{
|
||||
if ([self presentedForAvatarCreation]) {
|
||||
[self dismissAnimated:true];
|
||||
} else {
|
||||
[self transitionOutSaving:saving completion:^{
|
||||
[self dismiss];
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,12 +38,12 @@
|
||||
// controller.stickersContext = _stickersContext;
|
||||
controller.skipInitialTransition = true;
|
||||
controller.dontHideStatusBar = true;
|
||||
controller.didFinishEditing = ^(__unused id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges)
|
||||
controller.didFinishEditing = ^(__unused id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges, void(^commit)(void))
|
||||
{
|
||||
if (didFinishWithImage != nil)
|
||||
didFinishWithImage(resultImage);
|
||||
};
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
||||
controller.didFinishEditingVideo = ^(AVAsset *asset, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges, void(^commit)(void)) {
|
||||
if (didFinishWithVideo != nil) {
|
||||
if ([asset isKindOfClass:[AVURLAsset class]]) {
|
||||
didFinishWithVideo(resultImage, [(AVURLAsset *)asset URL], adjustments);
|
||||
|
@ -19,7 +19,7 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
|
||||
|
||||
present(legacyController, nil)
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: false, hasDeleteButton: false, hasViewButton: openCurrent != nil, personalPhoto: true, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: signup, forum: false)!
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: false, hasDeleteButton: false, hasViewButton: openCurrent != nil, personalPhoto: true, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: signup, forum: false, title: nil)!
|
||||
let _ = holder.swap(mixin)
|
||||
mixin.didFinishWithImage = { image in
|
||||
guard let image = image else {
|
||||
|
@ -33,10 +33,18 @@ public func peerInfoProfilePhotos(context: AccountContext, peerId: EnginePeer.Id
|
||||
|> mapToSignal { entries -> Signal<(Bool, [AvatarGalleryEntry])?, NoError> in
|
||||
if let entries = entries {
|
||||
if let firstEntry = entries.first {
|
||||
return context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer -> Signal<(Bool, [AvatarGalleryEntry])?, NoError>in
|
||||
return fetchedAvatarGalleryEntries(engine: context.engine, account: context.account, peer: peer, firstEntry: firstEntry)
|
||||
|> map(Optional.init)
|
||||
return context.account.postbox.peerView(id: peerId)
|
||||
|> 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
|
||||
}
|
||||
return fetchedAvatarGalleryEntries(engine: context.engine, account: context.account, peer: peer, firstEntry: firstEntry, secondEntry: secondEntry)
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single((true, []))
|
||||
@ -268,7 +276,7 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account, peer: Peer, firstEntry: AvatarGalleryEntry) -> Signal<(Bool, [AvatarGalleryEntry]), NoError> {
|
||||
public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account, peer: Peer, firstEntry: AvatarGalleryEntry, secondEntry: TelegramMediaImage?) -> Signal<(Bool, [AvatarGalleryEntry]), NoError> {
|
||||
let initialEntries = [firstEntry]
|
||||
return Signal<(Bool, [AvatarGalleryEntry]), NoError>.single((false, initialEntries))
|
||||
|> then(
|
||||
@ -313,6 +321,10 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
var photos = photos
|
||||
if let secondEntry {
|
||||
photos.insert(TelegramPeerPhoto(image: secondEntry, reference: secondEntry.reference, date: 0, index: 1, totalCount: 0, messageId: nil), at: 1)
|
||||
}
|
||||
for photo in photos {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
|
||||
if result.isEmpty, let first = initialEntries.first {
|
||||
|
@ -522,6 +522,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
var highlightedSide: Bool?
|
||||
public let stripContainerNode: ASDisplayNode
|
||||
public let highlightContainerNode: ASDisplayNode
|
||||
private let setByYouNode: ImmediateTextNode
|
||||
public private(set) var galleryEntries: [AvatarGalleryEntry] = []
|
||||
private var items: [PeerInfoAvatarListItem] = []
|
||||
private var itemNodes: [MediaResourceId: PeerInfoAvatarListItemNode] = [:]
|
||||
@ -689,6 +690,10 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
self.highlightContainerNode.addSubnode(self.leftHighlightNode)
|
||||
self.highlightContainerNode.addSubnode(self.rightHighlightNode)
|
||||
|
||||
self.setByYouNode = ImmediateTextNode()
|
||||
self.setByYouNode.alpha = 0.0
|
||||
self.setByYouNode.isUserInteractionEnabled = false
|
||||
|
||||
self.controlsContainerNode = ASDisplayNode()
|
||||
self.controlsContainerNode.isUserInteractionEnabled = false
|
||||
|
||||
@ -758,6 +763,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
self.controlsContainerNode.addSubnode(self.stripContainerNode)
|
||||
self.controlsClippingNode.addSubnode(self.controlsContainerNode)
|
||||
self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode)
|
||||
self.stripContainerNode.addSubnode(self.setByYouNode)
|
||||
|
||||
self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
@ -1254,6 +1260,20 @@ 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]
|
||||
if let representation = currentItem.representations.first?.representation, representation.isPersonal {
|
||||
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)
|
||||
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)
|
||||
} else {
|
||||
transition.updateAlpha(node: self.setByYouNode, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
for itemNode in addedItemNodesForAdditiveTransition {
|
||||
transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: additiveTransitionOffset, y: 0.0))
|
||||
}
|
||||
|
@ -6165,7 +6165,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
// return controller
|
||||
// }
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos && !fromGallery, hasViewButton: false, personalPhoto: peerId.namespace == Namespaces.Peer.CloudUser, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false)!
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos && !fromGallery, hasViewButton: false, personalPhoto: peerId.namespace == Namespaces.Peer.CloudUser, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil)!
|
||||
mixin.forceDark = true
|
||||
mixin.stickersContext = paintStickersContext
|
||||
let _ = strongSelf.currentAvatarMixin.swap(mixin)
|
||||
|
@ -160,7 +160,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
var videoRepresentations: [TelegramMediaImage.VideoRepresentation] = []
|
||||
switch photo {
|
||||
case let .photo(photo: apiPhoto, users: _):
|
||||
case let .photo(apiPhoto, _):
|
||||
switch apiPhoto {
|
||||
case .photoEmpty:
|
||||
break
|
||||
@ -303,13 +303,33 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
}
|
||||
} else {
|
||||
if let _ = peer as? TelegramUser {
|
||||
let signal: Signal<Api.photos.Photo, UploadPeerPhotoError> = network.request(Api.functions.photos.updateProfilePhoto(id: Api.InputPhoto.inputPhotoEmpty))
|
||||
let request: Signal<Api.photos.Photo, MTRpcError>
|
||||
if peer.id == accountPeerId {
|
||||
request = network.request(Api.functions.photos.updateProfilePhoto(id: Api.InputPhoto.inputPhotoEmpty))
|
||||
} else if let inputUser = apiInputUser(peer) {
|
||||
request = network.request(Api.functions.photos.uploadContactProfilePhoto(flags: 0, userId: inputUser, file: nil, video: nil, videoStartTs: nil))
|
||||
} else {
|
||||
request = .complete()
|
||||
}
|
||||
|
||||
return request
|
||||
|> mapError { _ -> UploadPeerPhotoError in
|
||||
return .generic
|
||||
}
|
||||
|
||||
return signal
|
||||
|> mapToSignal { _ -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||
|> mapToSignal { photo -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||
if peer.id != accountPeerId {
|
||||
var updatedUsers: [TelegramUser] = []
|
||||
switch photo {
|
||||
case let .photo(_, apiUsers):
|
||||
updatedUsers = apiUsers.map { TelegramUser(user: $0) }
|
||||
}
|
||||
return postbox.transaction { transaction -> UpdatePeerPhotoStatus in
|
||||
updatePeers(transaction: transaction, peers: updatedUsers, update: { (_, updatedPeer) -> Peer? in
|
||||
return updatedPeer
|
||||
})
|
||||
return .complete([])
|
||||
} |> mapError { _ -> UploadPeerPhotoError in }
|
||||
}
|
||||
return .single(.complete([]))
|
||||
}
|
||||
} else {
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Peer Info/AlertArrow.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Peer Info/AlertArrow.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "arrow (2).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
161
submodules/TelegramUI/Images.xcassets/Peer Info/AlertArrow.imageset/arrow (2).pdf
vendored
Normal file
161
submodules/TelegramUI/Images.xcassets/Peer Info/AlertArrow.imageset/arrow (2).pdf
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< /Type /XObject
|
||||
/Length 2 0 R
|
||||
/Group << /Type /Group
|
||||
/S /Transparency
|
||||
>>
|
||||
/Subtype /Form
|
||||
/Resources << >>
|
||||
/BBox [ 0.000000 0.000000 10.000000 16.000000 ]
|
||||
>>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 1.500000 -1.195312 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.707107 16.902420 m
|
||||
0.316583 17.292944 -0.316583 17.292944 -0.707107 16.902420 c
|
||||
-1.097631 16.511894 -1.097631 15.878730 -0.707107 15.488206 c
|
||||
0.707107 16.902420 l
|
||||
h
|
||||
7.000000 9.195312 m
|
||||
7.707107 8.488206 l
|
||||
8.097631 8.878730 8.097631 9.511895 7.707107 9.902419 c
|
||||
7.000000 9.195312 l
|
||||
h
|
||||
-0.707107 2.902419 m
|
||||
-1.097631 2.511895 -1.097631 1.878730 -0.707107 1.488206 c
|
||||
-0.316583 1.097681 0.316583 1.097681 0.707107 1.488206 c
|
||||
-0.707107 2.902419 l
|
||||
h
|
||||
-0.707107 15.488206 m
|
||||
6.292893 8.488206 l
|
||||
7.707107 9.902419 l
|
||||
0.707107 16.902420 l
|
||||
-0.707107 15.488206 l
|
||||
h
|
||||
6.292893 9.902419 m
|
||||
-0.707107 2.902419 l
|
||||
0.707107 1.488206 l
|
||||
7.707107 8.488206 l
|
||||
6.292893 9.902419 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
781
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
<< /Type /XObject
|
||||
/Length 4 0 R
|
||||
/Group << /Type /Group
|
||||
/S /Transparency
|
||||
>>
|
||||
/Subtype /Form
|
||||
/Resources << >>
|
||||
/BBox [ 0.000000 0.000000 10.000000 16.000000 ]
|
||||
>>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 16.000000 m
|
||||
10.000000 16.000000 l
|
||||
10.000000 0.000000 l
|
||||
0.000000 0.000000 l
|
||||
0.000000 16.000000 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
232
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /XObject << /X1 1 0 R >>
|
||||
/ExtGState << /E1 << /SMask << /Type /Mask
|
||||
/G 3 0 R
|
||||
/S /Alpha
|
||||
>>
|
||||
/Type /ExtGState
|
||||
>> >>
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Length 7 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
/E1 gs
|
||||
/X1 Do
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
46
|
||||
endobj
|
||||
|
||||
8 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 10.000000 16.000000 ]
|
||||
/Resources 5 0 R
|
||||
/Contents 6 0 R
|
||||
/Parent 9 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
9 0 obj
|
||||
<< /Kids [ 8 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
10 0 obj
|
||||
<< /Pages 9 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 11
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000001039 00000 n
|
||||
0000001061 00000 n
|
||||
0000001541 00000 n
|
||||
0000001563 00000 n
|
||||
0000001861 00000 n
|
||||
0000001963 00000 n
|
||||
0000001984 00000 n
|
||||
0000002157 00000 n
|
||||
0000002231 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 10 0 R
|
||||
/Size 11
|
||||
>>
|
||||
startxref
|
||||
2291
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Peer Info/SuggestAvatar.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Peer Info/SuggestAvatar.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "suggestphoto_30.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
500
submodules/TelegramUI/Images.xcassets/Peer Info/SuggestAvatar.imageset/suggestphoto_30.pdf
vendored
Normal file
500
submodules/TelegramUI/Images.xcassets/Peer Info/SuggestAvatar.imageset/suggestphoto_30.pdf
vendored
Normal file
@ -0,0 +1,500 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.750031 4.915199 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
7.250000 0.669800 m
|
||||
7.617270 0.669800 7.915000 0.967531 7.915000 1.334801 c
|
||||
7.915000 1.702070 7.617270 1.999802 7.250000 1.999802 c
|
||||
7.250000 0.669800 l
|
||||
h
|
||||
15.250000 1.999802 m
|
||||
14.882730 1.999802 14.585000 1.702070 14.585000 1.334801 c
|
||||
14.585000 0.967531 14.882730 0.669800 15.250000 0.669800 c
|
||||
15.250000 1.999802 l
|
||||
h
|
||||
1.638029 1.661781 m
|
||||
1.939932 2.254301 l
|
||||
1.638029 1.661781 l
|
||||
h
|
||||
5.406044 18.011244 m
|
||||
4.995583 18.534452 l
|
||||
5.406044 18.011244 l
|
||||
h
|
||||
4.411342 17.599224 m
|
||||
4.491065 16.939022 l
|
||||
4.411342 17.599224 l
|
||||
h
|
||||
7.861537 20.029541 m
|
||||
7.706295 20.676167 l
|
||||
7.861537 20.029541 l
|
||||
h
|
||||
6.562742 19.147543 m
|
||||
7.032968 18.677317 l
|
||||
6.562742 19.147543 l
|
||||
h
|
||||
15.216570 19.790081 m
|
||||
14.869108 19.223076 l
|
||||
15.216570 19.790081 l
|
||||
h
|
||||
14.638464 20.029541 m
|
||||
14.793705 20.676167 l
|
||||
14.638464 20.029541 l
|
||||
h
|
||||
18.088657 17.599224 m
|
||||
18.008936 16.939022 l
|
||||
18.088657 17.599224 l
|
||||
h
|
||||
16.734951 18.349850 m
|
||||
16.264725 17.879623 l
|
||||
16.734951 18.349850 l
|
||||
h
|
||||
17.093956 18.011244 m
|
||||
16.683493 17.488037 l
|
||||
17.093956 18.011244 l
|
||||
h
|
||||
22.413767 15.298920 m
|
||||
23.059650 15.457216 l
|
||||
22.413767 15.298920 l
|
||||
h
|
||||
20.214119 17.498568 m
|
||||
20.055822 16.852682 l
|
||||
20.214119 17.498568 l
|
||||
h
|
||||
22.173019 2.972830 m
|
||||
22.765539 2.670925 l
|
||||
22.173019 2.972830 l
|
||||
h
|
||||
20.861971 1.661781 m
|
||||
20.560068 2.254301 l
|
||||
20.861971 1.661781 l
|
||||
h
|
||||
0.086234 15.298920 m
|
||||
-0.559651 15.457216 l
|
||||
0.086234 15.298920 l
|
||||
h
|
||||
23.165001 6.134801 m
|
||||
23.165001 13.666742 l
|
||||
21.834999 13.666742 l
|
||||
21.834999 6.134801 l
|
||||
23.165001 6.134801 l
|
||||
h
|
||||
17.205177 18.820076 m
|
||||
16.407484 19.617769 l
|
||||
15.467031 18.677317 l
|
||||
16.264725 17.879623 l
|
||||
17.205177 18.820076 l
|
||||
h
|
||||
13.674517 20.749802 m
|
||||
8.825483 20.749802 l
|
||||
8.825483 19.419800 l
|
||||
13.674517 19.419800 l
|
||||
13.674517 20.749802 l
|
||||
h
|
||||
6.092515 19.617769 m
|
||||
5.294821 18.820074 l
|
||||
6.235273 17.879622 l
|
||||
7.032968 18.677317 l
|
||||
6.092515 19.617769 l
|
||||
h
|
||||
-0.665000 13.666742 m
|
||||
-0.665000 6.459801 l
|
||||
0.665000 6.459801 l
|
||||
0.665000 13.666742 l
|
||||
-0.665000 13.666742 l
|
||||
h
|
||||
-0.665000 6.459801 m
|
||||
-0.665000 6.134801 l
|
||||
0.665000 6.134801 l
|
||||
0.665000 6.459801 l
|
||||
-0.665000 6.459801 l
|
||||
h
|
||||
4.800000 0.669800 m
|
||||
7.250000 0.669800 l
|
||||
7.250000 1.999802 l
|
||||
4.800000 1.999802 l
|
||||
4.800000 0.669800 l
|
||||
h
|
||||
15.250000 0.669800 m
|
||||
17.699999 0.669800 l
|
||||
17.699999 1.999802 l
|
||||
15.250000 1.999802 l
|
||||
15.250000 0.669800 l
|
||||
h
|
||||
-0.665000 6.134801 m
|
||||
-0.665000 5.305696 -0.665517 4.643871 -0.621919 4.110254 c
|
||||
-0.577686 3.568874 -0.484757 3.101164 -0.265539 2.670925 c
|
||||
0.919500 3.274733 l
|
||||
0.811737 3.486229 0.741177 3.759426 0.703664 4.218559 c
|
||||
0.665517 4.685454 0.665000 5.283749 0.665000 6.134801 c
|
||||
-0.665000 6.134801 l
|
||||
h
|
||||
4.800000 1.999802 m
|
||||
3.948948 1.999802 3.350653 2.000319 2.883758 2.038465 c
|
||||
2.424626 2.075977 2.151429 2.146538 1.939932 2.254301 c
|
||||
1.336125 1.069262 l
|
||||
1.766364 0.850044 2.234073 0.757114 2.775454 0.712881 c
|
||||
3.309071 0.669283 3.970894 0.669800 4.800000 0.669800 c
|
||||
4.800000 1.999802 l
|
||||
h
|
||||
-0.265539 2.670925 m
|
||||
0.085837 1.981312 0.646511 1.420637 1.336125 1.069262 c
|
||||
1.939932 2.254301 l
|
||||
1.500574 2.478165 1.143364 2.835375 0.919500 3.274733 c
|
||||
-0.265539 2.670925 l
|
||||
h
|
||||
5.294821 18.820074 m
|
||||
5.107314 18.632566 5.051449 18.578279 4.995583 18.534452 c
|
||||
5.816506 17.488037 l
|
||||
5.949968 17.592739 6.070329 17.714678 6.235273 17.879622 c
|
||||
5.294821 18.820074 l
|
||||
h
|
||||
3.918058 16.919800 m
|
||||
4.151325 16.919800 4.322658 16.918686 4.491065 16.939022 c
|
||||
4.331619 18.259430 l
|
||||
4.261125 18.250916 4.183235 18.249802 3.918058 18.249802 c
|
||||
3.918058 16.919800 l
|
||||
h
|
||||
4.995583 18.534452 m
|
||||
4.803562 18.383810 4.573919 18.288689 4.331619 18.259430 c
|
||||
4.491065 16.939022 l
|
||||
4.974757 16.997429 5.433183 17.187315 5.816506 17.488037 c
|
||||
4.995583 18.534452 l
|
||||
h
|
||||
8.825483 20.749802 m
|
||||
8.367955 20.749802 8.030805 20.754074 7.706295 20.676167 c
|
||||
8.016778 19.382915 l
|
||||
8.152618 19.415527 8.304649 19.419800 8.825483 19.419800 c
|
||||
8.825483 20.749802 l
|
||||
h
|
||||
7.032968 18.677317 m
|
||||
7.401253 19.045601 7.511777 19.150082 7.630892 19.223076 c
|
||||
6.935968 20.357086 l
|
||||
6.651416 20.182713 6.416037 19.941290 6.092515 19.617769 c
|
||||
7.032968 18.677317 l
|
||||
h
|
||||
7.706295 20.676167 m
|
||||
7.434369 20.610882 7.174412 20.503204 6.935968 20.357086 c
|
||||
7.630892 19.223076 l
|
||||
7.750337 19.296272 7.880559 19.350212 8.016778 19.382915 c
|
||||
7.706295 20.676167 l
|
||||
h
|
||||
16.407484 19.617769 m
|
||||
16.083963 19.941290 15.848584 20.182713 15.564032 20.357086 c
|
||||
14.869108 19.223076 l
|
||||
14.988222 19.150082 15.098746 19.045603 15.467031 18.677317 c
|
||||
16.407484 19.617769 l
|
||||
h
|
||||
13.674517 19.419800 m
|
||||
14.195351 19.419800 14.347382 19.415527 14.483222 19.382915 c
|
||||
14.793705 20.676167 l
|
||||
14.469195 20.754074 14.132045 20.749802 13.674517 20.749802 c
|
||||
13.674517 19.419800 l
|
||||
h
|
||||
15.564032 20.357086 m
|
||||
15.325588 20.503204 15.065631 20.610882 14.793705 20.676167 c
|
||||
14.483222 19.382915 l
|
||||
14.619441 19.350212 14.749663 19.296272 14.869108 19.223076 c
|
||||
15.564032 20.357086 l
|
||||
h
|
||||
18.581942 18.249802 m
|
||||
18.316765 18.249802 18.238874 18.250916 18.168381 18.259430 c
|
||||
18.008936 16.939022 l
|
||||
18.177341 16.918686 18.348675 16.919800 18.581942 16.919800 c
|
||||
18.581942 18.249802 l
|
||||
h
|
||||
16.264725 17.879623 m
|
||||
16.429670 17.714678 16.550032 17.592739 16.683493 17.488037 c
|
||||
17.504417 18.534452 l
|
||||
17.448551 18.578279 17.392687 18.632566 17.205177 18.820076 c
|
||||
16.264725 17.879623 l
|
||||
h
|
||||
18.168381 18.259430 m
|
||||
17.926081 18.288689 17.696438 18.383810 17.504417 18.534452 c
|
||||
16.683493 17.488037 l
|
||||
17.066816 17.187315 17.525242 16.997429 18.008936 16.939022 c
|
||||
18.168381 18.259430 l
|
||||
h
|
||||
23.165001 13.666742 m
|
||||
23.165001 14.481091 23.169819 15.007710 23.059650 15.457216 c
|
||||
21.767881 15.140623 l
|
||||
21.830181 14.886425 21.834999 14.559493 21.834999 13.666742 c
|
||||
23.165001 13.666742 l
|
||||
h
|
||||
18.581942 16.919800 m
|
||||
19.474693 16.919800 19.801624 16.914982 20.055822 16.852682 c
|
||||
20.372416 18.144451 l
|
||||
19.922909 18.254620 19.396290 18.249802 18.581942 18.249802 c
|
||||
18.581942 16.919800 l
|
||||
h
|
||||
23.059650 15.457216 m
|
||||
22.734556 16.783680 21.698879 17.819357 20.372416 18.144451 c
|
||||
20.055822 16.852682 l
|
||||
20.900923 16.645561 21.560760 15.985723 21.767881 15.140623 c
|
||||
23.059650 15.457216 l
|
||||
h
|
||||
21.834999 6.134801 m
|
||||
21.834999 5.283749 21.834482 4.685454 21.796335 4.218559 c
|
||||
21.758823 3.759426 21.688263 3.486229 21.580500 3.274733 c
|
||||
22.765539 2.670925 l
|
||||
22.984756 3.101164 23.077686 3.568874 23.121920 4.110254 c
|
||||
23.165518 4.643871 23.165001 5.305695 23.165001 6.134801 c
|
||||
21.834999 6.134801 l
|
||||
h
|
||||
17.699999 0.669800 m
|
||||
18.529106 0.669800 19.190929 0.669283 19.724546 0.712881 c
|
||||
20.265926 0.757114 20.733637 0.850044 21.163876 1.069262 c
|
||||
20.560068 2.254301 l
|
||||
20.348572 2.146538 20.075375 2.075977 19.616241 2.038465 c
|
||||
19.149347 2.000319 18.551052 1.999802 17.699999 1.999802 c
|
||||
17.699999 0.669800 l
|
||||
h
|
||||
21.580500 3.274733 m
|
||||
21.356636 2.835375 20.999426 2.478165 20.560068 2.254301 c
|
||||
21.163876 1.069262 l
|
||||
21.853489 1.420637 22.414164 1.981312 22.765539 2.670925 c
|
||||
21.580500 3.274733 l
|
||||
h
|
||||
3.918058 18.249802 m
|
||||
3.103710 18.249802 2.577092 18.254620 2.127584 18.144451 c
|
||||
2.444177 16.852682 l
|
||||
2.698376 16.914982 3.025307 16.919800 3.918058 16.919800 c
|
||||
3.918058 18.249802 l
|
||||
h
|
||||
0.665000 13.666742 m
|
||||
0.665000 14.559494 0.669818 14.886425 0.732119 15.140623 c
|
||||
-0.559651 15.457216 l
|
||||
-0.669818 15.007710 -0.665000 14.481091 -0.665000 13.666742 c
|
||||
0.665000 13.666742 l
|
||||
h
|
||||
2.127584 18.144451 m
|
||||
0.801121 17.819357 -0.234555 16.783680 -0.559651 15.457216 c
|
||||
0.732119 15.140623 l
|
||||
0.939240 15.985723 1.599077 16.645561 2.444177 16.852682 c
|
||||
2.127584 18.144451 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 10.312500 7.670013 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
6.687500 1.329994 m
|
||||
6.687500 0.664994 l
|
||||
7.054770 0.664994 7.352500 0.962725 7.352500 1.329994 c
|
||||
6.687500 1.329994 l
|
||||
h
|
||||
6.687500 2.776849 m
|
||||
6.403426 3.378120 l
|
||||
6.170848 3.268237 6.022500 3.034078 6.022500 2.776849 c
|
||||
6.687500 2.776849 l
|
||||
h
|
||||
2.687500 2.776849 m
|
||||
3.352500 2.776849 l
|
||||
3.352500 3.034078 3.204152 3.268237 2.971574 3.378120 c
|
||||
2.687500 2.776849 l
|
||||
h
|
||||
2.687500 1.329994 m
|
||||
2.022500 1.329994 l
|
||||
2.022500 0.962725 2.320231 0.664994 2.687500 0.664994 c
|
||||
2.687500 1.329994 l
|
||||
h
|
||||
0.665000 7.017487 m
|
||||
0.665000 9.239052 2.465935 11.039987 4.687500 11.039987 c
|
||||
4.687500 12.369987 l
|
||||
1.731396 12.369987 -0.665000 9.973591 -0.665000 7.017487 c
|
||||
0.665000 7.017487 l
|
||||
h
|
||||
4.687500 11.039987 m
|
||||
6.909065 11.039987 8.710000 9.239052 8.710000 7.017487 c
|
||||
10.040000 7.017487 l
|
||||
10.040000 9.973591 7.643604 12.369987 4.687500 12.369987 c
|
||||
4.687500 11.039987 l
|
||||
h
|
||||
8.710000 7.017487 m
|
||||
8.710000 5.410845 7.768091 4.022863 6.403426 3.378120 c
|
||||
6.971574 2.175577 l
|
||||
8.783873 3.031808 10.040000 4.877287 10.040000 7.017487 c
|
||||
8.710000 7.017487 l
|
||||
h
|
||||
6.022500 2.776849 m
|
||||
6.022500 1.329994 l
|
||||
7.352500 1.329994 l
|
||||
7.352500 2.776849 l
|
||||
6.022500 2.776849 l
|
||||
h
|
||||
2.971574 3.378120 m
|
||||
1.606909 4.022863 0.665000 5.410845 0.665000 7.017487 c
|
||||
-0.665000 7.017487 l
|
||||
-0.665000 4.877287 0.591128 3.031808 2.403426 2.175577 c
|
||||
2.971574 3.378120 l
|
||||
h
|
||||
6.687500 1.994994 m
|
||||
2.687500 1.994994 l
|
||||
2.687500 0.664994 l
|
||||
6.687500 0.664994 l
|
||||
6.687500 1.994994 l
|
||||
h
|
||||
3.352500 1.329994 m
|
||||
3.352500 2.776849 l
|
||||
2.022500 2.776849 l
|
||||
2.022500 1.329994 l
|
||||
3.352500 1.329994 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 13.500000 11.577972 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.368876 3.975341 m
|
||||
0.063289 4.179066 -0.349589 4.096490 -0.553313 3.790903 c
|
||||
-0.757038 3.485317 -0.674462 3.072438 -0.368876 2.868714 c
|
||||
0.368876 3.975341 l
|
||||
h
|
||||
3.368876 2.868714 m
|
||||
3.674462 3.072438 3.757038 3.485317 3.553313 3.790903 c
|
||||
3.349589 4.096490 2.936711 4.179066 2.631124 3.975341 c
|
||||
3.368876 2.868714 l
|
||||
h
|
||||
0.835000 1.422028 m
|
||||
0.835000 1.054758 1.132731 0.757028 1.500000 0.757028 c
|
||||
1.867269 0.757028 2.165000 1.054758 2.165000 1.422028 c
|
||||
0.835000 1.422028 l
|
||||
h
|
||||
-0.368876 2.868714 m
|
||||
1.131124 1.868714 l
|
||||
1.868876 2.975341 l
|
||||
0.368876 3.975341 l
|
||||
-0.368876 2.868714 l
|
||||
h
|
||||
1.868876 1.868714 m
|
||||
3.368876 2.868714 l
|
||||
2.631124 3.975341 l
|
||||
1.131124 2.975341 l
|
||||
1.868876 1.868714 l
|
||||
h
|
||||
0.835000 2.422028 m
|
||||
0.835000 1.422028 l
|
||||
2.165000 1.422028 l
|
||||
2.165000 2.422028 l
|
||||
0.835000 2.422028 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 21.250031 17.500000 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
2.500000 1.250000 m
|
||||
2.500000 0.559644 1.940356 0.000000 1.250000 0.000000 c
|
||||
0.559644 0.000000 0.000000 0.559644 0.000000 1.250000 c
|
||||
0.000000 1.940356 0.559644 2.500000 1.250000 2.500000 c
|
||||
1.940356 2.500000 2.500000 1.940356 2.500000 1.250000 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 13.000000 4.920006 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 4.079994 m
|
||||
0.000000 4.744994 l
|
||||
-0.367269 4.744994 -0.665000 4.447264 -0.665000 4.079994 c
|
||||
0.000000 4.079994 l
|
||||
h
|
||||
4.000000 4.079994 m
|
||||
4.665000 4.079994 l
|
||||
4.665000 4.447264 4.367270 4.744994 4.000000 4.744994 c
|
||||
4.000000 4.079994 l
|
||||
h
|
||||
-0.665000 4.079994 m
|
||||
-0.665000 3.329994 l
|
||||
0.665000 3.329994 l
|
||||
0.665000 4.079994 l
|
||||
-0.665000 4.079994 l
|
||||
h
|
||||
4.665000 3.329994 m
|
||||
4.665000 4.079994 l
|
||||
3.335000 4.079994 l
|
||||
3.335000 3.329994 l
|
||||
4.665000 3.329994 l
|
||||
h
|
||||
4.000000 4.744994 m
|
||||
0.000000 4.744994 l
|
||||
0.000000 3.414994 l
|
||||
4.000000 3.414994 l
|
||||
4.000000 4.744994 l
|
||||
h
|
||||
2.000000 0.664994 m
|
||||
3.471839 0.664994 4.665000 1.858155 4.665000 3.329994 c
|
||||
3.335000 3.329994 l
|
||||
3.335000 2.592694 2.737300 1.994994 2.000000 1.994994 c
|
||||
2.000000 0.664994 l
|
||||
h
|
||||
-0.665000 3.329994 m
|
||||
-0.665000 1.858155 0.528161 0.664994 2.000000 0.664994 c
|
||||
2.000000 1.994994 l
|
||||
1.262700 1.994994 0.665000 2.592694 0.665000 3.329994 c
|
||||
-0.665000 3.329994 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
11022
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000011112 00000 n
|
||||
0000011136 00000 n
|
||||
0000011309 00000 n
|
||||
0000011383 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
11442
|
||||
%%EOF
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Icon-23.pdf",
|
||||
"filename" : "addphoto_30.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
@ -1,131 +0,0 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 1.335022 2.335083 cm
|
||||
0.000000 0.478431 1.000000 scn
|
||||
12.735368 21.999956 m
|
||||
12.289006 21.999956 11.872177 21.776876 11.624580 21.405481 c
|
||||
10.812046 20.186680 l
|
||||
10.317780 19.445280 9.485683 18.999956 8.594632 18.999956 c
|
||||
6.665000 18.999956 l
|
||||
5.927700 18.999956 5.330000 18.402256 5.330000 17.664955 c
|
||||
5.330000 11.664956 l
|
||||
5.330000 11.297687 5.032269 10.999956 4.665000 10.999956 c
|
||||
4.297730 10.999956 4.000000 11.297687 4.000000 11.664956 c
|
||||
4.000000 17.664955 l
|
||||
4.000000 19.136795 5.193161 20.329956 6.665000 20.329956 c
|
||||
8.594632 20.329956 l
|
||||
9.040994 20.329956 9.457823 20.553036 9.705420 20.924431 c
|
||||
10.517954 22.143232 l
|
||||
11.012220 22.884632 11.844316 23.329956 12.735368 23.329956 c
|
||||
16.594631 23.329956 l
|
||||
17.485683 23.329956 18.317780 22.884632 18.812046 22.143232 c
|
||||
19.624580 20.924431 l
|
||||
19.872177 20.553036 20.289005 20.329956 20.735367 20.329956 c
|
||||
22.665001 20.329956 l
|
||||
24.136837 20.329956 25.330002 19.136795 25.330002 17.664955 c
|
||||
25.330002 6.664955 l
|
||||
25.330002 5.193119 24.136837 3.999954 22.665001 3.999954 c
|
||||
11.665000 3.999954 l
|
||||
11.297730 3.999954 11.000000 4.297688 11.000000 4.664955 c
|
||||
11.000000 5.032227 11.297730 5.329956 11.665000 5.329956 c
|
||||
22.665001 5.329956 l
|
||||
23.402302 5.329956 24.000000 5.927654 24.000000 6.664955 c
|
||||
24.000000 17.664955 l
|
||||
24.000000 18.402256 23.402302 18.999956 22.665001 18.999956 c
|
||||
20.735367 18.999956 l
|
||||
19.844316 18.999956 19.012220 19.445280 18.517954 20.186680 c
|
||||
17.705420 21.405481 l
|
||||
17.457823 21.776876 17.040993 21.999956 16.594631 21.999956 c
|
||||
12.735368 21.999956 l
|
||||
h
|
||||
5.330000 8.664956 m
|
||||
5.330000 9.032226 5.032269 9.329956 4.665000 9.329956 c
|
||||
4.297730 9.329956 4.000000 9.032226 4.000000 8.664956 c
|
||||
4.000000 5.329956 l
|
||||
0.665000 5.329956 l
|
||||
0.297731 5.329956 0.000000 5.032225 0.000000 4.664955 c
|
||||
0.000000 4.297686 0.297731 3.999954 0.665000 3.999954 c
|
||||
4.000000 3.999954 l
|
||||
4.000000 0.664955 l
|
||||
4.000000 0.297688 4.297730 -0.000044 4.665000 -0.000044 c
|
||||
5.032269 -0.000044 5.330000 0.297688 5.330000 0.664955 c
|
||||
5.330000 3.999954 l
|
||||
8.665000 3.999954 l
|
||||
9.032269 3.999954 9.330000 4.297686 9.330000 4.664955 c
|
||||
9.330000 5.032225 9.032269 5.329956 8.665000 5.329956 c
|
||||
5.330000 5.329956 l
|
||||
5.330000 8.664956 l
|
||||
h
|
||||
11.330000 12.664956 m
|
||||
11.330000 14.506825 12.823131 15.999956 14.665000 15.999956 c
|
||||
16.506870 15.999956 18.000000 14.506825 18.000000 12.664956 c
|
||||
18.000000 10.823086 16.506870 9.329956 14.665000 9.329956 c
|
||||
12.823131 9.329956 11.330000 10.823086 11.330000 12.664956 c
|
||||
h
|
||||
14.665000 17.329956 m
|
||||
12.088592 17.329956 10.000000 15.241364 10.000000 12.664956 c
|
||||
10.000000 10.088548 12.088592 7.999956 14.665000 7.999956 c
|
||||
17.241409 7.999956 19.330000 10.088548 19.330000 12.664956 c
|
||||
19.330000 15.241364 17.241409 17.329956 14.665000 17.329956 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
2753
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000002843 00000 n
|
||||
0000002866 00000 n
|
||||
0000003039 00000 n
|
||||
0000003113 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
3172
|
||||
%%EOF
|
183
submodules/TelegramUI/Images.xcassets/Settings/SetAvatar.imageset/addphoto_30.pdf
vendored
Normal file
183
submodules/TelegramUI/Images.xcassets/Settings/SetAvatar.imageset/addphoto_30.pdf
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.840027 3.334705 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
11.735510 22.330292 m
|
||||
11.667685 22.330313 l
|
||||
11.244255 22.330513 10.924585 22.330666 10.616322 22.256659 c
|
||||
10.344395 22.191374 10.084438 22.083696 9.845995 21.937578 c
|
||||
9.575688 21.771935 9.349753 21.545786 9.050485 21.246233 c
|
||||
9.002542 21.198259 l
|
||||
8.204847 20.400566 l
|
||||
8.017340 20.213058 7.961475 20.158772 7.905609 20.114943 c
|
||||
7.713588 19.964300 7.483945 19.869179 7.241645 19.839920 c
|
||||
7.171151 19.831408 7.093261 19.830292 6.828084 19.830292 c
|
||||
6.729855 19.830307 l
|
||||
5.970903 19.830494 5.468783 19.830616 5.037611 19.724943 c
|
||||
3.711147 19.399847 2.675471 18.364172 2.350375 17.037708 c
|
||||
2.244702 16.606535 2.244824 16.104416 2.245010 15.345463 c
|
||||
2.245026 15.247234 l
|
||||
2.245026 11.040292 l
|
||||
2.245026 10.673022 2.542757 10.375292 2.910026 10.375292 c
|
||||
3.277296 10.375292 3.575026 10.673022 3.575026 11.040292 c
|
||||
3.575026 15.247234 l
|
||||
3.575026 16.139984 3.579845 16.466915 3.642145 16.721115 c
|
||||
3.849266 17.566216 4.509103 18.226051 5.354204 18.433174 c
|
||||
5.608402 18.495474 5.935334 18.500292 6.828084 18.500292 c
|
||||
6.862669 18.500286 l
|
||||
6.862678 18.500286 l
|
||||
7.078507 18.500235 7.241119 18.500195 7.401091 18.519512 c
|
||||
7.884783 18.577921 8.343209 18.767807 8.726533 19.068527 c
|
||||
8.853310 19.167986 8.968266 19.282997 9.120847 19.435654 c
|
||||
9.145300 19.460114 l
|
||||
9.942994 20.257809 l
|
||||
10.311279 20.626093 10.421803 20.730574 10.540918 20.803566 c
|
||||
10.660363 20.876762 10.790585 20.930702 10.926804 20.963406 c
|
||||
11.062645 20.996017 11.214676 21.000292 11.735510 21.000292 c
|
||||
16.584543 21.000292 l
|
||||
17.105377 21.000292 17.257408 20.996017 17.393248 20.963406 c
|
||||
17.529467 20.930702 17.659689 20.876762 17.779135 20.803566 c
|
||||
17.898249 20.730574 18.008772 20.626093 18.377058 20.257809 c
|
||||
19.174751 19.460114 l
|
||||
19.199215 19.435642 l
|
||||
19.199238 19.435621 l
|
||||
19.351803 19.282984 19.466751 19.167980 19.593519 19.068527 c
|
||||
19.976843 18.767807 20.435268 18.577921 20.918962 18.519512 c
|
||||
21.078936 18.500195 21.241550 18.500235 21.457384 18.500286 c
|
||||
21.491968 18.500292 l
|
||||
22.384720 18.500292 22.711651 18.495474 22.965849 18.433174 c
|
||||
23.810949 18.226051 24.470787 17.566216 24.677908 16.721115 c
|
||||
24.740208 16.466915 24.745026 16.139984 24.745026 15.247233 c
|
||||
24.745026 7.715292 l
|
||||
24.745026 6.864240 24.744509 6.265945 24.706362 5.799051 c
|
||||
24.668850 5.339918 24.598289 5.066721 24.490526 4.855225 c
|
||||
24.266663 4.415867 23.909452 4.058657 23.470095 3.834793 c
|
||||
23.258598 3.727030 22.985401 3.656469 22.526268 3.618958 c
|
||||
22.059374 3.580811 21.461079 3.580294 20.610025 3.580294 c
|
||||
11.160027 3.580294 l
|
||||
10.792757 3.580294 10.495026 3.282562 10.495026 2.915293 c
|
||||
10.495026 2.548023 10.792757 2.250292 11.160027 2.250292 c
|
||||
20.610025 2.250292 l
|
||||
20.638830 2.250292 l
|
||||
20.638893 2.250292 l
|
||||
21.454515 2.250286 22.107164 2.250282 22.634573 2.293373 c
|
||||
23.175953 2.337606 23.643663 2.430536 24.073902 2.649754 c
|
||||
24.763515 3.001129 25.324190 3.561804 25.675566 4.251417 c
|
||||
25.894783 4.681656 25.987713 5.149366 26.031946 5.690746 c
|
||||
26.075037 6.218155 26.075033 6.870803 26.075027 7.686420 c
|
||||
26.075027 7.686486 l
|
||||
26.075027 7.715292 l
|
||||
26.075027 15.247233 l
|
||||
26.075043 15.345453 l
|
||||
26.075230 16.104412 26.075352 16.606533 25.969677 17.037708 c
|
||||
25.644583 18.364172 24.608906 19.399847 23.282442 19.724943 c
|
||||
22.851271 19.830616 22.349150 19.830494 21.590197 19.830307 c
|
||||
21.491968 19.830292 l
|
||||
21.226791 19.830292 21.148901 19.831408 21.078407 19.839920 c
|
||||
20.836107 19.869179 20.606464 19.964300 20.414444 20.114943 c
|
||||
20.358578 20.158772 20.302713 20.213058 20.115204 20.400566 c
|
||||
19.317511 21.198261 l
|
||||
19.269571 21.246229 l
|
||||
18.970303 21.545784 18.744366 21.771933 18.474058 21.937578 c
|
||||
18.235615 22.083696 17.975657 22.191374 17.703732 22.256659 c
|
||||
17.395468 22.330666 17.075798 22.330513 16.652369 22.330313 c
|
||||
16.584543 22.330292 l
|
||||
11.735510 22.330292 l
|
||||
h
|
||||
10.137527 11.352793 m
|
||||
10.137527 13.574358 11.938460 15.375292 14.160027 15.375292 c
|
||||
16.381592 15.375292 18.182526 13.574358 18.182526 11.352793 c
|
||||
18.182526 9.131227 16.381592 7.330292 14.160027 7.330292 c
|
||||
11.938460 7.330292 10.137527 9.131227 10.137527 11.352793 c
|
||||
h
|
||||
14.160027 16.705292 m
|
||||
11.203922 16.705292 8.807527 14.308896 8.807527 11.352793 c
|
||||
8.807527 8.396688 11.203922 6.000292 14.160027 6.000292 c
|
||||
17.116131 6.000292 19.512526 8.396688 19.512526 11.352793 c
|
||||
19.512526 14.308896 17.116131 16.705292 14.160027 16.705292 c
|
||||
h
|
||||
22.910027 15.415292 m
|
||||
22.910027 14.724936 22.350382 14.165293 21.660027 14.165293 c
|
||||
20.969671 14.165293 20.410027 14.724936 20.410027 15.415292 c
|
||||
20.410027 16.105648 20.969671 16.665291 21.660027 16.665291 c
|
||||
22.350382 16.665291 22.910027 16.105648 22.910027 15.415292 c
|
||||
h
|
||||
4.665000 9.330334 m
|
||||
5.032269 9.330334 5.330000 9.032602 5.330000 8.665333 c
|
||||
5.330000 5.330334 l
|
||||
8.665000 5.330334 l
|
||||
9.032269 5.330334 9.330000 5.032602 9.330000 4.665333 c
|
||||
9.330000 4.298063 9.032269 4.000332 8.665000 4.000332 c
|
||||
5.330000 4.000332 l
|
||||
5.330000 0.665333 l
|
||||
5.330000 0.298063 5.032269 0.000332 4.665000 0.000332 c
|
||||
4.297730 0.000332 4.000000 0.298063 4.000000 0.665333 c
|
||||
4.000000 4.000332 l
|
||||
0.665000 4.000332 l
|
||||
0.297731 4.000332 0.000000 4.298063 0.000000 4.665333 c
|
||||
0.000000 5.032602 0.297731 5.330334 0.665000 5.330334 c
|
||||
4.000000 5.330334 l
|
||||
4.000000 8.665333 l
|
||||
4.000000 9.032602 4.297730 9.330334 4.665000 9.330334 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5244
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000005334 00000 n
|
||||
0000005357 00000 n
|
||||
0000005530 00000 n
|
||||
0000005604 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
5663
|
||||
%%EOF
|
@ -454,7 +454,7 @@ public func createChannelController(context: AccountContext) -> ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false)!
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil)!
|
||||
let _ = currentAvatarMixin.swap(mixin)
|
||||
mixin.requestSearchController = { assetsController in
|
||||
let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in
|
||||
|
@ -727,7 +727,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
}
|
||||
}
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false)!
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil)!
|
||||
let _ = currentAvatarMixin.swap(mixin)
|
||||
mixin.requestSearchController = { assetsController in
|
||||
let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in
|
||||
|
@ -1,6 +1,8 @@
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import AvatarNode
|
||||
|
||||
enum PeerInfoScreenActionColor {
|
||||
case accent
|
||||
@ -18,14 +20,16 @@ final class PeerInfoScreenActionItem: PeerInfoScreenItem {
|
||||
let text: String
|
||||
let color: PeerInfoScreenActionColor
|
||||
let icon: UIImage?
|
||||
let iconSignal: Signal<UIImage?, NoError>?
|
||||
let alignment: PeerInfoScreenActionAligmnent
|
||||
let action: (() -> Void)?
|
||||
|
||||
init(id: AnyHashable, text: String, color: PeerInfoScreenActionColor = .accent, icon: UIImage? = nil, alignment: PeerInfoScreenActionAligmnent = .natural, action: (() -> Void)?) {
|
||||
init(id: AnyHashable, text: String, color: PeerInfoScreenActionColor = .accent, icon: UIImage? = nil, iconSignal: Signal<UIImage?, NoError>? = nil, alignment: PeerInfoScreenActionAligmnent = .natural, action: (() -> Void)?) {
|
||||
self.id = id
|
||||
self.text = text
|
||||
self.color = color
|
||||
self.icon = icon
|
||||
self.iconSignal = iconSignal
|
||||
self.alignment = alignment
|
||||
self.action = action
|
||||
}
|
||||
@ -45,6 +49,8 @@ private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode {
|
||||
|
||||
private var item: PeerInfoScreenActionItem?
|
||||
|
||||
private let iconDisposable = MetaDisposable()
|
||||
|
||||
override init() {
|
||||
var bringToFrontForHighlightImpl: (() -> Void)?
|
||||
self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() })
|
||||
@ -79,17 +85,21 @@ private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode {
|
||||
self.addSubnode(self.activateArea)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.iconDisposable.dispose()
|
||||
}
|
||||
|
||||
override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
guard let item = item as? PeerInfoScreenActionItem else {
|
||||
return 10.0
|
||||
}
|
||||
|
||||
self.item = item
|
||||
|
||||
|
||||
self.selectionNode.pressed = item.action
|
||||
|
||||
let sideInset: CGFloat = 16.0 + safeInsets.left
|
||||
var leftInset = (item.icon == nil ? sideInset : sideInset + 29.0 + 16.0)
|
||||
var leftInset = (item.icon == nil && item.iconSignal == nil ? sideInset : sideInset + 29.0 + 16.0)
|
||||
var iconInset = sideInset
|
||||
if case .peerList = item.alignment {
|
||||
leftInset += 5.0
|
||||
@ -126,6 +136,19 @@ private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode {
|
||||
self.iconNode.image = generateTintedImage(image: icon, color: textColorValue)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: iconInset, y: floorToScreenPixels((height - icon.size.height) / 2.0)), size: icon.size)
|
||||
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||
} else if let iconSignal = item.iconSignal {
|
||||
self.iconDisposable.set((iconSignal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] image in
|
||||
if let strongSelf = self, let image {
|
||||
strongSelf.iconNode.image = image
|
||||
let iconFrame = CGRect(origin: CGPoint(x: iconInset, y: floorToScreenPixels((height - image.size.height) / 2.0)), size: image.size)
|
||||
transition.updateFrame(node: strongSelf.iconNode, frame: iconFrame)
|
||||
}
|
||||
}))
|
||||
if self.iconNode.supernode == nil {
|
||||
self.addSubnode(self.iconNode)
|
||||
}
|
||||
|
||||
} else if self.iconNode.supernode != nil {
|
||||
self.iconNode.image = nil
|
||||
self.iconNode.removeFromSupernode()
|
||||
|
@ -668,7 +668,14 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
|
||||
clipStyle = .round
|
||||
}
|
||||
|
||||
if canEditPeerInfo(context: self.context, peer: peer, chatLocation: chatLocation, threadData: threadData) {
|
||||
var isPersonal = false
|
||||
if let updatingAvatar, case let .image(image) = updatingAvatar, image.isPersonal {
|
||||
isPersonal = true
|
||||
}
|
||||
|
||||
if canEditPeerInfo(context: self.context, peer: peer, chatLocation: chatLocation, threadData: threadData)
|
||||
|| isPersonal
|
||||
|| self.currentRepresentation != nil && updatingAvatar == nil {
|
||||
var overlayHidden = true
|
||||
if let updatingAvatar = updatingAvatar {
|
||||
overlayHidden = false
|
||||
|
@ -481,6 +481,9 @@ private final class PeerInfoInteraction {
|
||||
let editingOpenSoundSettings: () -> Void
|
||||
let editingToggleShowMessageText: (Bool) -> Void
|
||||
let requestDeleteContact: () -> Void
|
||||
let suggestPhoto: () -> Void
|
||||
let setCustomPhoto: () -> Void
|
||||
let resetCustomPhoto: () -> Void
|
||||
let openAddContact: () -> Void
|
||||
let updateBlocked: (Bool) -> Void
|
||||
let openReport: (PeerInfoReportType) -> Void
|
||||
@ -526,6 +529,9 @@ private final class PeerInfoInteraction {
|
||||
editingOpenSoundSettings: @escaping () -> Void,
|
||||
editingToggleShowMessageText: @escaping (Bool) -> Void,
|
||||
requestDeleteContact: @escaping () -> Void,
|
||||
suggestPhoto: @escaping () -> Void,
|
||||
setCustomPhoto: @escaping () -> Void,
|
||||
resetCustomPhoto: @escaping () -> Void,
|
||||
openChat: @escaping () -> Void,
|
||||
openAddContact: @escaping () -> Void,
|
||||
updateBlocked: @escaping (Bool) -> Void,
|
||||
@ -571,6 +577,9 @@ private final class PeerInfoInteraction {
|
||||
self.editingOpenSoundSettings = editingOpenSoundSettings
|
||||
self.editingToggleShowMessageText = editingToggleShowMessageText
|
||||
self.requestDeleteContact = requestDeleteContact
|
||||
self.suggestPhoto = suggestPhoto
|
||||
self.setCustomPhoto = setCustomPhoto
|
||||
self.resetCustomPhoto = resetCustomPhoto
|
||||
self.openChat = openChat
|
||||
self.openAddContact = openAddContact
|
||||
self.updateBlocked = updateBlocked
|
||||
@ -1329,7 +1338,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
return result
|
||||
}
|
||||
|
||||
private func editingItems(data: PeerInfoScreenData?, chatLocation: ChatLocation, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||
private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatLocation: ChatLocation, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||
enum Section: Int, CaseIterable {
|
||||
case notifications
|
||||
case groupLocation
|
||||
@ -1346,8 +1355,33 @@ private func editingItems(data: PeerInfoScreenData?, chatLocation: ChatLocation,
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
if let _ = data.peer as? TelegramUser {
|
||||
let ItemDelete = 0
|
||||
if let user = data.peer as? TelegramUser {
|
||||
let ItemSuggest = 0
|
||||
let ItemCustom = 1
|
||||
let ItemReset = 2
|
||||
let ItemDelete = 3
|
||||
|
||||
let compactName = EnginePeer(user).compactDisplayTitle
|
||||
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemSuggest, text: presentationData.strings.UserInfo_SuggestPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Peer Info/SuggestAvatar"), action: {
|
||||
interaction.suggestPhoto()
|
||||
}))
|
||||
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemCustom, text: presentationData.strings.UserInfo_SetCustomPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Settings/SetAvatar"), action: {
|
||||
interaction.setCustomPhoto()
|
||||
}))
|
||||
|
||||
if user.photo.first?.isPersonal == true || state.updatingAvatar != nil {
|
||||
var representation: TelegramMediaImageRepresentation?
|
||||
if let cachedData = data.cachedData as? CachedUserData, case let .known(photo) = cachedData.photo {
|
||||
representation = photo?.representationForDisplayAtSize(PixelDimensions(width: 28, height: 28))
|
||||
}
|
||||
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemReset, text: presentationData.strings.UserInfo_ResetCustomPhoto, color: .accent, icon: nil, iconSignal: peerAvatarCompleteImage(account: context.account, peer: EnginePeer(user), forceProvidedRepresentation: true, representation: representation, size: CGSize(width: 28.0, height: 28.0)), action: {
|
||||
interaction.resetCustomPhoto()
|
||||
}))
|
||||
}
|
||||
|
||||
if data.isContact {
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemDelete, text: presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: {
|
||||
interaction.requestDeleteContact()
|
||||
@ -1985,6 +2019,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
requestDeleteContact: { [weak self] in
|
||||
self?.requestDeleteContact()
|
||||
},
|
||||
suggestPhoto: { [weak self] in
|
||||
self?.suggestPhoto()
|
||||
},
|
||||
setCustomPhoto: { [weak self] in
|
||||
self?.setCustomPhoto()
|
||||
},
|
||||
resetCustomPhoto: { [weak self] in
|
||||
self?.resetCustomPhoto()
|
||||
},
|
||||
openChat: { [weak self] in
|
||||
self?.openChat()
|
||||
},
|
||||
@ -2827,10 +2870,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self?.openAvatarForEditing(fromGallery: true, completion: completion)
|
||||
}
|
||||
galleryController.avatarPhotoEditCompletion = { [weak self] image in
|
||||
self?.updateProfilePhoto(image)
|
||||
self?.updateProfilePhoto(image, mode: .generic)
|
||||
}
|
||||
galleryController.avatarVideoEditCompletion = { [weak self] image, asset, adjustments in
|
||||
self?.updateProfileVideo(image, asset: asset, adjustments: adjustments)
|
||||
self?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: .generic)
|
||||
}
|
||||
galleryController.removedEntry = { [weak self] entry in
|
||||
if let item = PeerInfoAvatarListItem(entry: entry) {
|
||||
@ -3634,6 +3677,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
var previousAbout: String?
|
||||
var currentAbout: String?
|
||||
|
||||
var previousPhotoIsPersonal: Bool?
|
||||
var currentPhotoIsPersonal: Bool?
|
||||
if let previousUser = previousData?.peer as? TelegramUser {
|
||||
previousPhotoIsPersonal = previousUser.profileImageRepresentations.first?.isPersonal == true
|
||||
}
|
||||
if let user = data.peer as? TelegramUser {
|
||||
currentPhotoIsPersonal = user.profileImageRepresentations.first?.isPersonal == true
|
||||
}
|
||||
|
||||
if let previousCachedData = previousData?.cachedData as? CachedChannelData, let cachedData = data.cachedData as? CachedChannelData {
|
||||
previousCall = previousCachedData.activeCall
|
||||
currentCall = cachedData.activeCall
|
||||
@ -3670,6 +3722,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if (previousAbout?.isEmpty ?? true) != (currentAbout?.isEmpty ?? true) {
|
||||
infoUpdated = true
|
||||
}
|
||||
if let previousPhotoIsPersonal, let currentPhotoIsPersonal, previousPhotoIsPersonal != currentPhotoIsPersonal {
|
||||
infoUpdated = true
|
||||
}
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: self.didSetReady && (membersUpdated || infoUpdated) ? .animated(duration: 0.3, curve: .spring) : .immediate)
|
||||
}
|
||||
}
|
||||
@ -6686,7 +6741,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
private func updateProfilePhoto(_ image: UIImage) {
|
||||
private func updateProfilePhoto(_ image: UIImage, mode: AvatarEditingMode) {
|
||||
guard let data = image.jpegData(compressionQuality: 0.6) else {
|
||||
return
|
||||
}
|
||||
@ -6700,20 +6755,30 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
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: false)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: mode == .custom ? true : false)
|
||||
|
||||
self.state = self.state.withUpdatingAvatar(.image(representation))
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: mode == .custom ? .animated(duration: 0.2, curve: .easeInOut) : .immediate, additive: false)
|
||||
}
|
||||
self.headerNode.ignoreCollapse = false
|
||||
|
||||
let postbox = self.context.account.postbox
|
||||
let signal = self.isSettings ? self.context.engine.accountData.updateAccountPhoto(resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
}) : self.context.engine.peers.updatePeerPhoto(peerId: self.peerId, photo: self.context.engine.peers.uploadedPeerPhoto(resource: resource), mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
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)
|
||||
})
|
||||
} else if case .custom = mode {
|
||||
signal = self.context.engine.contacts.updateContactPhoto(peerId: self.peerId, resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} else {
|
||||
signal = self.context.engine.peers.updatePeerPhoto(peerId: self.peerId, photo: self.context.engine.peers.uploadedPeerPhoto(resource: resource), mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
}
|
||||
|
||||
self.updateAvatarDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
@ -6728,10 +6793,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
|
||||
if case .complete = result, case .custom = mode {
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func updateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?) {
|
||||
private func updateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?, mode: AvatarEditingMode) {
|
||||
guard let data = image.jpegData(compressionQuality: 0.6) else {
|
||||
return
|
||||
}
|
||||
@ -6745,11 +6819,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
let photoResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
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: false)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: mode == .custom ? true : false)
|
||||
|
||||
self.state = self.state.withUpdatingAvatar(.image(representation))
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: mode == .custom ? .animated(duration: 0.2, curve: .easeInOut) : .immediate, additive: false)
|
||||
}
|
||||
self.headerNode.ignoreCollapse = false
|
||||
|
||||
@ -6847,6 +6921,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
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, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} else {
|
||||
return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: context.engine.peers.uploadedPeerPhoto(resource: photoResource), video: context.engine.peers.uploadedPeerVideo(resource: videoResource) |> map(Optional.init), videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
@ -6866,11 +6944,26 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
|
||||
if case .complete = result, case .custom = mode {
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
guard let peer = self.data?.peer, canEditPeerInfo(context: self.context, peer: peer, chatLocation: self.chatLocation, threadData: self.data?.threadData) else {
|
||||
private enum AvatarEditingMode {
|
||||
case generic
|
||||
case suggest
|
||||
case custom
|
||||
}
|
||||
|
||||
private 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
|
||||
}
|
||||
|
||||
@ -6929,7 +7022,36 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
isForum = true
|
||||
}
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos && !fromGallery, hasViewButton: false, personalPhoto: strongSelf.isSettings, isVideo: currentIsVideo, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: isForum)!
|
||||
var hasDeleteButton = false
|
||||
if case .generic = mode {
|
||||
hasDeleteButton = hasPhotos && !fromGallery
|
||||
} else if case .custom = mode {
|
||||
hasDeleteButton = peer.profileImageRepresentations.first?.isPersonal == true
|
||||
}
|
||||
|
||||
let title: String?
|
||||
let confirmationTextPhoto: String?
|
||||
let confirmationTextVideo: String?
|
||||
let confirmationAction: String?
|
||||
switch mode {
|
||||
case .suggest:
|
||||
title = strongSelf.presentationData.strings.UserInfo_SuggestPhotoTitle(peer.compactDisplayTitle).string
|
||||
confirmationTextPhoto = strongSelf.presentationData.strings.UserInfo_SuggestPhoto_AlertPhotoText(peer.compactDisplayTitle).string
|
||||
confirmationTextVideo = strongSelf.presentationData.strings.UserInfo_SuggestPhoto_AlertVideoText(peer.compactDisplayTitle).string
|
||||
confirmationAction = strongSelf.presentationData.strings.UserInfo_SuggestPhoto_AlertSuggest
|
||||
case .custom:
|
||||
title = strongSelf.presentationData.strings.UserInfo_SetCustomPhotoTitle(peer.compactDisplayTitle).string
|
||||
confirmationTextPhoto = strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_AlertPhotoText(peer.compactDisplayTitle, peer.compactDisplayTitle).string
|
||||
confirmationTextVideo = strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_AlertVideoText(peer.compactDisplayTitle, peer.compactDisplayTitle).string
|
||||
confirmationAction = strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_AlertSet
|
||||
default:
|
||||
title = nil
|
||||
confirmationTextPhoto = nil
|
||||
confirmationTextVideo = nil
|
||||
confirmationAction = nil
|
||||
}
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasDeleteButton, hasViewButton: false, personalPhoto: strongSelf.isSettings, isVideo: currentIsVideo, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: isForum, title: title)!
|
||||
mixin.stickersContext = paintStickersContext
|
||||
let _ = strongSelf.currentAvatarMixin.swap(mixin)
|
||||
mixin.requestSearchController = { [weak self] assetsController in
|
||||
@ -6938,7 +7060,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: strongSelf.isSettings ? nil : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { [weak self] result in
|
||||
assetsController?.dismiss()
|
||||
self?.updateProfilePhoto(result)
|
||||
self?.updateProfilePhoto(result, mode: mode)
|
||||
}))
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.controller?.push(controller)
|
||||
@ -6947,16 +7069,36 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
completion()
|
||||
}
|
||||
}
|
||||
if let confirmationTextPhoto, let confirmationAction {
|
||||
mixin.willFinishWithImage = { [weak self] image, commit in
|
||||
if let strongSelf = self, let image {
|
||||
let controller = photoUpdateConfirmationController(context: strongSelf.context, peer: peer, image: image, text: confirmationTextPhoto, doneTitle: confirmationAction, commit: {
|
||||
commit?()
|
||||
})
|
||||
strongSelf.controller?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let confirmationTextVideo, let confirmationAction {
|
||||
mixin.willFinishWithVideo = { [weak self] image, commit in
|
||||
if let strongSelf = self, let image {
|
||||
let controller = photoUpdateConfirmationController(context: strongSelf.context, peer: peer, image: image, text: confirmationTextVideo, doneTitle: confirmationAction, commit: {
|
||||
commit?()
|
||||
})
|
||||
strongSelf.controller?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithImage = { [weak self] image in
|
||||
if let image = image {
|
||||
completion()
|
||||
self?.updateProfilePhoto(image)
|
||||
self?.updateProfilePhoto(image, mode: mode)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithVideo = { [weak self] image, asset, adjustments in
|
||||
if let image = image, let asset = asset {
|
||||
completion()
|
||||
self?.updateProfileVideo(image, asset: asset, adjustments: adjustments)
|
||||
self?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithDelete = {
|
||||
@ -8030,6 +8172,44 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
peerController.present(controller, in: .window(.root))
|
||||
}
|
||||
|
||||
private func suggestPhoto() {
|
||||
self.openAvatarForEditing(mode: .suggest)
|
||||
}
|
||||
|
||||
private func setCustomPhoto() {
|
||||
self.openAvatarForEditing(mode: .custom)
|
||||
}
|
||||
|
||||
private func resetCustomPhoto() {
|
||||
guard let peer = self.data?.peer else {
|
||||
return
|
||||
}
|
||||
let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: self.presentationData.strings.UserInfo_ResetToOriginalAlertText(EnginePeer(peer).compactDisplayTitle).string, actions: [
|
||||
TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {
|
||||
|
||||
}),
|
||||
TextAlertAction(type: .defaultAction, title: self.presentationData.strings.UserInfo_ResetToOriginalAlertReset, action: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateAvatarDisposable.set((strongSelf.context.engine.contacts.updateContactPhoto(peerId: strongSelf.peerId, resource: nil, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
mapResourceToAvatarSizes(postbox: strongSelf.context.account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.state = strongSelf.state.withUpdatingAvatar(nil).withAvatarUploadProgress(nil)
|
||||
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.2, curve: .easeInOut), additive: false)
|
||||
}
|
||||
}))
|
||||
})
|
||||
])
|
||||
self.controller?.present(alertController, in: .window(.root))
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
self.presentationData = presentationData
|
||||
|
||||
@ -8160,7 +8340,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
var validEditingSections: [AnyHashable] = []
|
||||
let editItems = self.isSettings ? settingsEditingItems(data: self.data, state: self.state, context: self.context, presentationData: self.presentationData, interaction: self.interaction) : editingItems(data: self.data, chatLocation: self.chatLocation, context: self.context, presentationData: self.presentationData, interaction: self.interaction)
|
||||
let editItems = self.isSettings ? settingsEditingItems(data: self.data, state: self.state, context: self.context, presentationData: self.presentationData, interaction: self.interaction) : editingItems(data: self.data, state: self.state, chatLocation: self.chatLocation, context: self.context, presentationData: self.presentationData, interaction: self.interaction)
|
||||
|
||||
for (sectionId, sectionItems) in editItems {
|
||||
var insets = UIEdgeInsets()
|
||||
|
@ -0,0 +1,244 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
import AvatarNode
|
||||
|
||||
private final class PhotoUpdateConfirmationAlertContentNode: AlertContentNode {
|
||||
private let strings: PresentationStrings
|
||||
private let text: String
|
||||
|
||||
private let textNode: ASTextNode
|
||||
private let avatarNode: AvatarNode
|
||||
private let arrowNode: ASImageNode
|
||||
private let iconNode: ASImageNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
override var dismissOnOutsideTap: Bool {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, image: UIImage, text: String, actions: [TextAlertAction]) {
|
||||
self.strings = strings
|
||||
self.text = text
|
||||
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0))
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.displayWithoutProcessing = true
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.clipsToBounds = true
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
self.iconNode.image = image
|
||||
self.iconNode.cornerRadius = 30.0
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
|
||||
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||
return TextAlertContentActionNode(theme: theme, action: action)
|
||||
}
|
||||
|
||||
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||
if actions.count > 1 {
|
||||
for _ in 0 ..< actions.count - 1 {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.isLayerBacked = true
|
||||
actionVerticalSeparators.append(separatorNode)
|
||||
}
|
||||
}
|
||||
self.actionVerticalSeparators = actionVerticalSeparators
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.arrowNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
self.addSubnode(actionNode)
|
||||
}
|
||||
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
|
||||
self.avatarNode.setPeer(context: context, theme: ptheme, peer: peer)
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Peer Info/AlertArrow"), color: theme.secondaryColor)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
}
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
_ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var size = size
|
||||
size.width = min(size.width, 270.0)
|
||||
|
||||
self.validLayout = size
|
||||
|
||||
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
|
||||
|
||||
let avatarSize = CGSize(width: 60.0, height: 60.0)
|
||||
self.avatarNode.updateSize(size: avatarSize)
|
||||
|
||||
let avatarFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarSize.width) / 2.0) - 44.0, y: origin.y), size: avatarSize)
|
||||
transition.updateFrame(node: self.avatarNode, frame: avatarFrame)
|
||||
|
||||
if let arrowImage = self.arrowNode.image {
|
||||
let arrowFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - arrowImage.size.width) / 2.0), y: origin.y + floorToScreenPixels((avatarSize.height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
||||
transition.updateFrame(node: self.arrowNode, frame: arrowFrame)
|
||||
}
|
||||
|
||||
if let _ = self.iconNode.image {
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarSize.width) / 2.0) + 44.0, y: origin.y), size: avatarSize)
|
||||
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||
origin.y += avatarSize.height + 10.0
|
||||
}
|
||||
|
||||
let textSize = self.textNode.measure(CGSize(width: size.width - 32.0, height: size.height))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||
let actionTitleInsets: CGFloat = 8.0
|
||||
|
||||
var effectiveActionLayout = TextAlertContentActionLayout.horizontal
|
||||
for actionNode in self.actionNodes {
|
||||
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
|
||||
effectiveActionLayout = .vertical
|
||||
}
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
minActionsWidth += actionTitleSize.width + actionTitleInsets
|
||||
case .vertical:
|
||||
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||
}
|
||||
}
|
||||
|
||||
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0)
|
||||
|
||||
let contentWidth = max(size.width, minActionsWidth)
|
||||
|
||||
var actionsHeight: CGFloat = 0.0
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionsHeight = actionButtonHeight
|
||||
case .vertical:
|
||||
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
}
|
||||
|
||||
let resultSize = CGSize(width: contentWidth, height: avatarSize.height + textSize.height + actionsHeight + 16.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)))
|
||||
|
||||
var actionOffset: CGFloat = 0.0
|
||||
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
|
||||
var separatorIndex = -1
|
||||
var nodeIndex = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if separatorIndex >= 0 {
|
||||
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
|
||||
case .vertical:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
separatorIndex += 1
|
||||
|
||||
let currentActionWidth: CGFloat
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
if nodeIndex == self.actionNodes.count - 1 {
|
||||
currentActionWidth = resultSize.width - actionOffset
|
||||
} else {
|
||||
currentActionWidth = actionWidth
|
||||
}
|
||||
case .vertical:
|
||||
currentActionWidth = resultSize.width
|
||||
}
|
||||
|
||||
let actionNodeFrame: CGRect
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += currentActionWidth
|
||||
case .vertical:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += actionButtonHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
}
|
||||
|
||||
func photoUpdateConfirmationController(context: AccountContext, peer: EnginePeer, image: UIImage, text: String, doneTitle: String, commit: @escaping () -> Void) -> AlertController {
|
||||
let theme = defaultDarkColorPresentationTheme
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: theme)
|
||||
let strings = presentationData.strings
|
||||
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
var contentNode: PhotoUpdateConfirmationAlertContentNode?
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
}), TextAlertAction(type: .defaultAction, title: doneTitle, action: {
|
||||
dismissImpl?(true)
|
||||
commit()
|
||||
})]
|
||||
|
||||
contentNode = PhotoUpdateConfirmationAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peer: peer, image: image, text: text, actions: actions)
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode!)
|
||||
dismissImpl = { [weak controller] animated in
|
||||
if animated {
|
||||
controller?.dismissAnimated()
|
||||
} else {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
return controller
|
||||
}
|
@ -37,13 +37,14 @@ func presentLegacyWebSearchEditor(context: AccountContext, theme: PresentationTh
|
||||
legacyController.bind(controller: controller)
|
||||
|
||||
controller.editingContext = TGMediaEditingContext()
|
||||
controller.didFinishEditing = { [weak controller] _, result, _, hasChanges in
|
||||
controller.didFinishEditing = { [weak controller] _, result, _, hasChanges, commit in
|
||||
if !hasChanges {
|
||||
return
|
||||
}
|
||||
if let result = result {
|
||||
completed(result)
|
||||
}
|
||||
commit?()
|
||||
controller?.dismiss(animated: true)
|
||||
}
|
||||
controller.requestThumbnailImage = { _ -> SSignal in
|
||||
|
Loading…
x
Reference in New Issue
Block a user