mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
575eb2ca5f
commit
c73f24f5f2
@ -13715,6 +13715,7 @@ Sorry for the inconvenience.";
|
|||||||
"PeerInfo.Gifts.SendGift" = "Send Gift";
|
"PeerInfo.Gifts.SendGift" = "Send Gift";
|
||||||
"PeerInfo.Gifts.ChannelNotify" = "Notify About New Gifts";
|
"PeerInfo.Gifts.ChannelNotify" = "Notify About New Gifts";
|
||||||
"PeerInfo.Gifts.ChannelNotifyTooltip" = "You will receive a message from Telegram when your channel receives a gift.";
|
"PeerInfo.Gifts.ChannelNotifyTooltip" = "You will receive a message from Telegram when your channel receives a gift.";
|
||||||
|
"PeerInfo.Gifts.ChannelNotifyDisabledTooltip" = "You will not receive a message from Telegram when your channel receives a gift.";
|
||||||
|
|
||||||
"Notification.StarsGift.Channel.Sent" = "%1$@ sent a gift to %2$@ for %3$@";
|
"Notification.StarsGift.Channel.Sent" = "%1$@ sent a gift to %2$@ for %3$@";
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ public func calculateAvatarColors(context: AccountContext?, explicitColorIndex:
|
|||||||
}
|
}
|
||||||
|
|
||||||
let colors: [UIColor]
|
let colors: [UIColor]
|
||||||
if icon != .none && icon != .cameraIcon {
|
if icon != .none {
|
||||||
if case .deletedIcon = icon {
|
if case .deletedIcon = icon {
|
||||||
colors = AvatarNode.grayscaleColors
|
colors = AvatarNode.grayscaleColors
|
||||||
} else if case .phoneIcon = icon {
|
} else if case .phoneIcon = icon {
|
||||||
@ -120,6 +120,8 @@ public func calculateAvatarColors(context: AccountContext?, explicitColorIndex:
|
|||||||
backgroundColors = theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors
|
backgroundColors = theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors
|
||||||
}
|
}
|
||||||
colors = [backgroundColors.1, backgroundColors.0]
|
colors = [backgroundColors.1, backgroundColors.0]
|
||||||
|
} else if case .cameraIcon = icon {
|
||||||
|
colors = AvatarNode.repostColors
|
||||||
} else {
|
} else {
|
||||||
colors = AvatarNode.grayscaleColors
|
colors = AvatarNode.grayscaleColors
|
||||||
}
|
}
|
||||||
@ -288,7 +290,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
]
|
]
|
||||||
|
|
||||||
static let repostColors: [UIColor] = [
|
static let repostColors: [UIColor] = [
|
||||||
UIColor(rgb: 0x34C76F), UIColor(rgb: 0x3DA1FD)
|
UIColor(rgb: 0x3DA1FD), UIColor(rgb: 0x34C76F)
|
||||||
]
|
]
|
||||||
|
|
||||||
public final class ContentNode: ASDisplayNode {
|
public final class ContentNode: ASDisplayNode {
|
||||||
|
@ -68,15 +68,15 @@ public struct GridNodeLayout: Equatable {
|
|||||||
public let scrollIndicatorInsets: UIEdgeInsets?
|
public let scrollIndicatorInsets: UIEdgeInsets?
|
||||||
public let preloadSize: CGFloat
|
public let preloadSize: CGFloat
|
||||||
public let type: GridNodeLayoutType
|
public let type: GridNodeLayoutType
|
||||||
public let cutout: CGRect?
|
public let cutouts: [CGRect]
|
||||||
|
|
||||||
public init(size: CGSize, insets: UIEdgeInsets, scrollIndicatorInsets: UIEdgeInsets? = nil, preloadSize: CGFloat, type: GridNodeLayoutType, cutout: CGRect? = nil) {
|
public init(size: CGSize, insets: UIEdgeInsets, scrollIndicatorInsets: UIEdgeInsets? = nil, preloadSize: CGFloat, type: GridNodeLayoutType, cutouts: [CGRect] = []) {
|
||||||
self.size = size
|
self.size = size
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.scrollIndicatorInsets = scrollIndicatorInsets
|
self.scrollIndicatorInsets = scrollIndicatorInsets
|
||||||
self.preloadSize = preloadSize
|
self.preloadSize = preloadSize
|
||||||
self.type = type
|
self.type = type
|
||||||
self.cutout = cutout
|
self.cutouts = cutouts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,9 +568,13 @@ open class GridNode: GridNodeScroller, ASScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let cutout = self.gridLayout.cutout, cutout.intersects(CGRect(origin: nextItemOrigin, size: itemSize)) {
|
if !self.gridLayout.cutouts.isEmpty, nextItemOrigin.y < itemSize.height * 3.0 {
|
||||||
|
for cutout in self.gridLayout.cutouts {
|
||||||
|
if cutout.intersects(CGRect(origin: nextItemOrigin, size: itemSize)) {
|
||||||
nextItemOrigin.x += cutout.width + itemSpacing
|
nextItemOrigin.x += cutout.width + itemSpacing
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !incrementedCurrentRow {
|
if !incrementedCurrentRow {
|
||||||
incrementedCurrentRow = true
|
incrementedCurrentRow = true
|
||||||
|
@ -26,7 +26,7 @@ typedef void (^TGMediaAvatarPresentImpl)(id<LegacyComponentsContext>, void (^)(U
|
|||||||
@property (nonatomic, copy) void (^requestSearchController)(TGMediaAssetsController *);
|
@property (nonatomic, copy) void (^requestSearchController)(TGMediaAssetsController *);
|
||||||
@property (nonatomic, copy) CGRect (^sourceRect)(void);
|
@property (nonatomic, copy) CGRect (^sourceRect)(void);
|
||||||
|
|
||||||
@property (nonatomic, copy) void (^requestAvatarEditor)(void (^)(UIImage *image, void(^commit)(void)), void (^)(UIImage *image, NSURL *asset, TGVideoEditAdjustments *adjustments, void(^commit)(void)));
|
@property (nonatomic, copy) void (^requestAvatarEditor)(void (^)(UIImage *image, void(^commit)(void)), void (^)(UIImage *image, NSURL *asset, id adjustments, id markup, void(^commit)(void)));
|
||||||
|
|
||||||
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
|
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
|
||||||
|
|
||||||
|
@ -193,60 +193,60 @@
|
|||||||
}];
|
}];
|
||||||
[itemViews addObject:galleryItem];
|
[itemViews addObject:galleryItem];
|
||||||
|
|
||||||
if (!_signup) {
|
// if (!_signup) {
|
||||||
TGMenuSheetButtonItemView *viewItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"ProfilePhoto.SetEmoji") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^
|
// TGMenuSheetButtonItemView *viewItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"ProfilePhoto.SetEmoji") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^
|
||||||
{
|
// {
|
||||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
// __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||||
if (strongSelf == nil)
|
// if (strongSelf == nil)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
__strong TGMenuSheetController *strongController = weakController;
|
// __strong TGMenuSheetController *strongController = weakController;
|
||||||
if (strongController == nil)
|
// if (strongController == nil)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
[strongController dismissAnimated:true];
|
// [strongController dismissAnimated:true];
|
||||||
if (strongSelf != nil && strongSelf.requestAvatarEditor) {
|
// if (strongSelf != nil && strongSelf.requestAvatarEditor) {
|
||||||
strongSelf.requestAvatarEditor(^(UIImage *image, void (^commit)(void)) {
|
// strongSelf.requestAvatarEditor(^(UIImage *image, void (^commit)(void)) {
|
||||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
// __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||||
if (strongSelf == nil)
|
// if (strongSelf == nil)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
if (strongSelf.willFinishWithImage != nil) {
|
// if (strongSelf.willFinishWithImage != nil) {
|
||||||
strongSelf.willFinishWithImage(image, ^{
|
// strongSelf.willFinishWithImage(image, ^{
|
||||||
if (strongSelf.didFinishWithImage != nil)
|
// if (strongSelf.didFinishWithImage != nil)
|
||||||
strongSelf.didFinishWithImage(image);
|
// strongSelf.didFinishWithImage(image);
|
||||||
|
//
|
||||||
commit();
|
// commit();
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
if (strongSelf.didFinishWithImage != nil)
|
// if (strongSelf.didFinishWithImage != nil)
|
||||||
strongSelf.didFinishWithImage(image);
|
// strongSelf.didFinishWithImage(image);
|
||||||
|
//
|
||||||
commit();
|
// commit();
|
||||||
}
|
// }
|
||||||
}, ^(UIImage *image, NSURL *asset, TGVideoEditAdjustments *adjustments, void (^commit)(void)) {
|
// }, ^(UIImage *image, NSURL *asset, id adjustments, id markup, void (^commit)(void)) {
|
||||||
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
// __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
|
||||||
if (strongSelf == nil)
|
// if (strongSelf == nil)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
if (strongSelf.willFinishWithVideo != nil) {
|
// if (strongSelf.willFinishWithVideo != nil) {
|
||||||
strongSelf.willFinishWithVideo(image, ^{
|
// strongSelf.willFinishWithVideo(image, ^{
|
||||||
if (strongSelf.didFinishWithVideo != nil)
|
// if (strongSelf.didFinishWithVideo != nil)
|
||||||
strongSelf.didFinishWithVideo(image, asset, adjustments);
|
// strongSelf.didFinishWithVideo(image, asset, adjustments);
|
||||||
|
//
|
||||||
commit();
|
// commit();
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
if (strongSelf.didFinishWithVideo != nil)
|
// if (strongSelf.didFinishWithVideo != nil)
|
||||||
strongSelf.didFinishWithVideo(image, asset, adjustments);
|
// strongSelf.didFinishWithVideo(image, asset, adjustments);
|
||||||
|
//
|
||||||
commit();
|
// commit();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}];
|
// }];
|
||||||
[itemViews addObject:viewItem];
|
// [itemViews addObject:viewItem];
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if (_hasSearchButton)
|
// if (_hasSearchButton)
|
||||||
// {
|
// {
|
||||||
|
@ -1546,7 +1546,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
let itemSpacing: CGFloat = 1.0
|
let itemSpacing: CGFloat = 1.0
|
||||||
let itemWidth = floorToScreenPixels((width - itemSpacing * CGFloat(itemsPerRow - 1)) / CGFloat(itemsPerRow))
|
let itemWidth = floorToScreenPixels((width - itemSpacing * CGFloat(itemsPerRow - 1)) / CGFloat(itemsPerRow))
|
||||||
|
|
||||||
var cutoutRect: CGRect?
|
var cutoutRects: [CGRect] = []
|
||||||
var cameraRect: CGRect? = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: 0.0), size: CGSize(width: itemWidth, height: itemWidth * 2.0 + 1.0))
|
var cameraRect: CGRect? = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: 0.0), size: CGSize(width: itemWidth, height: itemWidth * 2.0 + 1.0))
|
||||||
if self.cameraView == nil && self.modernCameraView == nil {
|
if self.cameraView == nil && self.modernCameraView == nil {
|
||||||
cameraRect = nil
|
cameraRect = nil
|
||||||
@ -1647,9 +1647,11 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
|
|
||||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: bounds.height)))
|
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: bounds.height)))
|
||||||
|
|
||||||
cutoutRect = cameraRect
|
if let cameraRect {
|
||||||
|
cutoutRects.append(cameraRect)
|
||||||
|
}
|
||||||
if let _ = self.avatarEditorPreviewView {
|
if let _ = self.avatarEditorPreviewView {
|
||||||
cutoutRect = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: 0.0), size: CGSize(width: cameraRect != nil ? itemWidth * 2.0 : itemWidth, height: itemWidth))
|
cutoutRects.append(CGRect(x: cameraRect != nil ? cameraRect!.maxX + itemSpacing : layout.safeInsets.left, y: 0.0, width: itemWidth, height: itemWidth))
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemHeight = itemWidth
|
var itemHeight = itemWidth
|
||||||
@ -1657,7 +1659,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
itemHeight = floor(itemWidth * 1.227)
|
itemHeight = floor(itemWidth * 1.227)
|
||||||
}
|
}
|
||||||
let preloadSize: CGFloat = itemHeight// * 3.0
|
let preloadSize: CGFloat = itemHeight// * 3.0
|
||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: bounds.size, insets: gridInsets, scrollIndicatorInsets: nil, preloadSize: preloadSize, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemHeight), fillWidth: true, lineSpacing: itemSpacing, itemSpacing: itemSpacing), cutout: cutoutRect), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, updateOpaqueState: nil, synchronousLoads: false), completion: { [weak self] _ in
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: bounds.size, insets: gridInsets, scrollIndicatorInsets: nil, preloadSize: preloadSize, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemHeight), fillWidth: true, lineSpacing: itemSpacing, itemSpacing: itemSpacing), cutouts: cutoutRects), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, updateOpaqueState: nil, synchronousLoads: false), completion: { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1680,9 +1682,6 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
if let avatarEditorPreviewView = self.avatarEditorPreviewView {
|
if let avatarEditorPreviewView = self.avatarEditorPreviewView {
|
||||||
avatarEditorPreviewView.frame = CGRect(origin: CGPoint(x: cameraRect != nil ? cameraRect!.maxX + itemSpacing : layout.safeInsets.left, y: 0.0), size: CGSize(width: itemWidth, height: itemWidth))
|
avatarEditorPreviewView.frame = CGRect(origin: CGPoint(x: cameraRect != nil ? cameraRect!.maxX + itemSpacing : layout.safeInsets.left, y: 0.0), size: CGSize(width: itemWidth, height: itemWidth))
|
||||||
avatarEditorPreviewView.updateLayout(size: CGSize(width: itemWidth, height: itemWidth))
|
avatarEditorPreviewView.updateLayout(size: CGSize(width: itemWidth, height: itemWidth))
|
||||||
if self.gridNode.view.subviews.last !== avatarEditorPreviewView {
|
|
||||||
self.gridNode.view.bringSubviewToFront(avatarEditorPreviewView)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let selectionNode = self.selectionNode, let controller = self.controller {
|
if let selectionNode = self.selectionNode, let controller = self.controller {
|
||||||
|
@ -419,8 +419,6 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
private let centralItemAttributesDisposable = DisposableSet();
|
private let centralItemAttributesDisposable = DisposableSet();
|
||||||
|
|
||||||
public var openAvatarSetup: ((@escaping () -> Void) -> Void)?
|
public var openAvatarSetup: ((@escaping () -> Void) -> Void)?
|
||||||
public var avatarPhotoEditCompletion: ((UIImage) -> Void)?
|
|
||||||
public var avatarVideoEditCompletion: ((UIImage, URL, TGVideoEditAdjustments?) -> Void)?
|
|
||||||
|
|
||||||
public var removedEntry: ((AvatarGalleryEntry) -> Void)?
|
public var removedEntry: ((AvatarGalleryEntry) -> Void)?
|
||||||
|
|
||||||
|
@ -815,8 +815,13 @@ func _internal_upgradeStarGift(account: Account, formId: Int64?, reference: Star
|
|||||||
case let .updateNewMessage(message, _, _):
|
case let .updateNewMessage(message, _, _):
|
||||||
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: false) {
|
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: false) {
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let action = media as? TelegramMediaAction, case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, _, _, _) = action.action, case let .Id(messageId) = message.id {
|
if let action = media as? TelegramMediaAction, case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, peerId, _, savedId) = action.action, case let .Id(messageId) = message.id {
|
||||||
let _ = messageId
|
let reference: StarGiftReference
|
||||||
|
if let peerId, let savedId {
|
||||||
|
reference = .peer(peerId: peerId, id: savedId)
|
||||||
|
} else {
|
||||||
|
reference = .message(messageId: messageId)
|
||||||
|
}
|
||||||
return .single(ProfileGiftsContext.State.StarGift(
|
return .single(ProfileGiftsContext.State.StarGift(
|
||||||
gift: gift,
|
gift: gift,
|
||||||
reference: reference,
|
reference: reference,
|
||||||
@ -1098,6 +1103,14 @@ private final class ProfileGiftsContextImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toggleStarGiftsNotifications(enabled: Bool) {
|
||||||
|
self.actionDisposable.set(
|
||||||
|
_internal_toggleStarGiftsNotifications(account: self.account, peerId: self.peerId, enabled: enabled).startStrict()
|
||||||
|
)
|
||||||
|
self.notificationsEnabled = enabled
|
||||||
|
self.pushState()
|
||||||
|
}
|
||||||
|
|
||||||
private func pushState() {
|
private func pushState() {
|
||||||
self._state = ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)
|
self._state = ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)
|
||||||
self.stateValue.set(.single(ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)))
|
self.stateValue.set(.single(ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)))
|
||||||
@ -1330,6 +1343,12 @@ public final class ProfileGiftsContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func toggleStarGiftsNotifications(enabled: Bool) {
|
||||||
|
self.impl.with { impl in
|
||||||
|
impl.toggleStarGiftsNotifications(enabled: enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public var currentState: ProfileGiftsContext.State? {
|
public var currentState: ProfileGiftsContext.State? {
|
||||||
var state: ProfileGiftsContext.State?
|
var state: ProfileGiftsContext.State?
|
||||||
self.impl.syncWith { impl in
|
self.impl.syncWith { impl in
|
||||||
|
@ -1464,10 +1464,16 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot
|
|||||||
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer:
|
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer:
|
||||||
receiptMessageId = nil
|
receiptMessageId = nil
|
||||||
}
|
}
|
||||||
} else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, _, _, _) = action.action, case let .Id(messageId) = message.id {
|
} else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, peerId, _, savedId) = action.action, case let .Id(messageId) = message.id {
|
||||||
|
let reference: StarGiftReference
|
||||||
|
if let peerId, let savedId {
|
||||||
|
reference = .peer(peerId: peerId, id: savedId)
|
||||||
|
} else {
|
||||||
|
reference = .message(messageId: messageId)
|
||||||
|
}
|
||||||
resultGift = ProfileGiftsContext.State.StarGift(
|
resultGift = ProfileGiftsContext.State.StarGift(
|
||||||
gift: gift,
|
gift: gift,
|
||||||
reference: .message(messageId: messageId),
|
reference: reference,
|
||||||
fromPeer: nil,
|
fromPeer: nil,
|
||||||
date: message.timestamp,
|
date: message.timestamp,
|
||||||
text: nil,
|
text: nil,
|
||||||
|
@ -1374,31 +1374,50 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let colors: [NSNumber] = state.selectedBackground.colors.map { Int32(bitPattern: $0) as NSNumber }
|
let backgroundColors = state.selectedBackground.colors.map { Int32(bitPattern: $0) }
|
||||||
|
guard let codableEntity = CodableDrawingEntity(entity: entity) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let entitiesData = DrawingEntitiesView.encodeEntitiesData([entity])
|
let values = MediaEditorValues(
|
||||||
|
peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)),
|
||||||
let paintingData = TGPaintingData(
|
originalDimensions: PixelDimensions(size),
|
||||||
drawing: nil,
|
cropOffset: .zero,
|
||||||
entitiesData: entitiesData,
|
|
||||||
image: nil,
|
|
||||||
stillImage: nil,
|
|
||||||
hasAnimation: entity.isAnimated,
|
|
||||||
stickers: []
|
|
||||||
)
|
|
||||||
|
|
||||||
let adjustments = PGPhotoEditorValues(
|
|
||||||
originalSize: size,
|
|
||||||
cropRect: CGRect(origin: .zero, size: size),
|
cropRect: CGRect(origin: .zero, size: size),
|
||||||
|
cropScale: 1.0,
|
||||||
cropRotation: 0.0,
|
cropRotation: 0.0,
|
||||||
cropOrientation: .up,
|
cropMirroring: false,
|
||||||
cropLockedAspectRatio: 1.0,
|
cropOrientation: nil,
|
||||||
cropMirrored: false,
|
gradientColors: nil,
|
||||||
|
videoTrimRange: nil,
|
||||||
|
videoIsMuted: false,
|
||||||
|
videoIsFullHd: false,
|
||||||
|
videoIsMirrored: false,
|
||||||
|
videoVolume: nil,
|
||||||
|
additionalVideoPath: nil,
|
||||||
|
additionalVideoIsDual: false,
|
||||||
|
additionalVideoPosition: nil,
|
||||||
|
additionalVideoScale: nil,
|
||||||
|
additionalVideoRotation: nil,
|
||||||
|
additionalVideoPositionChanges: [],
|
||||||
|
additionalVideoTrimRange: nil,
|
||||||
|
additionalVideoOffset: nil,
|
||||||
|
additionalVideoVolume: nil,
|
||||||
|
collage: [],
|
||||||
|
nightTheme: false,
|
||||||
|
drawing: nil,
|
||||||
|
maskDrawing: nil,
|
||||||
|
entities: [codableEntity],
|
||||||
toolValues: [:],
|
toolValues: [:],
|
||||||
paintingData: paintingData,
|
audioTrack: nil,
|
||||||
sendAsGif: true
|
audioTrackTrimRange: nil,
|
||||||
|
audioTrackOffset: nil,
|
||||||
|
audioTrackVolume: nil,
|
||||||
|
audioTrackSamples: nil,
|
||||||
|
collageTrackSamples: nil,
|
||||||
|
coverImageTimestamp: nil,
|
||||||
|
qualityPreset: .profileHigh
|
||||||
)
|
)
|
||||||
let preset: TGMediaVideoConversionPreset = TGMediaVideoConversionPresetProfileHigh
|
|
||||||
|
|
||||||
let combinedImage = generateImage(size, contextGenerator: { size, context in
|
let combinedImage = generateImage(size, contextGenerator: { size, context in
|
||||||
let bounds = CGRect(origin: .zero, size: size)
|
let bounds = CGRect(origin: .zero, size: size)
|
||||||
@ -1415,12 +1434,19 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
}, opaque: false)!
|
}, opaque: false)!
|
||||||
|
|
||||||
if entity.isAnimated {
|
if entity.isAnimated {
|
||||||
|
let markup: UploadPeerPhotoMarkup
|
||||||
if stickerPackId != 0 {
|
if stickerPackId != 0 {
|
||||||
controller.videoCompletion(combinedImage, tempUrl, TGVideoEditAdjustments(photoEditorValues: adjustments, preset: preset, stickerPackId: stickerPackId, stickerPackAccessHash: stickerPackAccessHash, documentId: fileId, colors: colors), { [weak controller] in
|
markup = .sticker(packReference: .id(id: stickerPackId, accessHash: stickerPackAccessHash), fileId: fileId, backgroundColors: backgroundColors)
|
||||||
|
} else {
|
||||||
|
markup = .emoji(fileId: fileId, backgroundColors: backgroundColors)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stickerPackId != 0 {
|
||||||
|
controller.videoCompletion(combinedImage, tempUrl, values, markup, { [weak controller] in
|
||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
controller.videoCompletion(combinedImage, tempUrl, TGVideoEditAdjustments(photoEditorValues: adjustments, preset: preset, documentId: fileId, colors: colors), { [weak controller] in
|
controller.videoCompletion(combinedImage, tempUrl, values, markup, { [weak controller] in
|
||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1461,7 +1487,7 @@ public final class AvatarEditorScreen: ViewControllerComponentContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var imageCompletion: (UIImage, @escaping () -> Void) -> Void = { _, _ in }
|
public var imageCompletion: (UIImage, @escaping () -> Void) -> Void = { _, _ in }
|
||||||
public var videoCompletion: (UIImage, URL, TGVideoEditAdjustments, @escaping () -> Void) -> Void = { _, _, _, _ in }
|
public var videoCompletion: (UIImage, URL, MediaEditorValues, UploadPeerPhotoMarkup, @escaping () -> Void) -> Void = { _, _, _, _, _ in }
|
||||||
|
|
||||||
public static func inputData(context: AccountContext, isGroup: Bool) -> Signal<AvatarKeyboardInputData, NoError> {
|
public static func inputData(context: AccountContext, isGroup: Bool) -> Signal<AvatarKeyboardInputData, NoError> {
|
||||||
let emojiItems = EmojiPagerContentComponent.emojiInputData(
|
let emojiItems = EmojiPagerContentComponent.emojiInputData(
|
||||||
|
@ -3959,6 +3959,9 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
||||||
|
if case .avatarEditor = self.controller?.mode {
|
||||||
|
return
|
||||||
|
}
|
||||||
switch subject {
|
switch subject {
|
||||||
case .message, .gift:
|
case .message, .gift:
|
||||||
return
|
return
|
||||||
@ -3979,6 +3982,9 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
||||||
|
if case .avatarEditor = self.controller?.mode {
|
||||||
|
return
|
||||||
|
}
|
||||||
switch subject {
|
switch subject {
|
||||||
case .message, .gift:
|
case .message, .gift:
|
||||||
return
|
return
|
||||||
@ -3999,6 +4005,9 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
||||||
|
if case .avatarEditor = self.controller?.mode {
|
||||||
|
return
|
||||||
|
}
|
||||||
switch subject {
|
switch subject {
|
||||||
case .message, .gift:
|
case .message, .gift:
|
||||||
return
|
return
|
||||||
@ -4168,19 +4177,20 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
let sourceAspectRatio = sourceLocalFrame.height / sourceLocalFrame.width
|
let sourceAspectRatio = sourceLocalFrame.height / sourceLocalFrame.width
|
||||||
|
|
||||||
let duration: Double = 0.4
|
let duration: Double = 0.4
|
||||||
|
let timingFunction = kCAMediaTimingFunctionSpring
|
||||||
|
|
||||||
self.previewContainerView.layer.animatePosition(from: sourceLocalFrame.center, to: self.previewContainerView.center, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
self.previewContainerView.layer.animatePosition(from: sourceLocalFrame.center, to: self.previewContainerView.center, duration: duration, timingFunction: timingFunction, completion: { _ in
|
||||||
completion()
|
completion()
|
||||||
})
|
})
|
||||||
self.previewContainerView.layer.animateScale(from: sourceScale, to: 1.0, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
self.previewContainerView.layer.animateScale(from: sourceScale, to: 1.0, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
self.previewContainerView.layer.animateBounds(from: CGRect(origin: CGPoint(x: 0.0, y: (self.previewContainerView.bounds.height - self.previewContainerView.bounds.width * sourceAspectRatio) / 2.0), size: CGSize(width: self.previewContainerView.bounds.width, height: self.previewContainerView.bounds.width * sourceAspectRatio)), to: self.previewContainerView.bounds, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
self.previewContainerView.layer.animateBounds(from: CGRect(origin: CGPoint(x: 0.0, y: (self.previewContainerView.bounds.height - self.previewContainerView.bounds.width * sourceAspectRatio) / 2.0), size: CGSize(width: self.previewContainerView.bounds.width, height: self.previewContainerView.bounds.width * sourceAspectRatio)), to: self.previewContainerView.bounds, duration: duration, timingFunction: timingFunction)
|
||||||
|
|
||||||
self.backgroundDimView.isHidden = false
|
self.backgroundDimView.isHidden = false
|
||||||
self.backgroundDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
self.backgroundDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.35)
|
||||||
|
|
||||||
if let componentView = self.componentHost.view {
|
if let componentView = self.componentHost.view {
|
||||||
componentView.layer.animatePosition(from: sourceLocalFrame.center, to: componentView.center, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
componentView.layer.animatePosition(from: sourceLocalFrame.center, to: componentView.center, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
componentView.layer.animateScale(from: sourceScale, to: 1.0, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
componentView.layer.animateScale(from: sourceScale, to: 1.0, duration: duration, timingFunction: timingFunction)
|
||||||
componentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
componentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5231,7 +5241,9 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
let result = super.hitTest(point, with: event)
|
let result = super.hitTest(point, with: event)
|
||||||
if result == self.componentHost.view {
|
if result == self.componentHost.view {
|
||||||
let point = self.view.convert(point, to: self.previewContainerView)
|
let point = self.view.convert(point, to: self.previewContainerView)
|
||||||
return self.previewContainerView.hitTest(point, with: event)
|
if let previewResult = self.previewContainerView.hitTest(point, with: event) {
|
||||||
|
return previewResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -6189,7 +6201,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
fileprivate let transitionOut: (Bool, Bool?) -> TransitionOut?
|
fileprivate let transitionOut: (Bool, Bool?) -> TransitionOut?
|
||||||
|
|
||||||
public var cancelled: (Bool) -> Void = { _ in }
|
public var cancelled: (Bool) -> Void = { _ in }
|
||||||
public var completion: (MediaEditorScreenImpl.Result, @escaping (@escaping () -> Void) -> Void) -> Void = { _, _ in }
|
public var willComplete: (UIImage?, Bool, @escaping () -> Void) -> Void
|
||||||
|
public var completion: (MediaEditorScreenImpl.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
||||||
public var dismissed: () -> Void = { }
|
public var dismissed: () -> Void = { }
|
||||||
public var willDismiss: () -> Void = { }
|
public var willDismiss: () -> Void = { }
|
||||||
public var sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?
|
public var sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?
|
||||||
@ -6222,6 +6235,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
initialLink: (url: String, name: String?)? = nil,
|
initialLink: (url: String, name: String?)? = nil,
|
||||||
transitionIn: TransitionIn?,
|
transitionIn: TransitionIn?,
|
||||||
transitionOut: @escaping (Bool, Bool?) -> TransitionOut?,
|
transitionOut: @escaping (Bool, Bool?) -> TransitionOut?,
|
||||||
|
willComplete: @escaping (UIImage?, Bool, @escaping () -> Void) -> Void = { _, _, commit in commit() },
|
||||||
completion: @escaping (MediaEditorScreenImpl.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
completion: @escaping (MediaEditorScreenImpl.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -6238,6 +6252,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
self.initialLink = initialLink
|
self.initialLink = initialLink
|
||||||
self.transitionIn = transitionIn
|
self.transitionIn = transitionIn
|
||||||
self.transitionOut = transitionOut
|
self.transitionOut = transitionOut
|
||||||
|
self.willComplete = willComplete
|
||||||
self.completion = completion
|
self.completion = completion
|
||||||
|
|
||||||
self.storiesBlockedPeers = BlockedPeersContext(account: context.account, subject: .stories)
|
self.storiesBlockedPeers = BlockedPeersContext(account: context.account, subject: .stories)
|
||||||
@ -7401,6 +7416,10 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
|
|
||||||
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: inputImage, dimensions: storyDimensions, values: mediaEditor.values, time: firstFrameTime, textScale: 2.0, completion: { [weak self] coverImage in
|
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: inputImage, dimensions: storyDimensions, values: mediaEditor.values, time: firstFrameTime, textScale: 2.0, completion: { [weak self] coverImage in
|
||||||
if let self {
|
if let self {
|
||||||
|
self.willComplete(coverImage, true, { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
Logger.shared.log("MediaEditor", "Completed with video \(videoResult)")
|
Logger.shared.log("MediaEditor", "Completed with video \(videoResult)")
|
||||||
self.completion(MediaEditorScreenImpl.Result(media: .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), mediaAreas: mediaAreas, caption: caption, coverTimestamp: mediaEditor.values.coverImageTimestamp, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
|
self.completion(MediaEditorScreenImpl.Result(media: .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), mediaAreas: mediaAreas, caption: caption, coverTimestamp: mediaEditor.values.coverImageTimestamp, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
|
||||||
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
|
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
|
||||||
@ -7410,6 +7429,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -7430,6 +7450,10 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
}
|
}
|
||||||
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, outputDimensions: outputDimensions, values: values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in
|
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, outputDimensions: outputDimensions, values: values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in
|
||||||
if let self, let resultImage {
|
if let self, let resultImage {
|
||||||
|
self.willComplete(resultImage, false, { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
Logger.shared.log("MediaEditor", "Completed with image \(resultImage)")
|
Logger.shared.log("MediaEditor", "Completed with image \(resultImage)")
|
||||||
self.completion(MediaEditorScreenImpl.Result(media: .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), mediaAreas: mediaAreas, caption: caption, coverTimestamp: nil, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
|
self.completion(MediaEditorScreenImpl.Result(media: .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), mediaAreas: mediaAreas, caption: caption, coverTimestamp: nil, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
|
||||||
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
|
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
|
||||||
@ -7442,6 +7466,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
if case let .draft(draft, id) = actualSubject, id == nil {
|
if case let .draft(draft, id) = actualSubject, id == nil {
|
||||||
removeStoryDraft(engine: self.context.engine, path: draft.path, delete: true)
|
removeStoryDraft(engine: self.context.engine, path: draft.path, delete: true)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1579,9 +1579,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
hasSavedMessageTags,
|
hasSavedMessageTags,
|
||||||
isPremiumRequiredForStoryPosting,
|
isPremiumRequiredForStoryPosting,
|
||||||
starsRevenueContextAndState,
|
starsRevenueContextAndState,
|
||||||
revenueContextAndState
|
revenueContextAndState,
|
||||||
|
profileGiftsContext.state
|
||||||
)
|
)
|
||||||
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState -> PeerInfoScreenData in
|
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState, profileGiftsState -> PeerInfoScreenData in
|
||||||
var availablePanes = availablePanes
|
var availablePanes = availablePanes
|
||||||
if let hasStories {
|
if let hasStories {
|
||||||
if hasStories {
|
if hasStories {
|
||||||
@ -1605,7 +1606,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
|
|
||||||
if availablePanes != nil, let cachedData = peerView.cachedData as? CachedChannelData {
|
if availablePanes != nil, let cachedData = peerView.cachedData as? CachedChannelData {
|
||||||
if let starGiftsCount = cachedData.starGiftsCount, starGiftsCount > 0 {
|
if (cachedData.starGiftsCount ?? 0) > 0 || (profileGiftsState.count ?? 0) > 0 {
|
||||||
availablePanes?.insert(.gifts, at: hasStories ? 1 : 0)
|
availablePanes?.insert(.gifts, at: hasStories ? 1 : 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9610,6 +9610,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
currentIsVideo = !videoRepresentations.isEmpty
|
currentIsVideo = !videoRepresentations.isEmpty
|
||||||
emojiMarkup = emojiMarkupValue
|
emojiMarkup = emojiMarkupValue
|
||||||
}
|
}
|
||||||
|
let _ = emojiMarkup
|
||||||
|
|
||||||
let peerId = self.peerId
|
let peerId = self.peerId
|
||||||
let _ = (self.context.engine.data.get(
|
let _ = (self.context.engine.data.get(
|
||||||
@ -9685,31 +9686,31 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasDeleteButton, hasViewButton: false, personalPhoto: strongSelf.isSettings || strongSelf.isMyProfile, isVideo: currentIsVideo, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: isForum, title: title, isSuggesting: [.custom, .suggest].contains(mode))!
|
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasDeleteButton, hasViewButton: false, personalPhoto: strongSelf.isSettings || strongSelf.isMyProfile, isVideo: currentIsVideo, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: isForum, title: title, isSuggesting: [.custom, .suggest].contains(mode))!
|
||||||
mixin.stickersContext = LegacyPaintStickersContext(context: strongSelf.context)
|
mixin.stickersContext = LegacyPaintStickersContext(context: strongSelf.context)
|
||||||
let _ = strongSelf.currentAvatarMixin.swap(mixin)
|
let _ = strongSelf.currentAvatarMixin.swap(mixin)
|
||||||
var isFromEditor = false
|
let isFromEditor = !"".isEmpty
|
||||||
mixin.requestAvatarEditor = { [weak self, weak parentController] imageCompletion, videoCompletion in
|
// mixin.requestAvatarEditor = { [weak self, weak parentController] imageCompletion, videoCompletion in
|
||||||
guard let strongSelf = self, let imageCompletion, let videoCompletion else {
|
// guard let strongSelf = self, let imageCompletion, let videoCompletion else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let peerType: AvatarEditorScreen.PeerType
|
// let peerType: AvatarEditorScreen.PeerType
|
||||||
if mode == .suggest {
|
// if mode == .suggest {
|
||||||
peerType = .suggest
|
// peerType = .suggest
|
||||||
} else if case .legacyGroup = peer {
|
// } else if case .legacyGroup = peer {
|
||||||
peerType = .group
|
// peerType = .group
|
||||||
} else if case let .channel(channel) = peer {
|
// } else if case let .channel(channel) = peer {
|
||||||
if case .group = channel.info {
|
// if case .group = channel.info {
|
||||||
peerType = channel.flags.contains(.isForum) ? .forum : .group
|
// peerType = channel.flags.contains(.isForum) ? .forum : .group
|
||||||
} else {
|
// } else {
|
||||||
peerType = .channel
|
// peerType = .channel
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
peerType = .user
|
// peerType = .user
|
||||||
}
|
// }
|
||||||
let controller = AvatarEditorScreen(context: strongSelf.context, inputData: keyboardInputData.get(), peerType: peerType, markup: emojiMarkup)
|
// let controller = AvatarEditorScreen(context: strongSelf.context, inputData: keyboardInputData.get(), peerType: peerType, markup: emojiMarkup)
|
||||||
controller.imageCompletion = imageCompletion
|
// controller.imageCompletion = imageCompletion
|
||||||
controller.videoCompletion = videoCompletion
|
// controller.videoCompletion = videoCompletion
|
||||||
parentController?.push(controller)
|
// parentController?.push(controller)
|
||||||
isFromEditor = true
|
// isFromEditor = true
|
||||||
}
|
// }
|
||||||
|
|
||||||
if let confirmationTextPhoto, let confirmationAction {
|
if let confirmationTextPhoto, let confirmationAction {
|
||||||
mixin.willFinishWithImage = { [weak self, weak parentController] image, commit in
|
mixin.willFinishWithImage = { [weak self, weak parentController] image, commit in
|
||||||
@ -9737,12 +9738,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
self?.controller?.updateProfilePhoto(image, mode: mode, uploadStatus: nil)
|
self?.controller?.updateProfilePhoto(image, mode: mode, uploadStatus: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mixin.didFinishWithVideo = { [weak self] image, asset, adjustments in
|
// mixin.didFinishWithVideo = { [weak self] image, asset, adjustments, _ in
|
||||||
if let image = image, let asset = asset {
|
// if let image = image, let asset = asset {
|
||||||
completion(image)
|
// completion(image)
|
||||||
self?.controller?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode)
|
// self?.controller?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
mixin.didFinishWithDelete = {
|
mixin.didFinishWithDelete = {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -12238,12 +12239,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
completion()
|
completion()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
galleryController.avatarPhotoEditCompletion = { [weak self] image in
|
|
||||||
self?.controller?.updateProfilePhoto(image, mode: .generic, uploadStatus: nil)
|
|
||||||
}
|
|
||||||
galleryController.avatarVideoEditCompletion = { [weak self] image, asset, adjustments in
|
|
||||||
self?.controller?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: .generic)
|
|
||||||
}
|
|
||||||
galleryController.removedEntry = { [weak self] entry in
|
galleryController.removedEntry = { [weak self] entry in
|
||||||
if let item = PeerInfoAvatarListItem(entry: entry) {
|
if let item = PeerInfoAvatarListItem(entry: entry) {
|
||||||
let _ = self?.headerNode.avatarListNode.listContainerNode.deleteItem(item)
|
let _ = self?.headerNode.avatarListNode.listContainerNode.deleteItem(item)
|
||||||
|
@ -69,7 +69,32 @@ extension PeerInfoScreenImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = hasDeleteButton
|
struct ConfirmationAlert {
|
||||||
|
let title: String
|
||||||
|
let photoText: String
|
||||||
|
let videoText: String
|
||||||
|
let action: String
|
||||||
|
}
|
||||||
|
|
||||||
|
let confirmationAlert: ConfirmationAlert?
|
||||||
|
switch mode {
|
||||||
|
case .suggest:
|
||||||
|
confirmationAlert = ConfirmationAlert(
|
||||||
|
title: self.presentationData.strings.UserInfo_SuggestPhotoTitle(peer.compactDisplayTitle).string,
|
||||||
|
photoText: self.presentationData.strings.UserInfo_SuggestPhoto_AlertPhotoText(peer.compactDisplayTitle).string,
|
||||||
|
videoText: self.presentationData.strings.UserInfo_SuggestPhoto_AlertVideoText(peer.compactDisplayTitle).string,
|
||||||
|
action: self.presentationData.strings.UserInfo_SuggestPhoto_AlertSuggest
|
||||||
|
)
|
||||||
|
case .custom:
|
||||||
|
confirmationAlert = ConfirmationAlert(
|
||||||
|
title: self.presentationData.strings.UserInfo_SetCustomPhotoTitle(peer.compactDisplayTitle).string,
|
||||||
|
photoText: self.presentationData.strings.UserInfo_SetCustomPhoto_AlertPhotoText(peer.compactDisplayTitle, peer.compactDisplayTitle).string,
|
||||||
|
videoText: self.presentationData.strings.UserInfo_SetCustomPhoto_AlertVideoText(peer.compactDisplayTitle, peer.compactDisplayTitle).string,
|
||||||
|
action: self.presentationData.strings.UserInfo_SetCustomPhoto_AlertSet
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
confirmationAlert = nil
|
||||||
|
}
|
||||||
|
|
||||||
let parentController = (self.context.sharedContext.mainWindow?.viewController as? NavigationController)?.topViewController as? ViewController
|
let parentController = (self.context.sharedContext.mainWindow?.viewController as? NavigationController)?.topViewController as? ViewController
|
||||||
|
|
||||||
@ -77,6 +102,9 @@ extension PeerInfoScreenImpl {
|
|||||||
let mainController = self.context.sharedContext.makeAvatarMediaPickerScreen(context: self.context, getSourceRect: { return nil }, canDelete: hasDeleteButton, performDelete: { [weak self] in
|
let mainController = self.context.sharedContext.makeAvatarMediaPickerScreen(context: self.context, getSourceRect: { return nil }, canDelete: hasDeleteButton, performDelete: { [weak self] in
|
||||||
self?.openAvatarRemoval(mode: mode, peer: peer, item: item)
|
self?.openAvatarRemoval(mode: mode, peer: peer, item: item)
|
||||||
}, completion: { result, transitionView, transitionRect, transitionImage, fromCamera, transitionOut, cancelled in
|
}, completion: { result, transitionView, transitionRect, transitionImage, fromCamera, transitionOut, cancelled in
|
||||||
|
var resultImage: UIImage?
|
||||||
|
let uploadStatusPromise = Promise<PeerInfoAvatarUploadStatus>(.progress(0.0))
|
||||||
|
|
||||||
let subject: Signal<MediaEditorScreenImpl.Subject?, NoError>
|
let subject: Signal<MediaEditorScreenImpl.Subject?, NoError>
|
||||||
if let asset = result as? PHAsset {
|
if let asset = result as? PHAsset {
|
||||||
subject = .single(.asset(asset))
|
subject = .single(.asset(asset))
|
||||||
@ -112,15 +140,21 @@ extension PeerInfoScreenImpl {
|
|||||||
peerType = .user
|
peerType = .user
|
||||||
}
|
}
|
||||||
let controller = AvatarEditorScreen(context: self.context, inputData: keyboardInputData.get(), peerType: peerType, markup: emojiMarkup)
|
let controller = AvatarEditorScreen(context: self.context, inputData: keyboardInputData.get(), peerType: peerType, markup: emojiMarkup)
|
||||||
//controller.imageCompletion = imageCompletion
|
controller.imageCompletion = { [weak self] image, commit in
|
||||||
//controller.videoCompletion = videoCompletion
|
resultImage = image
|
||||||
|
self?.updateProfilePhoto(image, mode: mode, uploadStatus: uploadStatusPromise)
|
||||||
|
commit()
|
||||||
|
}
|
||||||
|
controller.videoCompletion = { [weak self] image, url, values, markup, commit in
|
||||||
|
resultImage = image
|
||||||
|
self?.updateProfileVideo(image, asset: url, values: values, markup: markup, mode: mode, uploadStatus: uploadStatusPromise)
|
||||||
|
commit()
|
||||||
|
}
|
||||||
parentController?.push(controller)
|
parentController?.push(controller)
|
||||||
//isFromEditor = true
|
//isFromEditor = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultImage: UIImage?
|
|
||||||
let uploadStatusPromise = Promise<PeerInfoAvatarUploadStatus>(.progress(0.0))
|
|
||||||
let editorController = MediaEditorScreenImpl(
|
let editorController = MediaEditorScreenImpl(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
mode: .avatarEditor,
|
mode: .avatarEditor,
|
||||||
@ -153,7 +187,18 @@ extension PeerInfoScreenImpl {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, completion: { [weak self] result, commit in
|
},
|
||||||
|
willComplete: { [weak self, weak parentController] image, isVideo, commit in
|
||||||
|
if let self, let confirmationAlert, let image {
|
||||||
|
let controller = photoUpdateConfirmationController(context: self.context, peer: peer, image: image, text: isVideo ? confirmationAlert.videoText : confirmationAlert.photoText, doneTitle: confirmationAlert.action, commit: {
|
||||||
|
commit()
|
||||||
|
})
|
||||||
|
parentController?.presentInGlobalOverlay(controller)
|
||||||
|
} else {
|
||||||
|
commit()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
completion: { [weak self] result, commit in
|
||||||
switch result.media {
|
switch result.media {
|
||||||
case let .image(image, _):
|
case let .image(image, _):
|
||||||
resultImage = image
|
resultImage = image
|
||||||
@ -161,10 +206,8 @@ extension PeerInfoScreenImpl {
|
|||||||
commit({})
|
commit({})
|
||||||
case let .video(video, coverImage, values, _, _):
|
case let .video(video, coverImage, values, _, _):
|
||||||
if let coverImage {
|
if let coverImage {
|
||||||
let _ = values
|
|
||||||
//TODO:release
|
|
||||||
resultImage = coverImage
|
resultImage = coverImage
|
||||||
self?.updateProfileVideo(coverImage, asset: video, adjustments: nil, mode: mode)
|
self?.updateProfileVideo(coverImage, asset: video, values: values, markup: nil, mode: mode, uploadStatus: uploadStatusPromise)
|
||||||
}
|
}
|
||||||
commit({})
|
commit({})
|
||||||
default:
|
default:
|
||||||
@ -416,227 +459,135 @@ extension PeerInfoScreenImpl {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// public func updateProfileVideo(_ image: UIImage, video: MediaEditorScreenImpl.MediaResult.VideoResult, values: MediaEditorValues, mode: PeerInfoAvatarEditingMode) {
|
public func updateProfileVideo(_ image: UIImage, asset: Any?, values: MediaEditorValues?, markup: UploadPeerPhotoMarkup?, mode: PeerInfoAvatarEditingMode, uploadStatus: Promise<PeerInfoAvatarUploadStatus>?) {
|
||||||
// var markup: UploadPeerPhotoMarkup? = nil
|
var uploadVideo = true
|
||||||
// if let fileId = adjustments?.documentId, let backgroundColors = adjustments?.colors as? [Int32], fileId != 0 {
|
if let _ = markup {
|
||||||
// if let packId = adjustments?.stickerPackId, let accessHash = adjustments?.stickerPackAccessHash, packId != 0 {
|
if let data = self.context.currentAppConfiguration.with({ $0 }).data, let uploadVideoValue = data["upload_markup_video"] as? Bool, uploadVideoValue {
|
||||||
// markup = .sticker(packReference: .id(id: packId, accessHash: accessHash), fileId: fileId, backgroundColors: backgroundColors)
|
uploadVideo = true
|
||||||
// } else {
|
} else {
|
||||||
// markup = .emoji(fileId: fileId, backgroundColors: backgroundColors)
|
uploadVideo = false
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
guard let photoResource = self.setupProfilePhotoUpload(image: image, mode: mode, indefiniteProgress: !uploadVideo) else {
|
||||||
// var videoStartTimestamp: Double? = nil
|
uploadStatus?.set(.single(.done))
|
||||||
// if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
|
return
|
||||||
// videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
|
}
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var uploadVideo = true
|
|
||||||
// if let _ = markup {
|
|
||||||
// if let data = self.context.currentAppConfiguration.with({ $0 }).data, let uploadVideoValue = data["upload_markup_video"] as? Bool, uploadVideoValue {
|
|
||||||
// uploadVideo = true
|
|
||||||
// } else {
|
|
||||||
// uploadVideo = false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// guard let photoResource = self.setupProfilePhotoUpload(image: image, mode: mode, indefiniteProgress: !uploadVideo) else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let context = self.context
|
|
||||||
//
|
|
||||||
// let videoResource: Signal<TelegramMediaResource?, UploadPeerPhotoError>
|
|
||||||
// if uploadVideo {
|
|
||||||
// let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max)).mp4"
|
|
||||||
// let videoExport = MediaEditorVideoExport(
|
|
||||||
// postbox: context.account.postbox,
|
|
||||||
// subject: .image(image: image),
|
|
||||||
// configuration: configuration,
|
|
||||||
// outputPath: path
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// videoResource = Signal<TelegramMediaResource?, UploadPeerPhotoError> { [weak self] subscriber in
|
|
||||||
// let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
|
|
||||||
// if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
|
|
||||||
// return LegacyPaintEntityRenderer(postbox: account.postbox, adjustments: adjustments)
|
|
||||||
// } else {
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4")
|
|
||||||
// let uploadInterface = LegacyLiveUploadInterface(context: context)
|
|
||||||
// let signal: SSignal
|
|
||||||
// if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
|
||||||
// let durationSignal: SSignal = SSignal(generator: { subscriber in
|
|
||||||
// let disposable = (entityRenderer.duration()).start(next: { duration in
|
|
||||||
// subscriber.putNext(duration)
|
|
||||||
// subscriber.putCompletion()
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// return SBlockDisposable(block: {
|
|
||||||
// disposable.dispose()
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// signal = durationSignal.map(toSignal: { duration -> SSignal in
|
|
||||||
// if let duration = duration as? Double {
|
|
||||||
// return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, path: tempFile.path, watcher: nil, entityRenderer: entityRenderer)!
|
|
||||||
// } else {
|
|
||||||
// return SSignal.single(nil)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// } else if let asset = asset as? AVAsset {
|
|
||||||
// signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, path: tempFile.path, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
|
||||||
// } else {
|
|
||||||
// signal = SSignal.complete()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let signalDisposable = signal.start(next: { next in
|
|
||||||
// if let result = next as? TGMediaVideoConversionResult {
|
|
||||||
// if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
|
|
||||||
// account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if let timestamp = videoStartTimestamp {
|
|
||||||
// videoStartTimestamp = max(0.0, min(timestamp, result.duration - 0.05))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var value = stat()
|
|
||||||
// if stat(result.fileURL.path, &value) == 0 {
|
|
||||||
// if let data = try? Data(contentsOf: result.fileURL) {
|
|
||||||
// let resource: TelegramMediaResource
|
|
||||||
// if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
|
|
||||||
// resource = LocalFileMediaResource(fileId: liveUploadData.id)
|
|
||||||
// } else {
|
|
||||||
// resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
|
||||||
// }
|
|
||||||
// account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
|
||||||
// subscriber.putNext(resource)
|
|
||||||
//
|
|
||||||
// EngineTempBox.shared.dispose(tempFile)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// subscriber.putCompletion()
|
|
||||||
// } else if let strongSelf = self, let progress = next as? NSNumber {
|
|
||||||
// Queue.mainQueue().async {
|
|
||||||
// strongSelf.controllerNode.state = strongSelf.controllerNode.state.withAvatarUploadProgress(.value(CGFloat(progress.floatValue * 0.45)))
|
|
||||||
// if let (layout, navigationHeight) = strongSelf.controllerNode.validLayout {
|
|
||||||
// strongSelf.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }, error: { _ in
|
|
||||||
// }, completed: nil)
|
|
||||||
//
|
|
||||||
// let disposable = ActionDisposable {
|
|
||||||
// signalDisposable?.dispose()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return ActionDisposable {
|
|
||||||
// disposable.dispose()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// videoResource = .single(nil)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var dismissStatus: (() -> Void)?
|
|
||||||
// if [.suggest, .fallback, .accept].contains(mode) {
|
|
||||||
// let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: { [weak self] in
|
|
||||||
// self?.controllerNode.updateAvatarDisposable.set(nil)
|
|
||||||
// dismissStatus?()
|
|
||||||
// }))
|
|
||||||
// dismissStatus = { [weak statusController] in
|
|
||||||
// statusController?.dismiss()
|
|
||||||
// }
|
|
||||||
// if let topController = self.navigationController?.topViewController as? ViewController {
|
|
||||||
// topController.presentInGlobalOverlay(statusController)
|
|
||||||
// } else if let topController = self.parentController?.topViewController as? ViewController {
|
|
||||||
// topController.presentInGlobalOverlay(statusController)
|
|
||||||
// } else {
|
|
||||||
// self.presentInGlobalOverlay(statusController)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let peerId = self.peerId
|
|
||||||
// let isSettings = self.isSettings
|
|
||||||
// let isMyProfile = self.isMyProfile
|
|
||||||
// self.controllerNode.updateAvatarDisposable.set((videoResource
|
|
||||||
// |> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
|
||||||
// if isSettings || isMyProfile {
|
|
||||||
// if case .fallback = mode {
|
|
||||||
// return context.engine.accountData.updateFallbackPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
|
|
||||||
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
|
||||||
// })
|
|
||||||
// } else {
|
|
||||||
// return context.engine.accountData.updateAccountPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, 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, markup: markup, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
|
|
||||||
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
|
||||||
// })
|
|
||||||
// } else if case .suggest = mode {
|
|
||||||
// return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mode: .suggest, 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: videoResource.flatMap { context.engine.peers.uploadedPeerVideo(resource: $0) |> map(Optional.init) }, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
|
|
||||||
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// |> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
|
||||||
// guard let strongSelf = self else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// switch result {
|
|
||||||
// case .complete:
|
|
||||||
// strongSelf.controllerNode.state = strongSelf.controllerNode.state.withUpdatingAvatar(nil).withAvatarUploadProgress(nil)
|
|
||||||
// case let .progress(value):
|
|
||||||
// strongSelf.controllerNode.state = strongSelf.controllerNode.state.withAvatarUploadProgress(.value(CGFloat(0.45 + value * 0.55)))
|
|
||||||
// }
|
|
||||||
// if let (layout, navigationHeight) = strongSelf.controllerNode.validLayout {
|
|
||||||
// strongSelf.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if case .complete = result {
|
|
||||||
// dismissStatus?()
|
|
||||||
//
|
|
||||||
// let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.peerId))
|
|
||||||
// |> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
|
||||||
// if let strongSelf = self, let peer {
|
|
||||||
// switch mode {
|
|
||||||
// case .fallback:
|
|
||||||
// (strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: nil, text: strongSelf.presentationData.strings.Privacy_ProfilePhoto_PublicVideoSuccess, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
|
||||||
// case .custom:
|
|
||||||
// strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, title: nil, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessVideoText(peer.compactDisplayTitle).string, action: nil, duration: 5), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
|
||||||
//
|
|
||||||
// let _ = (strongSelf.context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, peerId: strongSelf.peerId, fetch: peerInfoProfilePhotos(context: strongSelf.context, peerId: strongSelf.peerId)) |> ignoreValues).startStandalone()
|
|
||||||
// case .suggest:
|
|
||||||
// if let navigationController = (strongSelf.navigationController as? NavigationController) {
|
|
||||||
// strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), keepStack: .default, completion: { _ in
|
|
||||||
// }))
|
|
||||||
// }
|
|
||||||
// case .accept:
|
|
||||||
// (strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
|
|
||||||
// if case .info = action {
|
|
||||||
// self?.parentController?.openSettings()
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// }), in: .current)
|
|
||||||
// default:
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }))
|
|
||||||
// }
|
|
||||||
|
|
||||||
public func updateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?, mode: PeerInfoAvatarEditingMode) {
|
var videoStartTimestamp: Double? = nil
|
||||||
|
if let values, let coverImageTimestamp = values.coverImageTimestamp, coverImageTimestamp > 0.0 {
|
||||||
|
videoStartTimestamp = coverImageTimestamp - (values.videoTrimRange?.lowerBound ?? 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
let account = self.context.account
|
||||||
|
let context = self.context
|
||||||
|
|
||||||
|
let videoResource: Signal<TelegramMediaResource?, UploadPeerPhotoError>
|
||||||
|
if uploadVideo {
|
||||||
|
videoResource = Signal { subscriber in
|
||||||
|
return EmptyDisposable
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
videoResource = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dismissStatus: (() -> Void)?
|
||||||
|
if [.suggest, .fallback, .accept].contains(mode) {
|
||||||
|
let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: { [weak self] in
|
||||||
|
self?.controllerNode.updateAvatarDisposable.set(nil)
|
||||||
|
dismissStatus?()
|
||||||
|
}))
|
||||||
|
dismissStatus = { [weak statusController] in
|
||||||
|
statusController?.dismiss()
|
||||||
|
}
|
||||||
|
if let topController = self.navigationController?.topViewController as? ViewController {
|
||||||
|
topController.presentInGlobalOverlay(statusController)
|
||||||
|
} else if let topController = self.parentController?.topViewController as? ViewController {
|
||||||
|
topController.presentInGlobalOverlay(statusController)
|
||||||
|
} else {
|
||||||
|
self.presentInGlobalOverlay(statusController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let peerId = self.peerId
|
||||||
|
let isSettings = self.isSettings
|
||||||
|
let isMyProfile = self.isMyProfile
|
||||||
|
self.controllerNode.updateAvatarDisposable.set((videoResource
|
||||||
|
|> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||||
|
if isSettings || isMyProfile {
|
||||||
|
if case .fallback = mode {
|
||||||
|
return context.engine.accountData.updateFallbackPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
|
||||||
|
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return context.engine.accountData.updateAccountPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, 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, markup: markup, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
|
||||||
|
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||||
|
})
|
||||||
|
} else if case .suggest = mode {
|
||||||
|
return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mode: .suggest, 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: videoResource.flatMap { context.engine.peers.uploadedPeerVideo(resource: $0) |> map(Optional.init) }, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
|
||||||
|
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch result {
|
||||||
|
case .complete:
|
||||||
|
uploadStatus?.set(.single(.done))
|
||||||
|
strongSelf.controllerNode.state = strongSelf.controllerNode.state.withUpdatingAvatar(nil).withAvatarUploadProgress(nil)
|
||||||
|
case let .progress(value):
|
||||||
|
uploadStatus?.set(.single(.progress(value)))
|
||||||
|
strongSelf.controllerNode.state = strongSelf.controllerNode.state.withAvatarUploadProgress(.value(CGFloat(0.45 + value * 0.55)))
|
||||||
|
}
|
||||||
|
if let (layout, navigationHeight) = strongSelf.controllerNode.validLayout {
|
||||||
|
strongSelf.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if case .complete = result {
|
||||||
|
dismissStatus?()
|
||||||
|
|
||||||
|
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.peerId))
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
||||||
|
if let strongSelf = self, let peer {
|
||||||
|
switch mode {
|
||||||
|
case .fallback:
|
||||||
|
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: nil, text: strongSelf.presentationData.strings.Privacy_ProfilePhoto_PublicVideoSuccess, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||||
|
case .custom:
|
||||||
|
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, title: nil, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessVideoText(peer.compactDisplayTitle).string, action: nil, duration: 5), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||||
|
|
||||||
|
let _ = (strongSelf.context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, peerId: strongSelf.peerId, fetch: peerInfoProfilePhotos(context: strongSelf.context, peerId: strongSelf.peerId)) |> ignoreValues).startStandalone()
|
||||||
|
case .suggest:
|
||||||
|
if let navigationController = (strongSelf.navigationController as? NavigationController) {
|
||||||
|
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), keepStack: .default, completion: { _ in
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
case .accept:
|
||||||
|
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
|
||||||
|
if case .info = action {
|
||||||
|
self?.parentController?.openSettings()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}), in: .current)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
public func oldUpdateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?, mode: PeerInfoAvatarEditingMode) {
|
||||||
var markup: UploadPeerPhotoMarkup? = nil
|
var markup: UploadPeerPhotoMarkup? = nil
|
||||||
if let fileId = adjustments?.documentId, let backgroundColors = adjustments?.colors as? [Int32], fileId != 0 {
|
if let fileId = adjustments?.documentId, let backgroundColors = adjustments?.colors as? [Int32], fileId != 0 {
|
||||||
if let packId = adjustments?.stickerPackId, let accessHash = adjustments?.stickerPackAccessHash, packId != 0 {
|
if let packId = adjustments?.stickerPackId, let accessHash = adjustments?.stickerPackAccessHash, packId != 0 {
|
||||||
|
@ -411,7 +411,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(CheckComponent(
|
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(CheckComponent(
|
||||||
theme: checkTheme,
|
theme: checkTheme,
|
||||||
size: CGSize(width: 22.0, height: 22.0),
|
size: CGSize(width: 22.0, height: 22.0),
|
||||||
selected: self.notify
|
selected: self.profileGifts.currentState?.notificationsEnabled ?? false
|
||||||
))),
|
))),
|
||||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(
|
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(string: presentationData.strings.PeerInfo_Gifts_ChannelNotify, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor))
|
text: .plain(NSAttributedString(string: presentationData.strings.PeerInfo_Gifts_ChannelNotify, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor))
|
||||||
@ -421,20 +421,23 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
)),
|
)),
|
||||||
effectAlignment: .center,
|
effectAlignment: .center,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
guard let self else {
|
guard let self, let currentState = self.profileGifts.currentState else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.notify = !self.notify
|
let enabled = !(currentState.notificationsEnabled ?? false)
|
||||||
|
self.profileGifts.toggleStarGiftsNotifications(enabled: enabled)
|
||||||
|
|
||||||
|
let animation = enabled ? "anim_profileunmute" : "anim_profilemute"
|
||||||
|
let text = enabled ? presentationData.strings.PeerInfo_Gifts_ChannelNotifyTooltip : presentationData.strings.PeerInfo_Gifts_ChannelNotifyDisabledTooltip
|
||||||
|
|
||||||
if self.notify {
|
|
||||||
let controller = UndoOverlayController(
|
let controller = UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: ["__allcolors__": UIColor.white], title: nil, text: presentationData.strings.PeerInfo_Gifts_ChannelNotifyTooltip, customUndoText: nil, timeout: nil),
|
content: .universal(animation: animation, scale: 0.075, colors: ["__allcolors__": UIColor.white], title: nil, text: text, customUndoText: nil, timeout: nil),
|
||||||
appearance: UndoOverlayController.Appearance(bottomInset: 53.0),
|
appearance: UndoOverlayController.Appearance(bottomInset: 53.0),
|
||||||
action: { _ in return true }
|
action: { _ in return true }
|
||||||
)
|
)
|
||||||
self.chatControllerInteraction.presentController(controller, nil)
|
self.chatControllerInteraction.presentController(controller, nil)
|
||||||
}
|
|
||||||
self.updateScrolling(transition: .immediate)
|
self.updateScrolling(transition: .immediate)
|
||||||
},
|
},
|
||||||
animateAlpha: false,
|
animateAlpha: false,
|
||||||
|
@ -1233,10 +1233,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
controller.videoCompletion = { [weak self] image, url, adjustments, commit in
|
controller.videoCompletion = { [weak self] image, url, values, markup, commit in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||||
settingsController.updateProfileVideo(image, asset: AVURLAsset(url: url), adjustments: adjustments, mode: .accept)
|
settingsController.updateProfileVideo(image, asset: AVURLAsset(url: url), values: values, markup: markup, mode: .accept, uploadStatus: nil)
|
||||||
commit()
|
commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1271,7 +1271,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, videoCompletion: { [weak self] image, url, adjustments in
|
}, videoCompletion: { [weak self] image, url, adjustments in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||||
settingsController.updateProfileVideo(image, asset: AVURLAsset(url: url), adjustments: adjustments, mode: .accept)
|
settingsController.oldUpdateProfileVideo(image, asset: AVURLAsset(url: url), adjustments: adjustments, mode: .accept)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -642,15 +642,15 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
}))
|
}))
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
mixin.requestAvatarEditor = { imageCompletion, videoCompletion in
|
// mixin.requestAvatarEditor = { imageCompletion, videoCompletion in
|
||||||
guard let imageCompletion, let videoCompletion else {
|
// guard let imageCompletion, let videoCompletion else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .channel, markup: nil)
|
// let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .channel, markup: nil)
|
||||||
controller.imageCompletion = imageCompletion
|
// controller.imageCompletion = imageCompletion
|
||||||
controller.videoCompletion = videoCompletion
|
// controller.videoCompletion = videoCompletion
|
||||||
pushControllerImpl?(controller)
|
// pushControllerImpl?(controller)
|
||||||
}
|
// }
|
||||||
mixin.didFinishWithImage = { image in
|
mixin.didFinishWithImage = { image in
|
||||||
if let image = image {
|
if let image = image {
|
||||||
completedChannelPhotoImpl(image)
|
completedChannelPhotoImpl(image)
|
||||||
|
@ -1061,15 +1061,15 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
|||||||
}))
|
}))
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
mixin.requestAvatarEditor = { imageCompletion, videoCompletion in
|
// mixin.requestAvatarEditor = { imageCompletion, videoCompletion in
|
||||||
guard let imageCompletion, let videoCompletion else {
|
// guard let imageCompletion, let videoCompletion else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .group, markup: nil)
|
// let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .group, markup: nil)
|
||||||
controller.imageCompletion = imageCompletion
|
// controller.imageCompletion = imageCompletion
|
||||||
controller.videoCompletion = videoCompletion
|
// controller.videoCompletion = videoCompletion
|
||||||
pushImpl?(controller)
|
// pushImpl?(controller)
|
||||||
}
|
// }
|
||||||
mixin.didFinishWithImage = { image in
|
mixin.didFinishWithImage = { image in
|
||||||
if let image = image {
|
if let image = image {
|
||||||
completedGroupPhotoImpl(image)
|
completedGroupPhotoImpl(image)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user