mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-25 17:43:18 +00:00
Video avatar fixes
This commit is contained in:
parent
4755ee4261
commit
a34b7402be
@ -3,6 +3,8 @@ import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
|
||||
private let minimalStreamableSize: Int = 384 * 1024
|
||||
|
||||
public func isMediaStreamable(message: Message, media: TelegramMediaFile) -> Bool {
|
||||
if message.containsSecretMedia {
|
||||
return false
|
||||
@ -13,7 +15,7 @@ public func isMediaStreamable(message: Message, media: TelegramMediaFile) -> Boo
|
||||
guard let size = media.size else {
|
||||
return false
|
||||
}
|
||||
if size < 256 * 1024 {
|
||||
if size < minimalStreamableSize {
|
||||
return false
|
||||
}
|
||||
for attribute in media.attributes {
|
||||
@ -36,7 +38,7 @@ public func isMediaStreamable(media: TelegramMediaFile) -> Bool {
|
||||
guard let size = media.size else {
|
||||
return false
|
||||
}
|
||||
if size < 1 * 1024 * 1024 {
|
||||
if size < minimalStreamableSize {
|
||||
return false
|
||||
}
|
||||
for attribute in media.attributes {
|
||||
@ -49,3 +51,11 @@ public func isMediaStreamable(media: TelegramMediaFile) -> Bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public func isMediaStreamable(resource: MediaResource) -> Bool {
|
||||
if let size = resource.size, size >= minimalStreamableSize {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
|
||||
node?.itemChanged = { [weak self] index in
|
||||
if let strongSelf = self {
|
||||
let pagerIndex = indexes[index]
|
||||
strongSelf.pager.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: pagerIndex))
|
||||
strongSelf.pager.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: pagerIndex, synchronous: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ public struct GalleryItemIndexData: Equatable {
|
||||
public protocol GalleryItem {
|
||||
var id: AnyHashable { get }
|
||||
|
||||
func node() -> GalleryItemNode
|
||||
func updateNode(node: GalleryItemNode)
|
||||
func node(synchronous: Bool) -> GalleryItemNode
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool)
|
||||
func thumbnailItem() -> (Int64, GalleryThumbnailItem)?
|
||||
}
|
||||
|
||||
@ -64,12 +64,14 @@ public struct GalleryPagerTransaction {
|
||||
public let insertItems: [GalleryPagerInsertItem]
|
||||
public let updateItems: [GalleryPagerUpdateItem]
|
||||
public let focusOnItem: Int?
|
||||
public let synchronous: Bool
|
||||
|
||||
public init(deleteItems: [Int], insertItems: [GalleryPagerInsertItem], updateItems: [GalleryPagerUpdateItem], focusOnItem: Int?) {
|
||||
public init(deleteItems: [Int], insertItems: [GalleryPagerInsertItem], updateItems: [GalleryPagerUpdateItem], focusOnItem: Int?, synchronous: Bool) {
|
||||
self.deleteItems = deleteItems
|
||||
self.insertItems = insertItems
|
||||
self.updateItems = updateItems
|
||||
self.focusOnItem = focusOnItem
|
||||
self.synchronous = synchronous
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,12 +312,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
}
|
||||
}
|
||||
|
||||
public func replaceItems(_ items: [GalleryItem], centralItemIndex: Int?, keepFirst: Bool = false) {
|
||||
var items = items
|
||||
if keepFirst && !self.items.isEmpty && !items.isEmpty {
|
||||
items[0] = self.items[0]
|
||||
}
|
||||
|
||||
public func replaceItems(_ items: [GalleryItem], centralItemIndex: Int?, synchronous: Bool = false) {
|
||||
var updateItems: [GalleryPagerUpdateItem] = []
|
||||
var deleteItems: [Int] = []
|
||||
var insertItems: [GalleryPagerInsertItem] = []
|
||||
@ -333,7 +330,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
insertItems.append(GalleryPagerInsertItem(index: i, item: items[i], previousIndex: previousIndexById[items[i].id]))
|
||||
}
|
||||
|
||||
self.transaction(GalleryPagerTransaction(deleteItems: deleteItems, insertItems: insertItems, updateItems: updateItems, focusOnItem: centralItemIndex))
|
||||
self.transaction(GalleryPagerTransaction(deleteItems: deleteItems, insertItems: insertItems, updateItems: updateItems, focusOnItem: centralItemIndex, synchronous: synchronous))
|
||||
}
|
||||
|
||||
public func transaction(_ transaction: GalleryPagerTransaction) {
|
||||
@ -341,7 +338,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
self.items[updatedItem.previousIndex] = updatedItem.item
|
||||
if let itemNode = self.visibleItemNode(at: updatedItem.previousIndex) {
|
||||
//print("update visible node at \(updatedItem.previousIndex)")
|
||||
updatedItem.item.updateNode(node: itemNode)
|
||||
updatedItem.item.updateNode(node: itemNode, synchronous: transaction.synchronous)
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,7 +392,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
self.centralItemIndex = focusOnItem
|
||||
}
|
||||
|
||||
self.updateItemNodes(transition: .immediate, notify: transaction.focusOnItem != nil)
|
||||
self.updateItemNodes(transition: .immediate, notify: transaction.focusOnItem != nil, synchronous: transaction.synchronous)
|
||||
|
||||
//print("visible indices after update \(self.itemNodes.map { $0.index })")
|
||||
}
|
||||
@ -425,18 +422,18 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
|
||||
private func goToPreviousItem() {
|
||||
if let index = self.centralItemIndex, index > 0 {
|
||||
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
||||
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||
}
|
||||
}
|
||||
|
||||
private func goToNextItem() {
|
||||
if let index = self.centralItemIndex, index < self.items.count - 1 {
|
||||
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1))
|
||||
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1, synchronous: false))
|
||||
}
|
||||
}
|
||||
|
||||
private func makeNodeForItem(at index: Int) -> GalleryItemNode {
|
||||
let node = self.items[index].node()
|
||||
private func makeNodeForItem(at index: Int, synchronous: Bool) -> GalleryItemNode {
|
||||
let node = self.items[index].node(synchronous: synchronous)
|
||||
node.toggleControlsVisibility = self.toggleControlsVisibility
|
||||
node.dismiss = self.dismiss
|
||||
node.beginCustomDismiss = self.beginCustomDismiss
|
||||
@ -475,7 +472,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
self.itemNodes.remove(at: internalIndex)
|
||||
}
|
||||
|
||||
private func updateItemNodes(transition: ContainedViewLayoutTransition, forceOffsetReset: Bool = false, notify: Bool = false, forceLoad: Bool = false) {
|
||||
private func updateItemNodes(transition: ContainedViewLayoutTransition, forceOffsetReset: Bool = false, notify: Bool = false, forceLoad: Bool = false, synchronous: Bool = false) {
|
||||
if self.items.isEmpty || self.containerLayout == nil {
|
||||
return
|
||||
}
|
||||
@ -487,7 +484,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
} while self.itemNodes.count > 0
|
||||
}
|
||||
if self.itemNodes.isEmpty {
|
||||
let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0)
|
||||
let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0, synchronous: synchronous)
|
||||
node.frame = CGRect(origin: CGPoint(), size: scrollView.bounds.size)
|
||||
if let containerLayout = self.containerLayout {
|
||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||
@ -502,7 +499,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
if let centralItemIndex = self.centralItemIndex, let centralItemNode = self.visibleItemNode(at: centralItemIndex) {
|
||||
if centralItemIndex != 0 {
|
||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex - 1) == nil {
|
||||
let node = self.makeNodeForItem(at: centralItemIndex - 1)
|
||||
let node = self.makeNodeForItem(at: centralItemIndex - 1, synchronous: synchronous)
|
||||
node.frame = centralItemNode.frame.offsetBy(dx: -centralItemNode.frame.size.width - self.pageGap, dy: 0.0)
|
||||
if let containerLayout = self.containerLayout {
|
||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||
@ -513,7 +510,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
|
||||
if centralItemIndex != self.items.count - 1 {
|
||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex + 1) == nil {
|
||||
let node = self.makeNodeForItem(at: centralItemIndex + 1)
|
||||
let node = self.makeNodeForItem(at: centralItemIndex + 1, synchronous: synchronous)
|
||||
node.frame = centralItemNode.frame.offsetBy(dx: centralItemNode.frame.size.width + self.pageGap, dy: 0.0)
|
||||
if let containerLayout = self.containerLayout {
|
||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||
@ -549,7 +546,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
|
||||
if centralItemCandidateNode.index != 0 {
|
||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemCandidateNode.index - 1) == nil {
|
||||
let node = self.makeNodeForItem(at: centralItemCandidateNode.index - 1)
|
||||
let node = self.makeNodeForItem(at: centralItemCandidateNode.index - 1, synchronous: synchronous)
|
||||
node.frame = centralItemCandidateNode.frame.offsetBy(dx: -centralItemCandidateNode.frame.size.width - self.pageGap, dy: 0.0)
|
||||
if let containerLayout = self.containerLayout {
|
||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||
@ -560,7 +557,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
||||
|
||||
if centralItemCandidateNode.index != items.count - 1 {
|
||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemCandidateNode.index + 1) == nil {
|
||||
let node = self.makeNodeForItem(at: centralItemCandidateNode.index + 1)
|
||||
let node = self.makeNodeForItem(at: centralItemCandidateNode.index + 1, synchronous: synchronous)
|
||||
node.frame = centralItemCandidateNode.frame.offsetBy(dx: centralItemCandidateNode.frame.size.width + self.pageGap, dy: 0.0)
|
||||
if let containerLayout = self.containerLayout {
|
||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||
|
||||
@ -31,7 +31,7 @@ class ChatAnimationGalleryItem: GalleryItem {
|
||||
self.location = location
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = ChatAnimationGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
||||
|
||||
for media in self.message.media {
|
||||
@ -46,7 +46,7 @@ class ChatAnimationGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? ChatAnimationGalleryItemNode {
|
||||
node.setMessage(self.message)
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ class ChatDocumentGalleryItem: GalleryItem {
|
||||
self.location = location
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = ChatDocumentGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
||||
|
||||
for media in self.message.media {
|
||||
@ -51,7 +51,7 @@ class ChatDocumentGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? ChatDocumentGalleryItemNode, let location = self.location {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
||||
node.setMessage(self.message)
|
||||
|
||||
@ -29,7 +29,7 @@ class ChatExternalFileGalleryItem: GalleryItem {
|
||||
self.location = location
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = ChatExternalFileGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
||||
|
||||
for media in self.message.media {
|
||||
@ -52,7 +52,7 @@ class ChatExternalFileGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? ChatExternalFileGalleryItemNode, let location = self.location {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
||||
node.setMessage(self.message)
|
||||
|
||||
@ -101,7 +101,7 @@ class ChatImageGalleryItem: GalleryItem {
|
||||
self.present = present
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = ChatImageGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present)
|
||||
|
||||
for media in self.message.media {
|
||||
@ -131,7 +131,7 @@ class ChatImageGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? ChatImageGalleryItemNode, let location = self.location {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
||||
self.present = present
|
||||
}
|
||||
|
||||
public func node() -> GalleryItemNode {
|
||||
public func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = UniversalVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present)
|
||||
|
||||
if let indexData = self.indexData {
|
||||
@ -78,7 +78,7 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
public func updateNode(node: GalleryItemNode) {
|
||||
public func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? UniversalVideoGalleryItemNode {
|
||||
if let indexData = self.indexData {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
||||
|
||||
@ -62,7 +62,7 @@ class InstantImageGalleryItem: GalleryItem {
|
||||
self.openUrlOptions = openUrlOptions
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = InstantImageGalleryItemNode(context: self.context, presentationData: self.presentationData, openUrl: self.openUrl, openUrlOptions: self.openUrlOptions)
|
||||
|
||||
node.setImage(imageReference: self.imageReference)
|
||||
@ -76,7 +76,7 @@ class InstantImageGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? InstantImageGalleryItemNode {
|
||||
if let location = self.location {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.position + 1)", "\(location.totalCount)").0))
|
||||
|
||||
@ -221,7 +221,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
|
||||
if strongSelf.isViewLoaded {
|
||||
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
||||
$0.item(context: context, webPage: webPage, message: message, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, landscape: landscape, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
|
||||
}), centralItemIndex: centralIndex, keepFirst: false)
|
||||
}), centralItemIndex: centralIndex)
|
||||
|
||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
||||
strongSelf?.didSetReady = true
|
||||
|
||||
@ -81,7 +81,6 @@
|
||||
#import <LegacyComponents/TGCameraMainTabletView.h>
|
||||
#import <LegacyComponents/TGCameraMainView.h>
|
||||
#import <LegacyComponents/TGCameraModeControl.h>
|
||||
#import <LegacyComponents/TGCameraPhotoPreviewController.h>
|
||||
#import <LegacyComponents/TGCameraPreviewView.h>
|
||||
#import <LegacyComponents/TGCameraSegmentsView.h>
|
||||
#import <LegacyComponents/TGCameraShutterButton.h>
|
||||
|
||||
@ -25,7 +25,8 @@ typedef enum
|
||||
PGCameraModePhoto,
|
||||
PGCameraModeVideo,
|
||||
PGCameraModeSquarePhoto,
|
||||
PGCameraModeSquareVideo
|
||||
PGCameraModeSquareVideo,
|
||||
PGCameraModeSquareSwing
|
||||
} PGCameraMode;
|
||||
|
||||
typedef enum
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
#import <LegacyComponents/TGOverlayController.h>
|
||||
#import <LegacyComponents/LegacyComponentsContext.h>
|
||||
|
||||
@class PGCameraShotMetadata;
|
||||
@class PGPhotoEditorValues;
|
||||
@class TGSuggestionContext;
|
||||
|
||||
@interface TGCameraPhotoPreviewController : TGOverlayController
|
||||
|
||||
@property (nonatomic, assign) bool allowCaptions;
|
||||
|
||||
@property (nonatomic, copy) CGRect(^beginTransitionIn)(void);
|
||||
@property (nonatomic, copy) CGRect(^beginTransitionOut)(CGRect referenceFrame);
|
||||
|
||||
@property (nonatomic, copy) void(^finishedTransitionIn)(void);
|
||||
|
||||
@property (nonatomic, copy) void (^photoEditorShown)(void);
|
||||
@property (nonatomic, copy) void (^photoEditorHidden)(void);
|
||||
|
||||
@property (nonatomic, copy) void(^retakePressed)(void);
|
||||
@property (nonatomic, copy) void(^sendPressed)(TGOverlayController *controller, UIImage *resultImage, NSString *caption, NSArray *entities, NSArray *stickers, NSNumber *timer);
|
||||
|
||||
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
|
||||
@property (nonatomic, assign) bool shouldStoreAssets;
|
||||
@property (nonatomic, assign) bool hasTimer;
|
||||
@property (nonatomic, assign) bool hasSilentPosting;
|
||||
@property (nonatomic, assign) bool hasSchedule;
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context image:(UIImage *)image metadata:(PGCameraShotMetadata *)metadata recipientName:(NSString *)recipientName saveCapturedMedia:(bool)saveCapturedMedia saveEditedPhotos:(bool)saveEditedPhotos;
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context image:(UIImage *)image metadata:(PGCameraShotMetadata *)metadata recipientName:(NSString *)recipientName backButtonTitle:(NSString *)backButtonTitle doneButtonTitle:(NSString *)doneButtonTitle saveCapturedMedia:(bool)saveCapturedMedia saveEditedPhotos:(bool)saveEditedPhotos;
|
||||
|
||||
|
||||
@end
|
||||
@ -38,10 +38,11 @@ typedef enum
|
||||
@property (nonatomic, readonly) UIImage *badge;
|
||||
@property (nonatomic, readonly) UIColor *badgeTextColor;
|
||||
@property (nonatomic, readonly) UIImage *sendIconImage;
|
||||
@property (nonatomic, readonly) UIImage *doneIconImage;
|
||||
|
||||
@property (nonatomic, readonly) UIColor *maybeAccentColor;
|
||||
|
||||
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage maybeAccentColor:(UIColor *)maybeAccentColor;
|
||||
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage doneIconImage:(UIImage *)doneIconImage maybeAccentColor:(UIColor *)maybeAccentColor;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
@class PGCameraShotMetadata;
|
||||
@class TGSuggestionContext;
|
||||
@class TGPhotoEditorController;
|
||||
@class AVPlayer;
|
||||
|
||||
@protocol TGPhotoPaintStickersContext;
|
||||
@class TGPhotoEntitiesContainerView;
|
||||
@ -57,6 +58,10 @@ typedef enum {
|
||||
@property (nonatomic, strong) PGCameraShotMetadata *metadata;
|
||||
@property (nonatomic, strong) NSArray *faces;
|
||||
|
||||
@property (nonatomic, strong) NSArray *cachedVideoThumbnails;
|
||||
|
||||
@property (nonatomic, strong) AVPlayer *player;
|
||||
|
||||
@property (nonatomic, strong) TGPhotoEntitiesContainerView *entitiesView;
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id<TGMediaEditableItem>)item intent:(TGPhotoEditorControllerIntent)intent adjustments:(id<TGMediaEditAdjustments>)adjustments caption:(NSString *)caption screenImage:(UIImage *)screenImage availableTabs:(TGPhotoEditorTab)availableTabs selectedTab:(TGPhotoEditorTab)selectedTab;
|
||||
|
||||
@ -63,6 +63,7 @@
|
||||
|
||||
- (bool)isDismissAllowed;
|
||||
|
||||
- (bool)hasOnScreenNavigation;
|
||||
- (UIInterfaceOrientation)effectiveOrientation;
|
||||
- (UIInterfaceOrientation)effectiveOrientation:(UIInterfaceOrientation)orientation;
|
||||
|
||||
|
||||
@ -28,7 +28,8 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
TGPhotoEditorDoneButtonSend,
|
||||
TGPhotoEditorDoneButtonCheck
|
||||
TGPhotoEditorDoneButtonCheck,
|
||||
TGPhotoEditorDoneButtonDone
|
||||
} TGPhotoEditorDoneButton;
|
||||
|
||||
@interface TGPhotoToolbarView : UIView
|
||||
@ -47,6 +48,9 @@ typedef enum
|
||||
@property (nonatomic, readonly) CGRect cancelButtonFrame;
|
||||
@property (nonatomic, readonly) CGRect doneButtonFrame;
|
||||
|
||||
@property (nonatomic, assign) TGPhotoEditorBackButton backButtonType;
|
||||
@property (nonatomic, assign) TGPhotoEditorDoneButton doneButtonType;
|
||||
|
||||
- (instancetype)initWithBackButton:(TGPhotoEditorBackButton)backButton doneButton:(TGPhotoEditorDoneButton)doneButton solidBackground:(bool)solidBackground;
|
||||
|
||||
- (void)transitionInAnimated:(bool)animated;
|
||||
|
||||
@ -384,7 +384,7 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus";
|
||||
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
|
||||
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
||||
|
||||
if (self.cameraMode == PGCameraModeSquarePhoto || self.cameraMode == PGCameraModeSquareVideo)
|
||||
if (self.cameraMode == PGCameraModeSquarePhoto || self.cameraMode == PGCameraModeSquareVideo || self.cameraMode == PGCameraModeSquareSwing)
|
||||
{
|
||||
CGFloat shorterSide = MIN(image.size.width, image.size.height);
|
||||
CGFloat longerSide = MAX(image.size.width, image.size.height);
|
||||
@ -636,7 +636,7 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus";
|
||||
|
||||
- (bool)flashActive
|
||||
{
|
||||
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo)
|
||||
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo || self.cameraMode == PGCameraModeSquareSwing)
|
||||
return self.captureSession.videoDevice.torchActive;
|
||||
|
||||
return self.captureSession.videoDevice.flashActive;
|
||||
@ -644,7 +644,7 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus";
|
||||
|
||||
- (bool)flashAvailable
|
||||
{
|
||||
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo)
|
||||
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo || self.cameraMode == PGCameraModeSquareSwing)
|
||||
return self.captureSession.videoDevice.torchAvailable;
|
||||
|
||||
return self.captureSession.videoDevice.flashAvailable;
|
||||
|
||||
@ -188,7 +188,7 @@ const NSInteger PGCameraFrameRate = 30;
|
||||
if (self.currentCameraPosition != _preferredCameraPosition)
|
||||
return true;
|
||||
|
||||
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo)
|
||||
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo || self.currentMode == PGCameraModeSquareSwing)
|
||||
return true;
|
||||
|
||||
if (self.zoomLevel > FLT_EPSILON)
|
||||
@ -270,11 +270,12 @@ const NSInteger PGCameraFrameRate = 30;
|
||||
|
||||
case PGCameraModeVideo:
|
||||
case PGCameraModeSquareVideo:
|
||||
case PGCameraModeSquareSwing:
|
||||
{
|
||||
self.sessionPreset = AVCaptureSessionPresetInputPriority;
|
||||
[self switchToBestVideoFormatForDevice:_videoDevice];
|
||||
[self _addAudioInputRequestAudioSession:true];
|
||||
[self setFrameRate:PGCameraFrameRate forDevice:_videoDevice];
|
||||
[self setFrameRate:mode == PGCameraFrameRate forDevice:_videoDevice];
|
||||
}
|
||||
break;
|
||||
|
||||
@ -529,6 +530,7 @@ const NSInteger PGCameraFrameRate = 30;
|
||||
{
|
||||
case PGCameraModeVideo:
|
||||
case PGCameraModeSquareVideo:
|
||||
case PGCameraModeSquareSwing:
|
||||
return _videoFlashMode;
|
||||
|
||||
default:
|
||||
@ -544,6 +546,7 @@ const NSInteger PGCameraFrameRate = 30;
|
||||
{
|
||||
case PGCameraModeVideo:
|
||||
case PGCameraModeSquareVideo:
|
||||
case PGCameraModeSquareSwing:
|
||||
{
|
||||
AVCaptureTorchMode torchMode = [PGCameraCaptureSession _deviceTorchModeForCameraFlashMode:mode];
|
||||
if (device.hasTorch && [device isTorchModeSupported:torchMode])
|
||||
@ -660,7 +663,7 @@ const NSInteger PGCameraFrameRate = 30;
|
||||
|
||||
[self commitConfiguration];
|
||||
|
||||
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo)
|
||||
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo || self.currentMode == PGCameraModeSquareSwing)
|
||||
[self setFrameRate:PGCameraFrameRate forDevice:deviceForTargetPosition];
|
||||
else
|
||||
[self setFrameRate:0 forDevice:deviceForTargetPosition];
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#import "PGPhotoBlurPass.h"
|
||||
|
||||
#import "GPUImageTwoInputFilter.h"
|
||||
#import "GPUImageThreeInputFilter.h"
|
||||
#import "PGPhotoGaussianBlurFilter.h"
|
||||
|
||||
NSString *const PGPhotoRadialBlurShaderString = PGShaderString
|
||||
@ -54,12 +55,33 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const PGPhotoMaskedBlurShaderString = PGShaderString
|
||||
(
|
||||
varying highp vec2 texCoord;
|
||||
varying highp vec2 texCoord2;
|
||||
varying highp vec2 texCoord3;
|
||||
|
||||
uniform sampler2D sourceImage;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
uniform sampler2D inputImageTexture3;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 sharpImageColor = texture2D(sourceImage, texCoord);
|
||||
lowp vec4 blurredImageColor = texture2D(inputImageTexture2, texCoord2);
|
||||
lowp vec4 maskImageColor = texture2D(inputImageTexture3, texCoord3);
|
||||
|
||||
gl_FragColor = mix(blurredImageColor, sharpImageColor, maskImageColor.r);
|
||||
}
|
||||
);
|
||||
|
||||
@interface PGPhotoBlurFilter : GPUImageOutput <GPUImageInput>
|
||||
{
|
||||
PGPhotoGaussianBlurFilter *_blurFilter;
|
||||
|
||||
GPUImageTwoInputFilter *_radialFocusFilter;
|
||||
GPUImageTwoInputFilter *_linearFocusFilter;
|
||||
GPUImageThreeInputFilter *_maskedFilter;
|
||||
|
||||
GPUImageOutput <GPUImageInput> *_currentFocusFilter;
|
||||
|
||||
@ -104,6 +126,10 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
||||
}
|
||||
break;
|
||||
|
||||
case PGBlurToolTypePortrait:
|
||||
{
|
||||
_currentFocusFilter = _maskedFilter;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -192,6 +218,7 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
||||
[_blurFilter setInputSize:newSize atIndex:textureIndex];
|
||||
[_radialFocusFilter setInputSize:newSize atIndex:textureIndex];
|
||||
[_linearFocusFilter setInputSize:newSize atIndex:textureIndex];
|
||||
[_maskedFilter setInputSize:newSize atIndex:textureIndex];
|
||||
|
||||
CGFloat aspectRatio = newSize.height / newSize.width;
|
||||
[_radialFocusFilter setFloat:(float)aspectRatio forUniformName:@"aspectRatio"];
|
||||
@ -203,6 +230,7 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
||||
[_blurFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[_radialFocusFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[_linearFocusFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[_maskedFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
}
|
||||
|
||||
- (CGSize)maximumOutputSize
|
||||
|
||||
@ -937,7 +937,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
||||
{
|
||||
if (editableItem.isVideo) {
|
||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||
} else {
|
||||
|
||||
@ -921,6 +921,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
|
||||
case PGCameraModeVideo:
|
||||
case PGCameraModeSquareVideo:
|
||||
case PGCameraModeSquareSwing:
|
||||
{
|
||||
if (!_camera.isRecordingVideo)
|
||||
{
|
||||
@ -994,7 +995,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
});
|
||||
}];
|
||||
}
|
||||
else if (cameraMode == PGCameraModeVideo)
|
||||
else if (cameraMode == PGCameraModeVideo || cameraMode == PGCameraModeSquareVideo || cameraMode == PGCameraModeSquareSwing)
|
||||
{
|
||||
if (!_camera.isRecordingVideo)
|
||||
{
|
||||
@ -1009,14 +1010,18 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
if (success)
|
||||
{
|
||||
TGCameraCapturedVideo *capturedVideo = [[TGCameraCapturedVideo alloc] initWithURL:outputURL];
|
||||
if (strongSelf->_intent == TGCameraControllerAvatarIntent || strongSelf->_intent == TGCameraControllerSignupAvatarIntent)
|
||||
{
|
||||
[strongSelf presentPhotoResultControllerWithImage:capturedVideo metadata:nil completion:^{}];
|
||||
} else {
|
||||
[strongSelf addResultItem:capturedVideo];
|
||||
|
||||
if (![strongSelf maybePresentResultControllerForItem:capturedVideo completion:nil])
|
||||
{
|
||||
strongSelf->_camera.disabled = false;
|
||||
[strongSelf->_interfaceView setRecordingVideo:false animated:true];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[strongSelf->_interfaceView setRecordingVideo:false animated:false];
|
||||
@ -1655,16 +1660,30 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
|
||||
#pragma mark - Legacy Photo Result
|
||||
|
||||
- (void)presentPhotoResultControllerWithImage:(UIImage *)image metadata:(PGCameraShotMetadata *)metadata completion:(void (^)(void))completion
|
||||
- (void)presentPhotoResultControllerWithImage:(id<TGMediaEditableItem>)input metadata:(PGCameraShotMetadata *)metadata completion:(void (^)(void))completion
|
||||
{
|
||||
[[[LegacyComponentsGlobals provider] applicationInstance] setIdleTimerDisabled:false];
|
||||
|
||||
if (image == nil || image.size.width < FLT_EPSILON)
|
||||
if (input == nil || ([input isKindOfClass:[UIImage class]] && ((UIImage *)input).size.width < FLT_EPSILON))
|
||||
{
|
||||
[self beginTransitionOutWithVelocity:0.0f];
|
||||
return;
|
||||
}
|
||||
|
||||
UIImage *image = nil;
|
||||
if ([input isKindOfClass:[UIImage class]]) {
|
||||
image = (UIImage *)input;
|
||||
} else if ([input isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
AVAsset *asset = ((TGCameraCapturedVideo *)input).immediateAVAsset;
|
||||
|
||||
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
|
||||
generator.appliesPreferredTrackTransform = true;
|
||||
generator.maximumSize = CGSizeMake(640.0f, 640.0f);
|
||||
CGImageRef imageRef = [generator copyCGImageAtTime:kCMTimeZero actualTime:NULL error:NULL];
|
||||
image = [[UIImage alloc] initWithCGImage:imageRef];
|
||||
CGImageRelease(imageRef);
|
||||
}
|
||||
|
||||
id<LegacyComponentsOverlayWindowManager> windowManager = nil;
|
||||
id<LegacyComponentsContext> windowContext = nil;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
|
||||
@ -1679,16 +1698,11 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
|
||||
_focusControl.ignoreAutofocusing = true;
|
||||
|
||||
switch (_intent)
|
||||
{
|
||||
case TGCameraControllerAvatarIntent:
|
||||
case TGCameraControllerSignupAvatarIntent:
|
||||
{
|
||||
TGPhotoEditorControllerIntent intent = TGPhotoEditorControllerAvatarIntent;
|
||||
if (_intent == TGCameraControllerSignupAvatarIntent) {
|
||||
intent = TGPhotoEditorControllerSignupAvatarIntent;
|
||||
}
|
||||
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:windowContext item:image intent:(TGPhotoEditorControllerFromCameraIntent | intent) adjustments:nil caption:nil screenImage:image availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
|
||||
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:windowContext item:input intent:(TGPhotoEditorControllerFromCameraIntent | intent) adjustments:nil caption:nil screenImage:image availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
|
||||
controller.stickersContext = _stickersContext;
|
||||
__weak TGPhotoEditorController *weakController = controller;
|
||||
controller.beginTransitionIn = ^UIView *(CGRect *referenceFrame, __unused UIView **parentView)
|
||||
@ -1738,7 +1752,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
if (strongSelf.finishedWithPhoto != nil)
|
||||
strongSelf.finishedWithPhoto(nil, resultImage, nil, nil, nil, nil);
|
||||
|
||||
if (strongSelf.shouldStoreCapturedAssets)
|
||||
if (strongSelf.shouldStoreCapturedAssets && [input isKindOfClass:[UIImage class]])
|
||||
{
|
||||
[strongSelf _savePhotoToCameraRollWithOriginalImage:image editedImage:[editorValues toolsApplied] ? resultImage : nil];
|
||||
}
|
||||
@ -1766,7 +1780,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
{
|
||||
if (editableItem.isVideo) {
|
||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||
} else {
|
||||
@ -1778,79 +1792,6 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
};
|
||||
|
||||
overlayController = (TGOverlayController *)controller;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
TGCameraPhotoPreviewController *controller = _shortcut ? [[TGCameraPhotoPreviewController alloc] initWithContext:windowContext image:image metadata:metadata recipientName:self.recipientName backButtonTitle:TGLocalized(@"Camera.Retake") doneButtonTitle:TGLocalized(@"Common.Next") saveCapturedMedia:_saveCapturedMedia saveEditedPhotos:_saveEditedPhotos] : [[TGCameraPhotoPreviewController alloc] initWithContext:windowContext image:image metadata:metadata recipientName:self.recipientName saveCapturedMedia:_saveCapturedMedia saveEditedPhotos:_saveEditedPhotos];
|
||||
controller.allowCaptions = self.allowCaptions;
|
||||
controller.shouldStoreAssets = self.shouldStoreCapturedAssets;
|
||||
controller.suggestionContext = self.suggestionContext;
|
||||
controller.hasTimer = self.hasTimer;
|
||||
controller.hasSilentPosting = self.hasSilentPosting;
|
||||
controller.hasSchedule = self.hasSchedule;
|
||||
|
||||
__weak TGCameraPhotoPreviewController *weakController = controller;
|
||||
controller.beginTransitionIn = ^CGRect
|
||||
{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return CGRectZero;
|
||||
|
||||
strongSelf->_previewView.hidden = true;
|
||||
|
||||
return strongSelf->_previewView.frame;
|
||||
};
|
||||
|
||||
controller.finishedTransitionIn = ^
|
||||
{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
if (strongSelf != nil)
|
||||
[strongSelf->_camera stopCaptureForPause:true completion:nil];
|
||||
};
|
||||
|
||||
controller.beginTransitionOut = ^CGRect(CGRect referenceFrame)
|
||||
{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return CGRectZero;
|
||||
|
||||
[strongSelf->_camera startCaptureForResume:true completion:nil];
|
||||
|
||||
return [strongSelf transitionBackFromResultControllerWithReferenceFrame:referenceFrame];
|
||||
};
|
||||
|
||||
controller.retakePressed = ^
|
||||
{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
[[[LegacyComponentsGlobals provider] applicationInstance] setIdleTimerDisabled:true];
|
||||
};
|
||||
|
||||
controller.sendPressed = ^(TGOverlayController *controller, UIImage *resultImage, NSString *caption, NSArray *entities, NSArray *stickers, NSNumber *timer)
|
||||
{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf.finishedWithPhoto != nil)
|
||||
strongSelf.finishedWithPhoto(controller, resultImage, caption, entities, stickers, timer);
|
||||
|
||||
if (strongSelf->_shortcut)
|
||||
return;
|
||||
|
||||
__strong TGOverlayController *strongController = weakController;
|
||||
if (strongController != nil)
|
||||
[strongSelf _dismissTransitionForResultController:strongController];
|
||||
};
|
||||
|
||||
overlayController = controller;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (windowManager != nil)
|
||||
{
|
||||
@ -2375,6 +2316,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
|
||||
case PGCameraModeSquarePhoto:
|
||||
case PGCameraModeSquareVideo:
|
||||
case PGCameraModeSquareSwing:
|
||||
{
|
||||
CGRect rect = [self _cameraPreviewFrameForScreenSize:screenSize mode:PGCameraModePhoto];
|
||||
CGFloat topOffset = CGRectGetMidY(rect) - rect.size.width / 2;
|
||||
@ -2406,7 +2348,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == PGCameraModeSquarePhoto || mode == PGCameraModeSquareVideo)
|
||||
if (mode == PGCameraModeSquarePhoto || mode == PGCameraModeSquareVideo || mode == PGCameraModeSquareSwing)
|
||||
return CGRectMake(0, (screenSize.height - screenSize.width) / 2, screenSize.width, screenSize.width);
|
||||
|
||||
return CGRectMake(0, 0, screenSize.width, screenSize.height);
|
||||
|
||||
@ -50,17 +50,17 @@
|
||||
break;
|
||||
|
||||
case PGCameraModeVideo:
|
||||
case PGCameraModeSquareVideo:
|
||||
{
|
||||
[_shutterButton setButtonMode:TGCameraShutterButtonVideoMode animated:true];
|
||||
[_timecodeView setHidden:false animated:true];
|
||||
}
|
||||
break;
|
||||
|
||||
case PGCameraModeSquareVideo:
|
||||
case PGCameraModeSquareSwing:
|
||||
{
|
||||
[_shutterButton setButtonMode:TGCameraShutterButtonVideoMode animated:true];
|
||||
[_timecodeView setHidden:true animated:true];
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
||||
|
||||
@interface TGCameraModeControl ()
|
||||
{
|
||||
UIImageView *_dotView;
|
||||
UIControl *_wrapperView;
|
||||
|
||||
CGFloat _kerning;
|
||||
@ -27,24 +26,6 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil)
|
||||
{
|
||||
static UIImage *dotImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(6, 6), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextSetFillColorWithColor(context, [TGCameraInterfaceAssets accentColor].CGColor);
|
||||
CGContextFillEllipseInRect(context, CGRectMake(0, 0, 6, 6));
|
||||
|
||||
dotImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
});
|
||||
|
||||
_dotView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 6, 6)];
|
||||
_dotView.image = dotImage;
|
||||
//[self addSubview:_dotView];
|
||||
|
||||
if (frame.size.width > frame.size.height)
|
||||
_kerning = 3.5f;
|
||||
else
|
||||
@ -64,7 +45,8 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
||||
_buttons = @
|
||||
[
|
||||
[self _createButtonForMode:PGCameraModeSquareVideo title:TGLocalized(@"Camera.VideoMode")],
|
||||
[self _createButtonForMode:PGCameraModePhoto title:TGLocalized(@"Camera.PhotoMode")]
|
||||
[self _createButtonForMode:PGCameraModePhoto title:TGLocalized(@"Camera.PhotoMode")],
|
||||
[self _createButtonForMode:PGCameraModeSquareSwing title:@"SWING"]
|
||||
];
|
||||
} else {
|
||||
_buttons = @
|
||||
@ -119,7 +101,6 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
||||
|
||||
+ (CGFloat)_buttonHorizontalSpacing
|
||||
{
|
||||
//return 22;
|
||||
return 19;
|
||||
}
|
||||
|
||||
@ -282,14 +263,7 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (self.frame.size.width > self.frame.size.height)
|
||||
{
|
||||
_dotView.frame = CGRectMake((self.frame.size.width - _dotView.frame.size.width) / 2, self.frame.size.height / 2 - 12, _dotView.frame.size.width, _dotView.frame.size.height);
|
||||
_maskLayer.frame = CGRectMake(0, 0, _maskView.frame.size.width, _maskView.frame.size.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dotView.frame = CGRectMake(13, (self.frame.size.height - _dotView.frame.size.height) / 2, _dotView.frame.size.width, _dotView.frame.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1374,7 +1374,7 @@
|
||||
|
||||
@implementation TGMediaAssetsPallete
|
||||
|
||||
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage maybeAccentColor:(UIColor *)maybeAccentColor
|
||||
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage doneIconImage:(UIImage *)doneIconImage maybeAccentColor:(UIColor *)maybeAccentColor
|
||||
{
|
||||
TGMediaAssetsPallete *pallete = [[TGMediaAssetsPallete alloc] init];
|
||||
pallete->_isDark = dark;
|
||||
@ -1390,6 +1390,7 @@
|
||||
pallete->_badge = badge;
|
||||
pallete->_badgeTextColor = badgeTextColor;
|
||||
pallete->_sendIconImage = sendIconImage;
|
||||
pallete->_doneIconImage = doneIconImage;
|
||||
pallete->_maybeAccentColor = maybeAccentColor;
|
||||
return pallete;
|
||||
}
|
||||
|
||||
@ -441,7 +441,7 @@
|
||||
{
|
||||
if (editableItem.isVideo) {
|
||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||
} else {
|
||||
|
||||
@ -94,6 +94,7 @@
|
||||
{
|
||||
}];
|
||||
|
||||
TGPhotoEditorController *controller = _controller;
|
||||
void (^imageReady)(void) = self.imageReady;
|
||||
_toTransitionView = [[TGImageView alloc] initWithFrame:fromTransitionFrame];
|
||||
[_toTransitionView setSignal:[[[self.referenceScreenImageSignal() deliverOn:[SQueue mainQueue]] filter:^bool(id result)
|
||||
@ -101,7 +102,7 @@
|
||||
return [result isKindOfClass:[UIImage class]];
|
||||
}] onNext:^(UIImage *next)
|
||||
{
|
||||
[_controller _setScreenImage:next];
|
||||
[controller _setScreenImage:next];
|
||||
if (imageReady != nil)
|
||||
imageReady();
|
||||
}]];
|
||||
|
||||
@ -577,7 +577,7 @@
|
||||
{
|
||||
if (editableItem.isVideo) {
|
||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||
} else {
|
||||
|
||||
@ -15,11 +15,12 @@
|
||||
@property (nonatomic, assign) NSTimeInterval trimStartValue;
|
||||
@property (nonatomic, assign) NSTimeInterval trimEndValue;
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval dotValue;
|
||||
@property (nonatomic, assign) bool hasDotPicker;
|
||||
- (void)setDotVideoView:(UIView *)dotVideoView;
|
||||
- (void)setDotImage:(UIImage *)dotImage;
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval maximumLength;
|
||||
|
||||
|
||||
@property (nonatomic, assign) bool disableZoom;
|
||||
@property (nonatomic, assign) bool disableTimeDisplay;
|
||||
|
||||
|
||||
@ -39,7 +39,10 @@ typedef enum
|
||||
UIView *_rightCurtainView;
|
||||
UIControl *_scrubberHandle;
|
||||
|
||||
UIImageView *_dotView;
|
||||
UIControl *_dotHandle;
|
||||
UIImageView *_dotImageView;
|
||||
__weak UIView *_dotVideoView;
|
||||
UIImageView *_dotFrameView;
|
||||
|
||||
UIPanGestureRecognizer *_panGestureRecognizer;
|
||||
UILongPressGestureRecognizer *_pressGestureRecognizer;
|
||||
@ -126,11 +129,6 @@ typedef enum
|
||||
_rightCurtainView.backgroundColor = [[TGPhotoEditorInterfaceAssets toolbarBackgroundColor] colorWithAlphaComponent:0.8f];
|
||||
[_wrapperView addSubview:_rightCurtainView];
|
||||
|
||||
_dotView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 8, 8)];
|
||||
_dotView.image = TGCircleImage(8.0, [TGPhotoEditorInterfaceAssets accentColor]);
|
||||
_dotView.hidden = true;
|
||||
[self addSubview:_dotView];
|
||||
|
||||
__weak TGMediaPickerGalleryVideoScrubber *weakSelf = self;
|
||||
_trimView = [[TGMediaPickerGalleryVideoTrimView alloc] initWithFrame:CGRectZero];
|
||||
_trimView.exclusiveTouch = true;
|
||||
@ -158,7 +156,11 @@ typedef enum
|
||||
|
||||
[strongSelf->_trimView setTrimming:true animated:true];
|
||||
|
||||
if (strongSelf->_hasDotPicker) {
|
||||
[strongSelf setDotHandleHidden:true animated:false];
|
||||
} else {
|
||||
[strongSelf setScrubberHandleHidden:true animated:false];
|
||||
}
|
||||
};
|
||||
_trimView.didEndEditing = ^
|
||||
{
|
||||
@ -206,7 +208,11 @@ typedef enum
|
||||
|
||||
[strongSelf->_trimView setTrimming:isTrimmed animated:true];
|
||||
|
||||
if (strongSelf->_hasDotPicker) {
|
||||
[strongSelf setDotHandleHidden:false animated:true];
|
||||
} else {
|
||||
[strongSelf setScrubberHandleHidden:false animated:true];
|
||||
}
|
||||
|
||||
[strongSelf cancelZoomIn];
|
||||
if (strongSelf->_zoomedIn)
|
||||
@ -260,8 +266,13 @@ typedef enum
|
||||
strongSelf->_trimStartValue = trimStartPosition;
|
||||
strongSelf->_trimEndValue = trimEndPosition;
|
||||
|
||||
[strongSelf setValue:strongSelf->_trimStartValue];
|
||||
|
||||
if (strongSelf->_hasDotPicker) {
|
||||
if (strongSelf->_value < trimStartPosition) {
|
||||
strongSelf->_value = trimStartPosition;
|
||||
}
|
||||
} else {
|
||||
[strongSelf setValue:trimStartPosition];
|
||||
}
|
||||
UIView *handle = strongSelf->_scrubberHandle;
|
||||
handle.center = CGPointMake(trimView.frame.origin.x + 12 + handle.frame.size.width / 2, handle.center.y);
|
||||
|
||||
@ -323,7 +334,13 @@ typedef enum
|
||||
strongSelf->_trimStartValue = trimStartPosition;
|
||||
strongSelf->_trimEndValue = trimEndPosition;
|
||||
|
||||
[strongSelf setValue:strongSelf->_trimEndValue];
|
||||
if (strongSelf->_hasDotPicker) {
|
||||
if (strongSelf->_value > trimEndPosition) {
|
||||
strongSelf->_value = trimEndPosition;
|
||||
}
|
||||
} else {
|
||||
[strongSelf setValue:trimEndPosition];
|
||||
}
|
||||
|
||||
UIView *handle = strongSelf->_scrubberHandle;
|
||||
handle.center = CGPointMake(CGRectGetMaxX(trimView.frame) - 12 - handle.frame.size.width / 2, handle.center.y);
|
||||
@ -341,13 +358,44 @@ typedef enum
|
||||
};
|
||||
[_wrapperView addSubview:_trimView];
|
||||
|
||||
_dotHandle = [[UIControl alloc] initWithFrame:CGRectMake(0, -4.0f, 26.0f, 44.0f)];
|
||||
_dotHandle.hitTestEdgeInsets = UIEdgeInsetsMake(-5, -12, -5, -12);
|
||||
_dotHandle.hidden = true;
|
||||
[_wrapperView addSubview:_dotHandle];
|
||||
|
||||
static UIImage *dotFrameImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(_dotHandle.frame.size.width, _dotHandle.frame.size.height), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
|
||||
CGContextSetLineWidth(context, 3.0);
|
||||
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(1.5f, 1.5f, _dotHandle.frame.size.width - 3.0, _dotHandle.frame.size.height - 3.0f) cornerRadius:4.0f];
|
||||
CGContextAddPath(context, path.CGPath);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
dotFrameImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
});
|
||||
|
||||
_dotImageView = [[UIImageView alloc] initWithFrame:CGRectInset(_dotHandle.bounds, 2.0, 2.0)];
|
||||
_dotImageView.clipsToBounds = true;
|
||||
_dotImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[_dotHandle addSubview:_dotImageView];
|
||||
|
||||
_dotFrameView = [[UIImageView alloc] initWithFrame:_dotHandle.bounds];
|
||||
_dotFrameView.image = dotFrameImage;
|
||||
[_dotHandle addSubview:_dotFrameView];
|
||||
|
||||
_scrubberHandle = [[UIControl alloc] initWithFrame:CGRectMake(0, -4.0f, 5.0f, 44.0f)];
|
||||
_scrubberHandle.hitTestEdgeInsets = UIEdgeInsetsMake(-5, -12, -5, -12);
|
||||
[_wrapperView addSubview:_scrubberHandle];
|
||||
|
||||
static UIImage *handleViewImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
static dispatch_once_t onceToken2;
|
||||
dispatch_once(&onceToken2, ^
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(_scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
@ -373,6 +421,7 @@ typedef enum
|
||||
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
||||
_panGestureRecognizer.delegate = self;
|
||||
[_scrubberHandle addGestureRecognizer:_panGestureRecognizer];
|
||||
[_dotHandle addGestureRecognizer:_panGestureRecognizer];
|
||||
|
||||
_arrowView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PhotoPickerArrow")];
|
||||
_arrowView.alpha = 0.45f;
|
||||
@ -400,6 +449,22 @@ typedef enum
|
||||
[self _layoutRecipientLabel];
|
||||
}
|
||||
|
||||
- (void)setHasDotPicker:(bool)hasDotPicker {
|
||||
_hasDotPicker = hasDotPicker;
|
||||
_dotHandle.hidden = !hasDotPicker;
|
||||
_scrubberHandle.hidden = true;
|
||||
}
|
||||
|
||||
- (void)setDotVideoView:(UIView *)dotVideoView {
|
||||
_dotVideoView = dotVideoView;
|
||||
_dotVideoView.frame = CGRectInset(_dotHandle.bounds, 2.0, 2.0);
|
||||
[_dotHandle insertSubview:dotVideoView belowSubview:_dotFrameView];
|
||||
}
|
||||
|
||||
- (void)setDotImage:(UIImage *)dotImage {
|
||||
_dotImageView.image = dotImage;
|
||||
}
|
||||
|
||||
- (bool)zoomAvailable
|
||||
{
|
||||
if (_disableZoom || _zoomedIn || _preparingToZoomIn || _summaryTimestamps.count == 0)
|
||||
@ -886,13 +951,18 @@ typedef enum
|
||||
CGPoint point = [self _scrubberPositionForPosition:_value duration:_duration zoomedIn:zoomedIn];
|
||||
CGRect frame = CGRectMake(CGFloor(point.x) - _scrubberHandle.frame.size.width / 2, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
||||
|
||||
CGPoint dotPoint = [self _dotPositionForPosition:_value duration:_duration];
|
||||
CGRect dotFrame = CGRectMake(CGFloor(dotPoint.x) - _dotHandle.frame.size.width / 2, _dotHandle.frame.origin.y, _dotHandle.frame.size.width, _dotHandle.frame.size.height);
|
||||
|
||||
if (_trimStartValue > DBL_EPSILON && fabs(_value - _trimStartValue) < 0.01)
|
||||
{
|
||||
frame = CGRectMake(_trimView.frame.origin.x + [self _scrubbingRectZoomedIn:zoomedIn].origin.x, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
||||
dotFrame = CGRectMake(_trimView.frame.origin.x + [self _scrubbingRectZoomedIn:false].origin.x, _dotHandle.frame.origin.y, _dotHandle.frame.size.width, _dotHandle.frame.size.height);
|
||||
}
|
||||
else if (fabs(_value - _trimEndValue) < 0.01)
|
||||
{
|
||||
frame = CGRectMake(_trimView.frame.origin.x + _trimView.frame.size.width - [self _scrubbingRectZoomedIn:zoomedIn].origin.x - _scrubberHandle.frame.size.width, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
||||
dotFrame = CGRectMake(_trimView.frame.origin.x + _trimView.frame.size.width - [self _scrubbingRectZoomedIn:false].origin.x - _dotHandle.frame.size.width, _dotHandle.frame.origin.y, _dotHandle.frame.size.width, _dotHandle.frame.size.height);
|
||||
}
|
||||
|
||||
if (_isPlaying)
|
||||
@ -921,6 +991,8 @@ typedef enum
|
||||
[self removeHandleAnimation];
|
||||
_scrubberHandle.frame = frame;
|
||||
}
|
||||
|
||||
_dotHandle.frame = dotFrame;
|
||||
}
|
||||
|
||||
- (void)addHandleAnimationFromFrame:(CGRect)fromFrame toFrame:(CGRect)toFrame duration:(NSTimeInterval)duration
|
||||
@ -1030,6 +1102,8 @@ typedef enum
|
||||
CGPoint translation = [gestureRecognizer translationInView:self];
|
||||
[gestureRecognizer setTranslation:CGPointZero inView:self];
|
||||
|
||||
UIView *handle = gestureRecognizer.view;
|
||||
|
||||
switch (gestureRecognizer.state)
|
||||
{
|
||||
case UIGestureRecognizerStateBegan:
|
||||
@ -1059,23 +1133,23 @@ typedef enum
|
||||
|
||||
CGRect scrubbingRect = [self _scrubbingRect];
|
||||
CGRect normalScrubbingRect = [self _scrubbingRectZoomedIn:false];
|
||||
CGFloat minPosition = scrubbingRect.origin.x + _scrubberHandle.frame.size.width / 2;
|
||||
CGFloat maxPosition = scrubbingRect.origin.x + scrubbingRect.size.width - _scrubberHandle.frame.size.width / 2;
|
||||
CGFloat minPosition = scrubbingRect.origin.x + handle.frame.size.width / 2;
|
||||
CGFloat maxPosition = scrubbingRect.origin.x + scrubbingRect.size.width - handle.frame.size.width / 2;
|
||||
if (self.allowsTrimming)
|
||||
{
|
||||
minPosition = MAX(minPosition, _trimView.frame.origin.x + normalScrubbingRect.origin.x + _scrubberHandle.frame.size.width / 2);
|
||||
maxPosition = MIN(maxPosition, CGRectGetMaxX(_trimView.frame) - normalScrubbingRect.origin.x - _scrubberHandle.frame.size.width / 2);
|
||||
minPosition = MAX(minPosition, _trimView.frame.origin.x + normalScrubbingRect.origin.x + handle.frame.size.width / 2);
|
||||
maxPosition = MIN(maxPosition, CGRectGetMaxX(_trimView.frame) - normalScrubbingRect.origin.x - handle.frame.size.width / 2);
|
||||
}
|
||||
|
||||
_scrubberHandle.center = CGPointMake(MIN(MAX(_scrubberHandle.center.x + translation.x, minPosition), maxPosition), _scrubberHandle.center.y);
|
||||
handle.center = CGPointMake(MIN(MAX(handle.center.x + translation.x, minPosition), maxPosition), handle.center.y);
|
||||
|
||||
NSTimeInterval position = [self _positionForScrubberPosition:_scrubberHandle.center duration:_duration];
|
||||
NSTimeInterval position = [self _positionForScrubberPosition:handle.center duration:_duration];
|
||||
|
||||
if (self.allowsTrimming)
|
||||
{
|
||||
if (ABS(_scrubberHandle.center.x - minPosition) < FLT_EPSILON)
|
||||
if (ABS(handle.center.x - minPosition) < FLT_EPSILON)
|
||||
position = _trimStartValue;
|
||||
else if (ABS(_scrubberHandle.center.x - maxPosition) < FLT_EPSILON)
|
||||
else if (ABS(handle.center.x - maxPosition) < FLT_EPSILON)
|
||||
position = _trimEndValue;
|
||||
}
|
||||
|
||||
@ -1105,8 +1179,6 @@ typedef enum
|
||||
|
||||
_scrubbing = false;
|
||||
|
||||
[self setDotValue:_value];
|
||||
|
||||
id<TGMediaPickerGalleryVideoScrubberDelegate> delegate = self.delegate;
|
||||
if ([delegate respondsToSelector:@selector(videoScrubberDidEndScrubbing:)])
|
||||
[delegate videoScrubberDidEndScrubbing:self];
|
||||
@ -1145,6 +1217,27 @@ typedef enum
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDotHandleHidden:(bool)hidden animated:(bool)animated
|
||||
{
|
||||
if (animated)
|
||||
{
|
||||
_dotHandle.hidden = false;
|
||||
[UIView animateWithDuration:0.25f animations:^
|
||||
{
|
||||
_dotHandle.alpha = hidden ? 0.0f : 1.0f;
|
||||
} completion:^(BOOL finished)
|
||||
{
|
||||
if (finished)
|
||||
_dotHandle.hidden = hidden;
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
_dotHandle.hidden = hidden;
|
||||
_dotHandle.alpha = hidden ? 0.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPoint)_scrubberPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
|
||||
{
|
||||
return [self _scrubberPositionForPosition:position duration:duration zoomedIn:_zoomedIn];
|
||||
@ -1202,25 +1295,17 @@ typedef enum
|
||||
|
||||
#pragma mark - Dot
|
||||
|
||||
- (void)setDotValue:(NSTimeInterval)dotValue
|
||||
- (CGPoint)_dotPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
|
||||
{
|
||||
_dotValue = dotValue;
|
||||
CGRect scrubbingRect = [self _scrubbingRectZoomedIn:false];
|
||||
|
||||
if (dotValue > FLT_EPSILON) {
|
||||
_dotView.hidden = false;
|
||||
|
||||
CGPoint point = [self _scrubberPositionForPosition:dotValue duration:_duration zoomedIn:false];
|
||||
_dotView.frame = CGRectMake(_wrapperView.frame.origin.x + point.x - _dotView.frame.size.width / 2.0, 8.0f, _dotView.frame.size.width, _dotView.frame.size.height);
|
||||
|
||||
_dotView.alpha = 0.0f;
|
||||
_dotView.transform = CGAffineTransformMakeScale(0.25, 0.25);
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
_dotView.alpha = 1.0;
|
||||
_dotView.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
} else {
|
||||
_dotView.hidden = true;
|
||||
if (duration < FLT_EPSILON)
|
||||
{
|
||||
position = 0.0;
|
||||
duration = 1.0;
|
||||
}
|
||||
|
||||
return CGPointMake(_dotHandle.frame.size.width / 2 + scrubbingRect.origin.x + (CGFloat)(position / duration) * (scrubbingRect.size.width - _dotHandle.frame.size.width), CGRectGetMidY([self _scrubbingRect]));
|
||||
}
|
||||
|
||||
#pragma mark - Trimming
|
||||
|
||||
@ -125,7 +125,7 @@
|
||||
|
||||
CGSize dimensions = [avAsset tracksWithMediaType:AVMediaTypeVideo].firstObject.naturalSize;
|
||||
TGMediaVideoConversionPreset preset = adjustments.sendAsGif ? TGMediaVideoConversionPresetAnimation : [self presetFromAdjustments:adjustments];
|
||||
if (!CGSizeEqualToSize(dimensions, CGSizeZero) && preset != TGMediaVideoConversionPresetAnimation && preset != TGMediaVideoConversionPresetVideoMessage)
|
||||
if (!CGSizeEqualToSize(dimensions, CGSizeZero) && preset != TGMediaVideoConversionPresetAnimation && preset != TGMediaVideoConversionPresetVideoMessage && preset != TGMediaVideoConversionPresetProfile)
|
||||
{
|
||||
TGMediaVideoConversionPreset bestPreset = [self bestAvailablePresetForDimensions:dimensions];
|
||||
if (preset > bestPreset)
|
||||
@ -344,8 +344,6 @@
|
||||
if (TGOrientationIsSideward(adjustments.cropOrientation, NULL))
|
||||
outputDimensions = CGSizeMake(outputDimensions.height, outputDimensions.width);
|
||||
|
||||
CMTimeRange instructionTimeRange = CMTimeRangeMake(kCMTimeZero, timeRange.duration);
|
||||
|
||||
AVMutableCompositionTrack *compositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
if (adjustments.videoStartValue > 0.0 && adjustments.videoStartValue > adjustments.trimStartValue) {
|
||||
NSTimeInterval trimEndValue = adjustments.trimEndValue > adjustments.trimStartValue ? adjustments.trimEndValue : CMTimeGetSeconds(videoTrack.timeRange.duration);
|
||||
@ -1340,7 +1338,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
||||
return 300;
|
||||
|
||||
case TGMediaVideoConversionPresetProfile:
|
||||
return 1000;
|
||||
return 1800;
|
||||
|
||||
default:
|
||||
return 900;
|
||||
|
||||
@ -172,8 +172,11 @@
|
||||
if ([_manager managesWindow]) {
|
||||
_contentController = contentController;
|
||||
__weak TGOverlayControllerWindow *weakSelf = self;
|
||||
__weak TGViewController *weakParentController = parentController;
|
||||
contentController.customDismissBlock = ^{
|
||||
__strong TGOverlayControllerWindow *strongSelf = weakSelf;
|
||||
__strong TGViewController *strongParentController = weakParentController;
|
||||
[strongParentController.associatedWindowStack removeObject:strongSelf];
|
||||
[manager setHidden:true window:strongSelf];
|
||||
};
|
||||
[_manager bindController:contentController];
|
||||
|
||||
@ -277,6 +277,8 @@ const CGFloat TGPhotoAvatarCropButtonsWrapperSize = 61.0f;
|
||||
{
|
||||
[_cropView hideImageForCustomTransition];
|
||||
[_cropView animateTransitionOutSwitching:false];
|
||||
[_cropView invalidateVideoView];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^
|
||||
{
|
||||
_buttonsWrapperView.alpha = 0.0f;
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#import "TGPhotoEditorSparseView.h"
|
||||
|
||||
#import "TGMediaPickerGalleryVideoScrubber.h"
|
||||
#import "TGModernGalleryVideoView.h"
|
||||
|
||||
const CGFloat TGPhotoAvatarPreviewPanelSize = 96.0f;
|
||||
const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanelSize + 40.0f;
|
||||
@ -36,6 +37,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
CGFloat _currentDiameter;
|
||||
|
||||
TGMediaPickerGalleryVideoScrubber *_scrubberView;
|
||||
TGModernGalleryVideoView *_dotVideoView;
|
||||
UILabel *_coverLabel;
|
||||
bool _wasPlayingBeforeScrubbing;
|
||||
bool _requestingThumbnails;
|
||||
@ -139,11 +141,13 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
_scrubberView.allowsTrimming = true;
|
||||
_scrubberView.allowsTrimming = self.item.originalDuration >= TGVideoEditMinimumTrimmableDuration;
|
||||
_scrubberView.hasDotPicker = true;
|
||||
_scrubberView.disableZoom = true;
|
||||
_scrubberView.disableTimeDisplay = true;
|
||||
_scrubberView.trimStartValue = 0.0;
|
||||
_scrubberView.trimEndValue = self.item.originalDuration;
|
||||
_scrubberView.trimEndValue = MIN(10.0, self.item.originalDuration);
|
||||
_scrubberView.maximumLength = 10.0;
|
||||
[_scrubberView reloadData];
|
||||
[_scrubberView resetToStart];
|
||||
}
|
||||
@ -169,11 +173,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
_landscapeToolsWrapperView.alpha = 1.0f;
|
||||
}];
|
||||
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
switch (orientation)
|
||||
switch (self.effectiveOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
{
|
||||
@ -217,11 +217,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
[_videoAreaView.superview bringSubviewToFront:_videoAreaView];
|
||||
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
switch (orientation)
|
||||
switch (self.effectiveOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
{
|
||||
@ -383,11 +379,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
||||
{
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
||||
CGRect sourceFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
|
||||
@ -397,16 +389,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||
{
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
|
||||
@ -441,11 +424,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
||||
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
||||
screenEdges.top += safeAreaInset.top;
|
||||
screenEdges.left += safeAreaInset.left;
|
||||
@ -517,10 +496,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
- (void)updatePreviewView
|
||||
{
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([self inFormSheet] || TGIsPad())
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
|
||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||
@ -529,11 +504,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
if (_dismissing || previewView.superview != self.view)
|
||||
return;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size);
|
||||
previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
|
||||
@ -588,12 +559,12 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
- (TGPhotoEditorTab)availableTabs
|
||||
{
|
||||
return TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
|
||||
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
|
||||
}
|
||||
|
||||
- (TGPhotoEditorTab)activeTab
|
||||
{
|
||||
return TGPhotoEditorCropTab;
|
||||
return TGPhotoEditorNoneTab;
|
||||
}
|
||||
|
||||
- (TGPhotoEditorTab)highlightedTabs
|
||||
@ -681,7 +652,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
_wasPlayingBeforeScrubbing = true;
|
||||
self.controlVideoPlayback(false);
|
||||
|
||||
_scrubberView.dotValue = 0.0;
|
||||
_dotVideoView.hidden = false;
|
||||
|
||||
_coverLabel.alpha = 1.0f;
|
||||
|
||||
@ -694,6 +665,19 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
- (void)videoScrubberDidEndScrubbing:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber
|
||||
{
|
||||
AVPlayer *player = ((TGPhotoEditorController *)self.parentViewController).player;
|
||||
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:player.currentItem.asset];
|
||||
generator.appliesPreferredTrackTransform = true;
|
||||
generator.maximumSize = CGSizeMake(128.0f, 128.0f);
|
||||
generator.requestedTimeToleranceAfter = kCMTimeZero;
|
||||
generator.requestedTimeToleranceBefore = kCMTimeZero;
|
||||
CGImageRef imageRef = [generator copyCGImageAtTime:player.currentItem.currentTime actualTime:NULL error:NULL];
|
||||
UIImage *thumbnailImage = [[UIImage alloc] initWithCGImage:imageRef];
|
||||
CGImageRelease(imageRef);
|
||||
|
||||
[_scrubberView setDotImage:thumbnailImage];
|
||||
_dotVideoView.hidden = true;
|
||||
|
||||
[UIView animateWithDuration:0.12 animations:^{
|
||||
_flashView.alpha = 1.0f;
|
||||
} completion:^(BOOL finished) {
|
||||
@ -791,18 +775,30 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
id<TGMediaEditAdjustments> adjustments = [self.photoEditor exportAdjustments];
|
||||
|
||||
NSArray *cachedThumbnails = ((TGPhotoEditorController *)self.parentViewController).cachedVideoThumbnails;
|
||||
|
||||
SSignal *thumbnailsSignal = nil;
|
||||
if ([self.item isKindOfClass:[TGMediaAsset class]])
|
||||
if (cachedThumbnails.count > 0) {
|
||||
thumbnailsSignal = [SSignal single:cachedThumbnails];
|
||||
} else if ([self.item isKindOfClass:[TGMediaAsset class]]) {
|
||||
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:(TGMediaAsset *)self.item size:size timestamps:timestamps];
|
||||
else if ([self.item isKindOfClass:[TGCameraCapturedVideo class]])
|
||||
} else if ([self.item isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
thumbnailsSignal = [((TGCameraCapturedVideo *)self.item).avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
|
||||
return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
|
||||
}];
|
||||
}
|
||||
|
||||
_requestingThumbnails = true;
|
||||
|
||||
__weak TGPhotoAvatarPreviewController *weakSelf = self;
|
||||
[_thumbnailsDisposable setDisposable:[[[thumbnailsSignal map:^NSArray *(NSArray *images) {
|
||||
[_thumbnailsDisposable setDisposable:[[[[thumbnailsSignal onNext:^(NSArray *images) {
|
||||
__strong TGPhotoAvatarPreviewController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
TGDispatchOnMainThread(^{
|
||||
((TGPhotoEditorController *)strongSelf.parentViewController).cachedVideoThumbnails = images;
|
||||
});
|
||||
}] map:^NSArray *(NSArray *images) {
|
||||
if (adjustments.toolsApplied) {
|
||||
NSMutableArray *editedImages = [[NSMutableArray alloc] init];
|
||||
PGPhotoEditor *editor = [[PGPhotoEditor alloc] initWithOriginalSize:adjustments.originalSize adjustments:adjustments forVideo:false enableStickers:true];
|
||||
@ -868,16 +864,22 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
- (void)setScrubberPosition:(NSTimeInterval)position reset:(bool)reset
|
||||
{
|
||||
[_scrubberView setValue:_scrubberView.trimStartValue resetPosition:reset];
|
||||
|
||||
}
|
||||
|
||||
- (void)setScrubberPlaying:(bool)value
|
||||
{
|
||||
[_scrubberView setIsPlaying:value];
|
||||
if (_dotVideoView == nil) {
|
||||
AVPlayer *player = ((TGPhotoEditorController *)self.parentViewController).player;
|
||||
_dotVideoView = [[TGModernGalleryVideoView alloc] initWithFrame:CGRectMake(0.0, 0.0, 27.0, 44.0) player:player];
|
||||
_dotVideoView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
_dotVideoView.hidden = true;
|
||||
[_scrubberView setDotVideoView:_dotVideoView];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSTimeInterval)coverPosition {
|
||||
return _scrubberView.dotValue;
|
||||
return _scrubberView.value;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -37,9 +37,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
CGFloat _autoRotationAngle;
|
||||
|
||||
UIView *_buttonsWrapperView;
|
||||
TGModernButton *_rotateButton;
|
||||
TGModernButton *_mirrorButton;
|
||||
TGModernButton *_aspectRatioButton;
|
||||
TGModernButton *_resetButton;
|
||||
|
||||
TGPhotoCropView *_cropView;
|
||||
@ -107,7 +104,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
[self.view addSubview:_wrapperView];
|
||||
|
||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||
_cropView = [[TGPhotoCropView alloc] initWithOriginalSize:photoEditor.originalSize hasArbitraryRotation:true];
|
||||
_cropView = [[TGPhotoCropView alloc] initWithOriginalSize:photoEditor.originalSize hasArbitraryRotation:!_forVideo];
|
||||
[_cropView setCropRect:photoEditor.cropRect];
|
||||
[_cropView setCropOrientation:photoEditor.cropOrientation];
|
||||
[_cropView setRotation:photoEditor.cropRotation];
|
||||
@ -153,31 +150,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
_buttonsWrapperView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[_wrapperView addSubview:_buttonsWrapperView];
|
||||
|
||||
_rotateButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
|
||||
_rotateButton.exclusiveTouch = true;
|
||||
_rotateButton.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
|
||||
[_rotateButton addTarget:self action:@selector(rotate) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_rotateButton setImage:TGComponentsImageNamed(@"PhotoEditorRotateIcon") forState:UIControlStateNormal];
|
||||
//[_buttonsWrapperView addSubview:_rotateButton];
|
||||
|
||||
_mirrorButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
|
||||
_mirrorButton.exclusiveTouch = true;
|
||||
_mirrorButton.imageEdgeInsets = UIEdgeInsetsMake(4.0f, 0.0f, 0.0f, 0.0f);
|
||||
_mirrorButton.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
|
||||
[_mirrorButton addTarget:self action:@selector(mirror) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_mirrorButton setImage:TGComponentsImageNamed(@"PhotoEditorMirrorIcon") forState:UIControlStateNormal];
|
||||
//[_buttonsWrapperView addSubview:_mirrorButton];
|
||||
|
||||
_aspectRatioButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
|
||||
_aspectRatioButton.exclusiveTouch = true;
|
||||
_aspectRatioButton.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
|
||||
[_aspectRatioButton addTarget:self action:@selector(aspectRatioButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
UIImage *aspectRatioHighlightedImage = TGTintedImage(TGComponentsImageNamed(@"PhotoEditorAspectRatioIcon"), [TGPhotoEditorInterfaceAssets accentColor]);
|
||||
[_aspectRatioButton setImage:TGComponentsImageNamed(@"PhotoEditorAspectRatioIcon") forState:UIControlStateNormal];
|
||||
[_aspectRatioButton setImage:aspectRatioHighlightedImage forState:UIControlStateSelected];
|
||||
[_aspectRatioButton setImage:aspectRatioHighlightedImage forState:UIControlStateSelected | UIControlStateHighlighted];
|
||||
//[_buttonsWrapperView addSubview:_aspectRatioButton];
|
||||
|
||||
NSString *resetButtonTitle = TGLocalized(@"PhotoEditor.CropReset");
|
||||
_resetButton = [[TGModernButton alloc] init];
|
||||
_resetButton.exclusiveTouch = true;
|
||||
@ -190,14 +162,10 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
_resetButton.frame = CGRectMake(0, 0, _resetButton.frame.size.width, 24);
|
||||
[_buttonsWrapperView addSubview:_resetButton];
|
||||
|
||||
if ([resetButtonTitle respondsToSelector:@selector(sizeWithAttributes:)])
|
||||
_resetButtonWidth = CGCeil([resetButtonTitle sizeWithAttributes:@{ NSFontAttributeName:TGSystemFontOfSize(13) }].width);
|
||||
else
|
||||
_resetButtonWidth = CGCeil([resetButtonTitle sizeWithFont:TGSystemFontOfSize(13)].width);
|
||||
|
||||
if (photoEditor.cropLockedAspectRatio > FLT_EPSILON)
|
||||
{
|
||||
_aspectRatioButton.selected = true;
|
||||
[_cropView setLockedAspectRatio:photoEditor.cropLockedAspectRatio performResize:false animated:false];
|
||||
}
|
||||
else if ([photoEditor hasDefaultCropping] && ABS(_autoRotationAngle) > FLT_EPSILON)
|
||||
@ -376,16 +344,11 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||
{
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoCropController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation hasArbitraryRotation:_cropView.hasArbitraryRotation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoCropController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation hasArbitraryRotation:_cropView.hasArbitraryRotation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
containerFrame = CGRectInset(containerFrame, TGPhotoCropAreaInsetSize.width, TGPhotoCropAreaInsetSize.height);
|
||||
|
||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||
@ -576,7 +539,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
if (_cropView.isAspectRatioLocked)
|
||||
{
|
||||
[_cropView unlockAspectRatio];
|
||||
_aspectRatioButton.selected = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -677,14 +639,14 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
}]];
|
||||
|
||||
[controller setItemViews:items];
|
||||
controller.sourceRect = ^CGRect
|
||||
{
|
||||
__strong TGPhotoCropController *strongSelf = weakSelf;
|
||||
if (strongSelf != nil)
|
||||
return [strongSelf.view convertRect:strongSelf->_aspectRatioButton.frame fromView:strongSelf->_aspectRatioButton.superview];
|
||||
|
||||
return CGRectZero;
|
||||
};
|
||||
// controller.sourceRect = ^CGRect
|
||||
// {
|
||||
// __strong TGPhotoCropController *strongSelf = weakSelf;
|
||||
// if (strongSelf != nil)
|
||||
// return [strongSelf.view convertRect:strongSelf->_aspectRatioButton.frame fromView:strongSelf->_aspectRatioButton.superview];
|
||||
//
|
||||
// return CGRectZero;
|
||||
// };
|
||||
[controller presentInViewController:self.parentViewController sourceView:self.view animated:true];
|
||||
}
|
||||
|
||||
@ -706,8 +668,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
}
|
||||
else
|
||||
{
|
||||
_aspectRatioButton.selected = false;
|
||||
|
||||
[_cropView resetAnimated:true];
|
||||
|
||||
if (hasAutorotationAngle)
|
||||
@ -796,8 +756,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
|
||||
- (void)updateLayout:(UIInterfaceOrientation)orientation
|
||||
{
|
||||
if ([self inFormSheet] || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
orientation = [self effectiveOrientation:orientation];
|
||||
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
|
||||
@ -823,18 +782,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
{
|
||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.left + self.toolbarLandscapeSize,
|
||||
screenEdges.top,
|
||||
TGPhotoCropButtonsWrapperSize,
|
||||
referenceSize.height);
|
||||
|
||||
_rotateButton.frame = CGRectMake(25, 10, _rotateButton.frame.size.width, _rotateButton.frame.size.height);
|
||||
_mirrorButton.frame = CGRectMake(25, 60, _mirrorButton.frame.size.width, _mirrorButton.frame.size.height);
|
||||
|
||||
_aspectRatioButton.frame = CGRectMake(25,
|
||||
_buttonsWrapperView.frame.size.height - _aspectRatioButton.frame.size.height - 10,
|
||||
_aspectRatioButton.frame.size.width,
|
||||
_aspectRatioButton.frame.size.height);
|
||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.left + self.toolbarLandscapeSize, screenEdges.top, TGPhotoCropButtonsWrapperSize, referenceSize.height);
|
||||
|
||||
_resetButton.transform = CGAffineTransformIdentity;
|
||||
_resetButton.frame = CGRectMake(0, 0, _resetButtonWidth, 24);
|
||||
@ -852,18 +800,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
|
||||
case UIInterfaceOrientationLandscapeRight:
|
||||
{
|
||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.right - self.toolbarLandscapeSize - TGPhotoCropButtonsWrapperSize,
|
||||
screenEdges.top,
|
||||
TGPhotoCropButtonsWrapperSize,
|
||||
referenceSize.height);
|
||||
|
||||
_rotateButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _rotateButton.frame.size.width - 25, 10, _rotateButton.frame.size.width, _rotateButton.frame.size.height);
|
||||
_mirrorButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _mirrorButton.frame.size.width - 25, 60, _mirrorButton.frame.size.width, _mirrorButton.frame.size.height);
|
||||
|
||||
_aspectRatioButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _aspectRatioButton.frame.size.width - 25,
|
||||
_buttonsWrapperView.frame.size.height - _aspectRatioButton.frame.size.height - 10,
|
||||
_aspectRatioButton.frame.size.width,
|
||||
_aspectRatioButton.frame.size.height);
|
||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.right - self.toolbarLandscapeSize - TGPhotoCropButtonsWrapperSize, screenEdges.top, TGPhotoCropButtonsWrapperSize, referenceSize.height);
|
||||
|
||||
_resetButton.transform = CGAffineTransformIdentity;
|
||||
_resetButton.frame = CGRectMake(0, 0, _resetButtonWidth, 24);
|
||||
@ -881,18 +818,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
||||
|
||||
default:
|
||||
{
|
||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.left,
|
||||
screenEdges.bottom - TGPhotoEditorToolbarSize - TGPhotoCropButtonsWrapperSize,
|
||||
referenceSize.width,
|
||||
TGPhotoCropButtonsWrapperSize);
|
||||
|
||||
_rotateButton.frame = CGRectMake(10, _buttonsWrapperView.frame.size.height - _rotateButton.frame.size.height - 25, _rotateButton.frame.size.width, _rotateButton.frame.size.height);
|
||||
_mirrorButton.frame = CGRectMake(60, _buttonsWrapperView.frame.size.height - _mirrorButton.frame.size.height - 25, _mirrorButton.frame.size.width, _mirrorButton.frame.size.height);
|
||||
|
||||
_aspectRatioButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _aspectRatioButton.frame.size.width - 10,
|
||||
_buttonsWrapperView.frame.size.height - _aspectRatioButton.frame.size.height - 25,
|
||||
_aspectRatioButton.frame.size.width,
|
||||
_aspectRatioButton.frame.size.height);
|
||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.left, screenEdges.bottom - TGPhotoEditorToolbarSize - TGPhotoCropButtonsWrapperSize, referenceSize.width, TGPhotoCropButtonsWrapperSize);
|
||||
|
||||
_resetButton.transform = CGAffineTransformIdentity;
|
||||
_resetButton.frame = CGRectMake((_buttonsWrapperView.frame.size.width - _resetButton.frame.size.width) / 2, 20, _resetButtonWidth, 24);
|
||||
|
||||
@ -72,12 +72,12 @@
|
||||
UIImage *_thumbnailImage;
|
||||
|
||||
AVPlayerItem *_playerItem;
|
||||
AVPlayer *_player;
|
||||
SMetaDisposable *_playerItemDisposable;
|
||||
id _playerStartedObserver;
|
||||
id _playerReachedEndObserver;
|
||||
bool _registeredKeypathObserver;
|
||||
NSTimer *_positionTimer;
|
||||
bool _scheduledVideoPlayback;
|
||||
|
||||
id<TGMediaEditAdjustments> _initialAdjustments;
|
||||
NSString *_caption;
|
||||
@ -260,14 +260,6 @@
|
||||
|
||||
|
||||
TGPhotoEditorBackButton backButton = TGPhotoEditorBackButtonCancel;
|
||||
if ([self presentedForAvatarCreation])
|
||||
{
|
||||
if ([self presentedFromCamera])
|
||||
backButton = TGPhotoEditorBackButtonCancel;
|
||||
else
|
||||
backButton = TGPhotoEditorBackButtonCancel;
|
||||
}
|
||||
|
||||
TGPhotoEditorDoneButton doneButton = TGPhotoEditorDoneButtonCheck;
|
||||
_portraitToolbarView = [[TGPhotoToolbarView alloc] initWithBackButton:backButton doneButton:doneButton solidBackground:true];
|
||||
[_portraitToolbarView setToolbarTabs:_availableTabs animated:false];
|
||||
@ -403,8 +395,11 @@
|
||||
|
||||
[signal startWithNext:^(id next)
|
||||
{
|
||||
CGFloat progress = 0.0;
|
||||
bool progressVisible = false;
|
||||
if ([next isKindOfClass:[UIImage class]]) {
|
||||
[_photoEditor setImage:(UIImage *)next forCropRect:_photoEditor.cropRect cropRotation:_photoEditor.cropRotation cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored fullSize:false];
|
||||
progress = 1.0f;
|
||||
} else if ([next isKindOfClass:[AVAsset class]]) {
|
||||
_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
|
||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||
@ -421,8 +416,21 @@
|
||||
[_previewView performTransitionInWithCompletion:^
|
||||
{
|
||||
}];
|
||||
});
|
||||
|
||||
if (_scheduledVideoPlayback) {
|
||||
_scheduledVideoPlayback = false;
|
||||
[self startVideoPlayback:true];
|
||||
}
|
||||
});
|
||||
progress = 1.0f;
|
||||
} else if ([next isKindOfClass:[NSNumber class]]) {
|
||||
progress = [next floatValue];
|
||||
progressVisible = true;
|
||||
}
|
||||
|
||||
TGDispatchOnMainThread(^{
|
||||
[self setProgressVisible:progressVisible value:progress animated:true];
|
||||
});
|
||||
|
||||
if (_ignoreDefaultPreviewViewTransitionIn)
|
||||
{
|
||||
@ -496,6 +504,11 @@
|
||||
}
|
||||
|
||||
- (void)startVideoPlayback:(bool)reset {
|
||||
if (reset && _player == nil) {
|
||||
_scheduledVideoPlayback = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
NSTimeInterval startPosition = 0.0f;
|
||||
if (_photoEditor.trimStartValue > DBL_EPSILON)
|
||||
@ -973,6 +986,9 @@
|
||||
|
||||
_switchingTab = true;
|
||||
|
||||
TGPhotoEditorBackButton backButtonType = TGPhotoEditorBackButtonCancel;
|
||||
TGPhotoEditorDoneButton doneButtonType = TGPhotoEditorDoneButtonCheck;
|
||||
|
||||
__weak TGPhotoEditorController *weakSelf = self;
|
||||
TGPhotoEditorTabController *controller = nil;
|
||||
switch (tab)
|
||||
@ -1358,6 +1374,8 @@
|
||||
[strongSelf setVideoEndTime:endTime];
|
||||
};
|
||||
controller = previewController;
|
||||
|
||||
doneButtonType = TGPhotoEditorDoneButtonDone;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1365,6 +1383,10 @@
|
||||
break;
|
||||
}
|
||||
|
||||
if (_intent == TGPhotoEditorControllerAvatarIntent && !isInitialAppearance && tab != TGPhotoEditorPreviewTab) {
|
||||
backButtonType = TGPhotoEditorBackButtonBack;
|
||||
}
|
||||
|
||||
_currentTabController = controller;
|
||||
_currentTabController.item = _item;
|
||||
_currentTabController.intent = _intent;
|
||||
@ -1382,11 +1404,11 @@
|
||||
if (currentController != nil)
|
||||
[_currentTabController viewWillAppear:true];
|
||||
|
||||
_currentTabController.view.frame = _containerView.bounds;
|
||||
|
||||
if (currentController != nil)
|
||||
[_currentTabController viewDidAppear:true];
|
||||
|
||||
_currentTabController.view.frame = _containerView.bounds;
|
||||
|
||||
_currentTabController.valuesChanged = ^
|
||||
{
|
||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||
@ -1405,6 +1427,12 @@
|
||||
[_portraitToolbarView setToolbarTabs:[_currentTabController availableTabs] animated:true];
|
||||
[_landscapeToolbarView setToolbarTabs:[_currentTabController availableTabs] animated:true];
|
||||
|
||||
[_portraitToolbarView setBackButtonType:backButtonType];
|
||||
[_landscapeToolbarView setBackButtonType:backButtonType];
|
||||
|
||||
[_portraitToolbarView setDoneButtonType:doneButtonType];
|
||||
[_landscapeToolbarView setDoneButtonType:doneButtonType];
|
||||
|
||||
[self updateEditorButtons];
|
||||
|
||||
if ([self respondsToSelector:@selector(setNeedsUpdateOfScreenEdgesDeferringSystemGestures)])
|
||||
@ -1474,10 +1502,7 @@
|
||||
|
||||
- (void)dismissEditor
|
||||
{
|
||||
if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
|
||||
[self presentEditorTab:TGPhotoEditorCropTab];
|
||||
return;
|
||||
} else if (![_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]] && _intent == TGPhotoEditorControllerAvatarIntent) {
|
||||
if ((![_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]] && ![_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]]) && _intent == TGPhotoEditorControllerAvatarIntent) {
|
||||
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
||||
return;
|
||||
}
|
||||
@ -1570,9 +1595,7 @@
|
||||
|
||||
- (void)doneButtonPressed
|
||||
{
|
||||
if ([_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]]) {
|
||||
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
||||
} else if (_intent == TGPhotoEditorControllerAvatarIntent && ![_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
|
||||
if (_intent == TGPhotoEditorControllerAvatarIntent && ![_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
|
||||
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
||||
} else {
|
||||
[self applyEditor];
|
||||
@ -1895,7 +1918,7 @@
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
if (self.overlayWindow != nil)
|
||||
if (self.overlayWindow != nil || self.customDismissBlock != nil)
|
||||
{
|
||||
[super dismiss];
|
||||
}
|
||||
|
||||
@ -82,6 +82,13 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)hasOnScreenNavigation {
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
return hasOnScreenNavigation;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)effectiveOrientation {
|
||||
return [self effectiveOrientation:self.interfaceOrientation];
|
||||
}
|
||||
|
||||
@ -1830,16 +1830,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||
{
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
|
||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
@ -1920,11 +1911,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
|
||||
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
||||
{
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
|
||||
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
||||
return CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
@ -1942,15 +1929,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
TGPhotoEditorPreviewView *previewView = self.previewView;
|
||||
[previewView prepareForTransitionOut];
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
UIInterfaceOrientation orientation = self.effectiveOrientation;
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGRect referenceFrame = CGRectMake(0, 0, self.photoEditor.rotatedCropSize.width, self.photoEditor.rotatedCropSize.height);
|
||||
CGRect rect = CGRectOffset([self transitionOutSourceFrameForReferenceFrame:referenceFrame orientation:orientation], -containerFrame.origin.x, -containerFrame.origin.y);
|
||||
previewView.frame = rect;
|
||||
@ -2183,18 +2163,14 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
CGFloat panelToolbarPortraitSize = TGPhotoPaintBottomPanelSize + TGPhotoEditorToolbarSize;
|
||||
CGFloat panelToolbarLandscapeSize = TGPhotoPaintBottomPanelSize + self.toolbarLandscapeSize;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
||||
screenEdges.top += safeAreaInset.top;
|
||||
screenEdges.left += safeAreaInset.left;
|
||||
screenEdges.bottom -= safeAreaInset.bottom;
|
||||
screenEdges.right -= safeAreaInset.right;
|
||||
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
|
||||
_settingsViewWrapper.frame = self.parentViewController.view.bounds;
|
||||
|
||||
@ -2361,18 +2337,10 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
|
||||
- (void)keyboardHeightChangedTo:(CGFloat)height duration:(NSTimeInterval)duration curve:(NSInteger)curve
|
||||
{
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([self inFormSheet] || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
CGFloat screenSide = MAX(referenceSize.width, referenceSize.height) + 2 * TGPhotoPaintBottomPanelSize;
|
||||
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
|
||||
CGFloat visibleArea = self.view.frame.size.height - height;
|
||||
CGFloat yCenter = visibleArea / 2.0f;
|
||||
|
||||
@ -42,12 +42,34 @@
|
||||
_buttonsWrapperView = [[UIView alloc] initWithFrame:_backgroundView.bounds];
|
||||
[_backgroundView addSubview:_buttonsWrapperView];
|
||||
|
||||
_cancelButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 49, 49)];
|
||||
CGSize buttonSize = CGSizeMake(49.0f, 49.0f);
|
||||
_cancelButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
|
||||
_cancelButton.exclusiveTouch = true;
|
||||
_cancelButton.adjustsImageWhenHighlighted = false;
|
||||
[self setBackButtonType:backButton];
|
||||
[_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_backgroundView addSubview:_cancelButton];
|
||||
|
||||
|
||||
_doneButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
|
||||
_doneButton.exclusiveTouch = true;
|
||||
_doneButton.adjustsImageWhenHighlighted = false;
|
||||
[self setDoneButtonType:doneButton];
|
||||
[_doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_backgroundView addSubview:_doneButton];
|
||||
|
||||
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(doneButtonLongPressed:)];
|
||||
_longPressGestureRecognizer.minimumPressDuration = 0.4;
|
||||
[_doneButton addGestureRecognizer:_longPressGestureRecognizer];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setBackButtonType:(TGPhotoEditorBackButton)backButtonType {
|
||||
_backButtonType = backButtonType;
|
||||
|
||||
UIImage *cancelImage = nil;
|
||||
switch (backButton)
|
||||
switch (backButtonType)
|
||||
{
|
||||
case TGPhotoEditorBackButtonCancel:
|
||||
cancelImage = TGTintedImage([UIImage imageNamed:@"Editor/Cancel"], [UIColor whiteColor]);
|
||||
@ -58,17 +80,27 @@
|
||||
break;
|
||||
}
|
||||
[_cancelButton setImage:cancelImage forState:UIControlStateNormal];
|
||||
[_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_backgroundView addSubview:_cancelButton];
|
||||
}
|
||||
|
||||
UIImage *doneImage = nil;
|
||||
CGSize buttonSize = CGSizeMake(49.0f, 49.0f);
|
||||
switch (doneButton)
|
||||
- (void)setDoneButtonType:(TGPhotoEditorDoneButton)doneButtonType {
|
||||
_doneButtonType = doneButtonType;
|
||||
|
||||
UIImage *doneImage;
|
||||
switch (doneButtonType)
|
||||
{
|
||||
case TGPhotoEditorDoneButtonCheck:
|
||||
doneImage = TGTintedImage([UIImage imageNamed:@"Editor/Commit"], [UIColor whiteColor]);
|
||||
break;
|
||||
|
||||
case TGPhotoEditorDoneButtonDone:
|
||||
{
|
||||
TGMediaAssetsPallete *pallete = nil;
|
||||
if ([[LegacyComponentsGlobals provider] respondsToSelector:@selector(mediaAssetsPallete)])
|
||||
pallete = [[LegacyComponentsGlobals provider] mediaAssetsPallete];
|
||||
|
||||
doneImage = pallete != nil ? pallete.doneIconImage : TGTintedImage([UIImage imageNamed:@"Editor/Commit"], [UIColor whiteColor]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
TGMediaAssetsPallete *pallete = nil;
|
||||
@ -79,20 +111,7 @@
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_doneButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
|
||||
_doneButton.exclusiveTouch = true;
|
||||
_doneButton.adjustsImageWhenHighlighted = false;
|
||||
|
||||
[_doneButton setImage:doneImage forState:UIControlStateNormal];
|
||||
[_doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_backgroundView addSubview:_doneButton];
|
||||
|
||||
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(doneButtonLongPressed:)];
|
||||
_longPressGestureRecognizer.minimumPressDuration = 0.4;
|
||||
[_doneButton addGestureRecognizer:_longPressGestureRecognizer];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIButton *)doneButton
|
||||
|
||||
@ -30,6 +30,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
{
|
||||
NSValue *_contentOffsetAfterRotation;
|
||||
bool _appeared;
|
||||
bool _scheduledTransitionIn;
|
||||
CGFloat _cellWidth;
|
||||
|
||||
NSArray *_allTools;
|
||||
@ -306,17 +307,17 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
|
||||
- (void)transitionIn
|
||||
{
|
||||
if (_portraitToolsWrapperView.frame.size.height < FLT_EPSILON) {
|
||||
_scheduledTransitionIn = true;
|
||||
return;
|
||||
}
|
||||
[UIView animateWithDuration:0.3f animations:^
|
||||
{
|
||||
_portraitToolsWrapperView.alpha = 1.0f;
|
||||
_landscapeToolsWrapperView.alpha = 1.0f;
|
||||
}];
|
||||
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
switch (orientation)
|
||||
switch (self.effectiveOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
{
|
||||
@ -350,8 +351,12 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
}
|
||||
}
|
||||
|
||||
- (void)transitionOutSwitching:(bool)__unused switching completion:(void (^)(void))completion
|
||||
- (void)transitionOutSwitching:(bool)switching completion:(void (^)(void))completion
|
||||
{
|
||||
if (switching) {
|
||||
_dismissing = true;
|
||||
}
|
||||
|
||||
TGPhotoEditorPreviewView *previewView = self.previewView;
|
||||
previewView.touchedUp = nil;
|
||||
previewView.touchedDown = nil;
|
||||
@ -360,11 +365,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
|
||||
[_toolAreaView.superview bringSubviewToFront:_toolAreaView];
|
||||
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
switch (orientation)
|
||||
switch (self.effectiveOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
{
|
||||
@ -769,17 +770,18 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
|
||||
[self updateLayout:[[LegacyComponentsGlobals provider] applicationStatusBarOrientation]];
|
||||
|
||||
if (_scheduledTransitionIn) {
|
||||
_scheduledTransitionIn = false;
|
||||
[self transitionIn];
|
||||
}
|
||||
|
||||
if (![self inFormSheet])
|
||||
[self _applyPreparedContentOffset];
|
||||
}
|
||||
|
||||
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
||||
{
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
||||
CGRect sourceFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
|
||||
@ -789,16 +791,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||
{
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
|
||||
@ -831,11 +824,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
||||
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
||||
screenEdges.top += safeAreaInset.top;
|
||||
screenEdges.left += safeAreaInset.left;
|
||||
@ -946,23 +935,14 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
||||
|
||||
- (void)updatePreviewView
|
||||
{
|
||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
||||
if ([self inFormSheet] || TGIsPad())
|
||||
orientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
|
||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||
TGPhotoEditorPreviewView *previewView = self.previewView;
|
||||
|
||||
if (_dismissing || previewView.superview != self.view)
|
||||
return;
|
||||
|
||||
bool hasOnScreenNavigation = false;
|
||||
if (iosMajorVersion() >= 11)
|
||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||
|
||||
CGRect containerFrame = _preview ? CGRectMake(0.0f, 0.0f, referenceSize.width, referenceSize.height) : [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGSize referenceSize = [self referenceViewSize];
|
||||
CGRect containerFrame = _preview ? CGRectMake(0.0f, 0.0f, referenceSize.width, referenceSize.height) : [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||
CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size);
|
||||
previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#import "TGPhotoPaintStickerEntity.h"
|
||||
#import "TGPhotoPaintTextEntity.h"
|
||||
|
||||
const NSTimeInterval TGVideoEditMinimumTrimmableDuration = 1.0;
|
||||
const NSTimeInterval TGVideoEditMinimumTrimmableDuration = 1.5;
|
||||
const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
|
||||
@implementation TGVideoEditAdjustments
|
||||
|
||||
@ -27,7 +27,7 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
|
||||
}
|
||||
completion(image)
|
||||
}
|
||||
mixin.didFinishWithView = { [weak legacyController] in
|
||||
mixin.didFinishWithView = {
|
||||
openCurrent?()
|
||||
}
|
||||
mixin.didDismiss = { [weak legacyController] in
|
||||
|
||||
@ -346,7 +346,7 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
||||
let navigationBar = presentationTheme.rootController.navigationBar
|
||||
let tabBar = presentationTheme.rootController.tabBar
|
||||
|
||||
return TGMediaAssetsPallete(dark: presentationTheme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: tabBar.backgroundColor, barSeparatorColor: tabBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationTheme), maybeAccentColor: navigationBar.accentTextColor)
|
||||
return TGMediaAssetsPallete(dark: presentationTheme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: tabBar.backgroundColor, barSeparatorColor: tabBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationTheme), doneIconImage: PresentationResourcesChat.chatInputPanelApplyButtonImage(presentationTheme), maybeAccentColor: navigationBar.accentTextColor)
|
||||
}
|
||||
|
||||
func checkButtonPallete() -> TGCheckButtonPallete! {
|
||||
|
||||
@ -105,7 +105,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo
|
||||
$0.item(context: context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, secureIdContext: strongSelf.secureIdContext, delete: { resource in
|
||||
self?.deleteItem(resource)
|
||||
})
|
||||
}), centralItemIndex: centralIndex, keepFirst: false)
|
||||
}), centralItemIndex: centralIndex)
|
||||
|
||||
let ready = (strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void()))) |> afterNext { [weak strongSelf] _ in
|
||||
strongSelf?.didSetReady = true
|
||||
|
||||
@ -39,7 +39,7 @@ class SecureIdDocumentGalleryItem: GalleryItem {
|
||||
self.delete = delete
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = SecureIdDocumentGalleryItemNode(context: self.context, theme: self.theme, strings: self.strings)
|
||||
|
||||
node.setResource(secureIdContext: self.secureIdContext, resource: self.resource)
|
||||
@ -52,7 +52,7 @@ class SecureIdDocumentGalleryItem: GalleryItem {
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? SecureIdDocumentGalleryItemNode {
|
||||
node._title.set(.single(self.strings.Items_NOfM("\(self.location.position + 1)", "\(self.location.totalCount)").0))
|
||||
|
||||
|
||||
@ -223,6 +223,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
self.disposable.set(combineLatest(entriesSignal, self.animatedIn.get()).start(next: { [weak self] entries, animatedIn in
|
||||
let f: () -> Void = {
|
||||
if let strongSelf = self, animatedIn {
|
||||
let isFirstTime = strongSelf.entries.isEmpty
|
||||
strongSelf.entries = entries
|
||||
if strongSelf.centralEntryIndex == nil {
|
||||
strongSelf.centralEntryIndex = 0
|
||||
@ -248,7 +249,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
} : nil, setMain: { [weak self] in
|
||||
self?.setMainEntry(entry)
|
||||
})
|
||||
}), centralItemIndex: 0, keepFirst: false)
|
||||
}), centralItemIndex: 0, synchronous: !isFirstTime)
|
||||
|
||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
||||
strongSelf?.didSetReady = true
|
||||
@ -597,7 +598,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
} else {
|
||||
if let index = self.entries.firstIndex(of: entry) {
|
||||
self.entries.remove(at: index)
|
||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -611,7 +612,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
} else {
|
||||
if let index = self.entries.firstIndex(of: entry) {
|
||||
self.entries.remove(at: index)
|
||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -625,7 +626,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
} else {
|
||||
if let index = self.entries.firstIndex(of: entry) {
|
||||
self.entries.remove(at: index)
|
||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,27 +65,27 @@ class PeerAvatarImageGalleryItem: GalleryItem {
|
||||
self.setMain = setMain
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = PeerAvatarImageGalleryItemNode(context: self.context, presentationData: self.presentationData, peer: self.peer, sourceHasRoundCorners: self.sourceHasRoundCorners)
|
||||
|
||||
if let indexData = self.entry.indexData {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
||||
}
|
||||
|
||||
node.setEntry(self.entry)
|
||||
node.setEntry(self.entry, synchronous: synchronous)
|
||||
node.footerContentNode.delete = self.delete
|
||||
node.footerContentNode.setMain = self.setMain
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? PeerAvatarImageGalleryItemNode {
|
||||
if let indexData = self.entry.indexData {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
||||
}
|
||||
|
||||
node.setEntry(self.entry)
|
||||
node.setEntry(self.entry, synchronous: synchronous)
|
||||
node.footerContentNode.delete = self.delete
|
||||
node.footerContentNode.setMain = self.setMain
|
||||
}
|
||||
@ -201,7 +201,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(), size: statusSize))
|
||||
}
|
||||
|
||||
fileprivate func setEntry(_ entry: AvatarGalleryEntry) {
|
||||
fileprivate func setEntry(_ entry: AvatarGalleryEntry, synchronous: Bool) {
|
||||
if self.entry != entry {
|
||||
self.entry = entry
|
||||
|
||||
@ -224,7 +224,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
case let .image(_, _, imageRepresentations, _, _, _, _, _):
|
||||
representations = imageRepresentations
|
||||
}
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations), dispatchOnDisplayLink: false)
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, attemptSynchronously: synchronous), attemptSynchronously: synchronous, dispatchOnDisplayLink: false)
|
||||
self.zoomableContent = (largestSize.dimensions.cgSize, self.contentNode)
|
||||
|
||||
if let largestIndex = representations.firstIndex(where: { $0.representation == largestSize }) {
|
||||
@ -278,8 +278,8 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
if let video = entry.videoRepresentations.last, let id = id {
|
||||
let mediaManager = self.context.sharedContext.mediaManager
|
||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
|
||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
||||
videoNode.isUserInteractionEnabled = false
|
||||
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||
|
||||
@ -774,7 +774,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
|
||||
if let profileImage = peer?.smallProfileImage {
|
||||
return $0.withUpdatedUpdatingAvatar(.image(profileImage, false))
|
||||
} else {
|
||||
return $0.withUpdatedUpdatingAvatar(.none)
|
||||
return $0.withUpdatedUpdatingAvatar(ItemListAvatarAndNameInfoItemUpdatingAvatar.none)
|
||||
}
|
||||
}
|
||||
updateAvatarDisposable.set((updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
|
||||
@ -628,7 +628,7 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
if let profileImage = peer?.smallProfileImage {
|
||||
return $0.withUpdatedUpdatingAvatar(.image(profileImage, false))
|
||||
} else {
|
||||
return $0.withUpdatedUpdatingAvatar(.none)
|
||||
return $0.withUpdatedUpdatingAvatar(ItemListAvatarAndNameInfoItemUpdatingAvatar.none)
|
||||
}
|
||||
}
|
||||
updateAvatarDisposable.set((updateAccountPhoto(account: context.account, resource: nil, videoResource: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
|
||||
@ -301,7 +301,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
updateItems.append(item)
|
||||
i += 1
|
||||
}
|
||||
return GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: updateItems, focusOnItem: self.galleryNode.pager.centralItemNode()?.index)
|
||||
return GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: updateItems, focusOnItem: self.galleryNode.pager.centralItemNode()?.index, synchronous: false)
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
|
||||
@ -51,13 +51,13 @@ class WallpaperGalleryItem: GalleryItem {
|
||||
self.source = source
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = WallpaperGalleryItemNode(context: self.context)
|
||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? WallpaperGalleryItemNode {
|
||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
||||
}
|
||||
|
||||
@ -122,19 +122,21 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
||||
public let sizeSpec: String
|
||||
public let volumeId: Int64
|
||||
public let localId: Int32
|
||||
public let size: Int?
|
||||
public let fileReference: Data?
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return CloudPhotoSizeMediaResourceId(datacenterId: Int32(self.datacenterId), photoId: self.photoId, sizeSpec: self.sizeSpec)
|
||||
}
|
||||
|
||||
public init(datacenterId: Int32, photoId: Int64, accessHash: Int64, sizeSpec: String, volumeId: Int64, localId: Int32, fileReference: Data?) {
|
||||
public init(datacenterId: Int32, photoId: Int64, accessHash: Int64, sizeSpec: String, volumeId: Int64, localId: Int32, size: Int?, fileReference: Data?) {
|
||||
self.datacenterId = Int(datacenterId)
|
||||
self.photoId = photoId
|
||||
self.accessHash = accessHash
|
||||
self.sizeSpec = sizeSpec
|
||||
self.volumeId = volumeId
|
||||
self.localId = localId
|
||||
self.size = size
|
||||
self.fileReference = fileReference
|
||||
}
|
||||
|
||||
@ -145,6 +147,11 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
||||
self.sizeSpec = decoder.decodeStringForKey("s", orElse: "")
|
||||
self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0)
|
||||
self.localId = decoder.decodeInt32ForKey("l", orElse: 0)
|
||||
if let size = decoder.decodeOptionalInt32ForKey("n") {
|
||||
self.size = Int(size)
|
||||
} else {
|
||||
self.size = nil
|
||||
}
|
||||
self.fileReference = decoder.decodeBytesForKey("fr")?.makeData()
|
||||
}
|
||||
|
||||
@ -155,6 +162,11 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
||||
encoder.encodeString(self.sizeSpec, forKey: "s")
|
||||
encoder.encodeInt64(self.volumeId, forKey: "v")
|
||||
encoder.encodeInt32(self.localId, forKey: "l")
|
||||
if let size = self.size {
|
||||
encoder.encodeInt32(Int32(size), forKey: "n")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "n")
|
||||
}
|
||||
if let fileReference = self.fileReference {
|
||||
encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr")
|
||||
} else {
|
||||
@ -164,7 +176,7 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? CloudPhotoSizeMediaResource {
|
||||
return self.datacenterId == to.datacenterId && self.photoId == to.photoId && self.accessHash == to.accessHash && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId && self.fileReference == to.fileReference
|
||||
return self.datacenterId == to.datacenterId && self.photoId == to.photoId && self.accessHash == to.accessHash && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId && self.size == to.size && self.fileReference == to.fileReference
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -125,12 +125,13 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
|
||||
|> mapError { _ in return UploadPeerPhotoError.generic }
|
||||
|> mapToSignal { photo -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
var videoRepresentations: [TelegramMediaImage.VideoRepresentation] = []
|
||||
switch photo {
|
||||
case let .photo(photo: apiPhoto, users: _):
|
||||
switch apiPhoto {
|
||||
case .photoEmpty:
|
||||
break
|
||||
case let .photo(_, _, _, _, _, sizes, videoSizes, dcId):
|
||||
case let .photo(_, id, accessHash, fileReference, _, sizes, videoSizes, dcId):
|
||||
var sizes = sizes
|
||||
if sizes.count == 3 {
|
||||
sizes.remove(at: 1)
|
||||
@ -147,14 +148,32 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
|
||||
}
|
||||
}
|
||||
|
||||
if let resource = photoResult.resource as? LocalFileReferenceMediaResource {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) {
|
||||
for representation in representations {
|
||||
postbox.mediaBox.storeResourceData(representation.resource.id, data: data)
|
||||
if let videoSizes = videoSizes {
|
||||
for size in videoSizes {
|
||||
switch size {
|
||||
case let .videoSize(type, location, w, h, size):
|
||||
let resource: TelegramMediaResource
|
||||
switch location {
|
||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||
resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: Int(size), fileReference: fileReference.makeData())
|
||||
}
|
||||
|
||||
videoRepresentations.append(TelegramMediaImage.VideoRepresentation(
|
||||
dimensions: PixelDimensions(width: w, height: h),
|
||||
resource: resource))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for representation in representations {
|
||||
postbox.mediaBox.copyResourceData(from: photoResult.resource.id, to: representation.resource.id)
|
||||
}
|
||||
|
||||
if let resource = videoResult?.resource {
|
||||
for representation in videoRepresentations {
|
||||
postbox.mediaBox.copyResourceData(from: resource.id, to: representation.resource.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return postbox.transaction { transaction -> (UpdatePeerPhotoStatus, MediaResource?) in
|
||||
@ -221,7 +240,7 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
|
||||
switch result {
|
||||
case let .complete(representations):
|
||||
if let resource = resource as? LocalFileReferenceMediaResource {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath), options: [.mappedRead] ) {
|
||||
for representation in representations {
|
||||
postbox.mediaBox.storeResourceData(representation.resource.id, data: data)
|
||||
}
|
||||
@ -284,16 +303,10 @@ public func updatePeerPhotoExisting(network: Network, reference: TelegramMediaIm
|
||||
|> `catch` { _ -> Signal<Api.UserProfilePhoto, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return network.request(Api.functions.photos.deletePhotos(id: [.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))]))
|
||||
|> `catch` { _ -> Signal<[Int64], NoError> in
|
||||
return .single([])
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func removeAccountPhoto(network: Network, reference: TelegramMediaImageReference?) -> Signal<Void, NoError> {
|
||||
|
||||
@ -12,13 +12,13 @@ func telegramMediaImageRepresentationsFromApiSizes(datacenterId: Int32, photoId:
|
||||
case let .photoCachedSize(type, location, w, h, _):
|
||||
switch location {
|
||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference)
|
||||
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: nil, fileReference: fileReference)
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource))
|
||||
}
|
||||
case let .photoSize(type, location, w, h, _):
|
||||
case let .photoSize(type, location, w, h, size):
|
||||
switch location {
|
||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference)
|
||||
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: Int(size), fileReference: fileReference)
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource))
|
||||
}
|
||||
case let .photoStrippedSize(_, data):
|
||||
@ -44,11 +44,11 @@ func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? {
|
||||
if let videoSizes = videoSizes {
|
||||
for size in videoSizes {
|
||||
switch size {
|
||||
case let .videoSize(type, location, w, h, _):
|
||||
case let .videoSize(type, location, w, h, size):
|
||||
let resource: TelegramMediaResource
|
||||
switch location {
|
||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||
resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference.makeData())
|
||||
resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: Int(size), fileReference: fileReference.makeData())
|
||||
}
|
||||
|
||||
videoRepresentations.append(TelegramMediaImage.VideoRepresentation(
|
||||
|
||||
@ -12,7 +12,7 @@ private func collectPreCachedResources(for photo: Api.Photo) -> [(MediaResource,
|
||||
case let .photoCachedSize(type, location, _, _, bytes):
|
||||
switch location {
|
||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||
let resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference.makeData())
|
||||
let resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: nil, fileReference: fileReference.makeData())
|
||||
let data = bytes.makeData()
|
||||
return [(resource, data)]
|
||||
}
|
||||
|
||||
@ -7,7 +7,10 @@ import TelegramUIPreferences
|
||||
|
||||
private func decodeColor<Key>(_ values: KeyedDecodingContainer<Key>, _ key: Key, decoder: Decoder? = nil, fallbackKey: String? = nil) throws -> UIColor {
|
||||
if let decoder = decoder as? PresentationThemeDecoding, let fallbackKey = fallbackKey {
|
||||
let key = (decoder.codingPath.map { $0.stringValue } + [key.stringValue]).joined(separator: ".")
|
||||
var codingPath = decoder.codingPath.map { $0.stringValue }
|
||||
codingPath.append(key.stringValue)
|
||||
|
||||
let key = codingPath.joined(separator: ".")
|
||||
decoder.fallbackKeys[key] = fallbackKey
|
||||
}
|
||||
|
||||
@ -1021,9 +1024,17 @@ extension PresentationThemeBubbleColorComponents: Codable {
|
||||
public convenience init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
||||
|
||||
var fillColor = try decodeColor(values, .bg)
|
||||
var gradientColor = try decodeColor(values, .gradientBg, decoder: decoder, fallbackKey: "\(codingPath).bg")
|
||||
if gradientColor.rgb != fillColor.rgb {
|
||||
fillColor = fillColor.withAlphaComponent(1.0)
|
||||
gradientColor = gradientColor.withAlphaComponent(1.0)
|
||||
}
|
||||
|
||||
self.init(
|
||||
fill: try decodeColor(values, .bg),
|
||||
gradientFill: try decodeColor(values, .gradientBg, decoder: decoder, fallbackKey: codingPath + ".bg"),
|
||||
fill: fillColor,
|
||||
gradientFill: gradientColor,
|
||||
highlightedFill: try decodeColor(values, .highlightedBg),
|
||||
stroke: try decodeColor(values, .stroke),
|
||||
shadow: try? values.decode(PresentationThemeBubbleShadow.self, forKey: .shadow)
|
||||
@ -1162,7 +1173,7 @@ extension PresentationThemePartedColors: Codable {
|
||||
accentControlDisabledColor: (try? decodeColor(values, .accentControlDisabled)) ?? accentControlColor.withAlphaComponent(0.5),
|
||||
mediaActiveControlColor: try decodeColor(values, .mediaActiveControl),
|
||||
mediaInactiveControlColor: try decodeColor(values, .mediaInactiveControl),
|
||||
mediaControlInnerBackgroundColor: try decodeColor(values, .mediaControlInnerBg, decoder: decoder, fallbackKey: codingPath + ".bubble.withWp.bg"),
|
||||
mediaControlInnerBackgroundColor: try decodeColor(values, .mediaControlInnerBg, decoder: decoder, fallbackKey: "\(codingPath).bubble.withWp.bg"),
|
||||
pendingActivityColor: try decodeColor(values, .pendingActivity),
|
||||
fileTitleColor: try decodeColor(values, .fileTitle),
|
||||
fileDescriptionColor: try decodeColor(values, .fileDescription),
|
||||
@ -1389,7 +1400,7 @@ extension PresentationThemeChatInputPanel: Codable {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
||||
self.init(panelBackgroundColor: try decodeColor(values, .panelBg),
|
||||
panelBackgroundColorNoWallpaper: try decodeColor(values, .panelBg, decoder: decoder, fallbackKey: codingPath + ".panelBgNoWallpaper"),
|
||||
panelBackgroundColorNoWallpaper: try decodeColor(values, .panelBg, decoder: decoder, fallbackKey: "\(codingPath).panelBgNoWallpaper"),
|
||||
panelSeparatorColor: try decodeColor(values, .panelSeparator),
|
||||
panelControlAccentColor: try decodeColor(values, .panelControlAccent),
|
||||
panelControlColor: try decodeColor(values, .panelControl),
|
||||
|
||||
@ -182,12 +182,20 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
var isExpanded: Bool = false {
|
||||
didSet {
|
||||
self.videoNode?.canAttachContent = self.isExpanded
|
||||
}
|
||||
}
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.imageNode = TransformImageNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||
self.addSubnode(self.imageNode)
|
||||
|
||||
@ -222,8 +230,8 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
|
||||
if let video = videoRepresentations.last, let id = id {
|
||||
let mediaManager = self.context.sharedContext.mediaManager
|
||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
|
||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
||||
videoNode.isUserInteractionEnabled = false
|
||||
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||
@ -259,7 +267,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
videoNode.updateLayout(size: imageSize, transition: .immediate)
|
||||
videoNode.frame = imageFrame
|
||||
|
||||
videoNode.canAttachContent = true
|
||||
videoNode.canAttachContent = self.isExpanded
|
||||
if videoNode.hasAttachedContext {
|
||||
videoNode.play()
|
||||
}
|
||||
@ -285,17 +293,17 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
private var items: [PeerInfoAvatarListItem] = []
|
||||
private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:]
|
||||
private var stripNodes: [ASImageNode] = []
|
||||
private var stripWidth: CGFloat = 0.0
|
||||
private let activeStripImage: UIImage
|
||||
private var appliedStripNodeCurrentIndex: Int?
|
||||
private var currentIndex: Int = 0
|
||||
private var transitionFraction: CGFloat = 0.0
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var isExpanded = false
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private let positionDisposable = MetaDisposable()
|
||||
private var initializedList = false
|
||||
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
||||
|
||||
let isReady = Promise<Bool>()
|
||||
private var didSetReady = false
|
||||
@ -316,55 +324,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private var playerUpdateTimer: SwiftSignalKit.Timer?
|
||||
private var playerStatus: MediaPlayerStatus? {
|
||||
didSet {
|
||||
if self.playerStatus != oldValue {
|
||||
if let playerStatus = playerStatus, case .playing = playerStatus.status {
|
||||
self.ensureHasTimer()
|
||||
} else {
|
||||
self.stopTimer()
|
||||
}
|
||||
self.updateStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func ensureHasTimer() {
|
||||
if self.playerUpdateTimer == nil {
|
||||
let timer = SwiftSignalKit.Timer(timeout: 0.016, repeat: true, completion: { [weak self] in
|
||||
self?.updateStatus()
|
||||
}, queue: Queue.mainQueue())
|
||||
self.playerUpdateTimer = timer
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateStatus() {
|
||||
var position: CGFloat = 1.0
|
||||
if let playerStatus = self.playerStatus {
|
||||
var playerPosition: Double
|
||||
if !playerStatus.generationTimestamp.isZero, case .playing = playerStatus.status {
|
||||
playerPosition = playerStatus.timestamp + (CACurrentMediaTime() - playerStatus.generationTimestamp)
|
||||
} else {
|
||||
playerPosition = playerStatus.timestamp
|
||||
}
|
||||
|
||||
position = CGFloat(playerPosition / playerStatus.duration)
|
||||
}
|
||||
|
||||
if let appliedStripNodeCurrentIndex = self.appliedStripNodeCurrentIndex {
|
||||
var frame = self.stripNodes[appliedStripNodeCurrentIndex].frame
|
||||
frame.size.width = self.stripWidth * position
|
||||
self.stripNodes[appliedStripNodeCurrentIndex].frame = frame
|
||||
}
|
||||
}
|
||||
|
||||
private func stopTimer() {
|
||||
self.playerUpdateTimer?.invalidate()
|
||||
self.playerUpdateTimer = nil
|
||||
}
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
|
||||
@ -537,7 +496,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.positionDisposable.dispose()
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
@ -628,8 +586,9 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func update(size: CGSize, peer: Peer?, transition: ContainedViewLayoutTransition) {
|
||||
func update(size: CGSize, peer: Peer?, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
self.isExpanded = isExpanded
|
||||
|
||||
self.leftHighlightNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height))
|
||||
self.rightHighlightNode.frame = CGRect(origin: CGPoint(x: size.width - floor(size.width * 1.0 / 5.0), y: 0.0), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height))
|
||||
@ -652,6 +611,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
strongSelf.galleryEntries = entries
|
||||
strongSelf.items = items
|
||||
strongSelf.itemsUpdated?(items)
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.updateItems(size: size, transition: .immediate, stripTransition: .immediate)
|
||||
}
|
||||
@ -677,9 +637,11 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
var wasAdded = false
|
||||
if let current = self.itemNodes[self.items[i].id] {
|
||||
itemNode = current
|
||||
itemNode.isExpanded = self.isExpanded
|
||||
} else {
|
||||
wasAdded = true
|
||||
itemNode = PeerInfoAvatarListItemNode(context: self.context)
|
||||
itemNode.isExpanded = self.isExpanded
|
||||
itemNode.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex)
|
||||
self.itemNodes[self.items[i].id] = itemNode
|
||||
self.contentNode.addSubnode(itemNode)
|
||||
@ -687,6 +649,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
let indexOffset = CGFloat(i - self.currentIndex)
|
||||
let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width - size.width / 2.0, y: -size.height / 2.0), size: size)
|
||||
|
||||
|
||||
if wasAdded {
|
||||
addedItemNodesForAdditiveTransition.append(itemNode)
|
||||
itemNode.frame = itemFrame
|
||||
@ -748,17 +711,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
if self.currentIndex >= 0 && self.currentIndex < self.stripNodes.count {
|
||||
self.stripNodes[self.currentIndex].alpha = 1.0
|
||||
}
|
||||
|
||||
if let currentItemNode = self.currentItemNode {
|
||||
self.positionDisposable.set((currentItemNode.mediaStatus
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self {
|
||||
strongSelf.playerStatus = status
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
self.positionDisposable.set(nil)
|
||||
}
|
||||
}
|
||||
if hadOneStripNode && self.stripNodes.count > 1 {
|
||||
self.stripContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
@ -766,7 +718,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
let stripInset: CGFloat = 8.0
|
||||
let stripSpacing: CGFloat = 4.0
|
||||
let stripWidth: CGFloat = max(5.0, floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count)))
|
||||
self.stripWidth = stripWidth
|
||||
let currentStripMinX = stripInset + CGFloat(self.currentIndex) * (stripWidth + stripSpacing)
|
||||
let currentStripMidX = floor(currentStripMinX + stripWidth / 2.0)
|
||||
let lastStripMaxX = stripInset + CGFloat(self.stripNodes.count - 1) * (stripWidth + stripSpacing) + stripWidth
|
||||
@ -795,6 +746,9 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
let context: AccountContext
|
||||
let avatarNode: AvatarNode
|
||||
|
||||
private var videoNode: UniversalVideoNode?
|
||||
private var videoContent: NativeVideoContent?
|
||||
|
||||
var tapped: (() -> Void)?
|
||||
|
||||
private var isFirstAvatarLoading = true
|
||||
@ -818,7 +772,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func update(peer: Peer?, theme: PresentationTheme, avatarSize: CGFloat) {
|
||||
func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool) {
|
||||
if let peer = peer {
|
||||
var overrideImage: AvatarNodeImageOverride?
|
||||
if peer.isDeleted {
|
||||
@ -829,6 +783,46 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
|
||||
self.avatarNode.frame = CGRect(origin: CGPoint(x: -avatarSize / 2.0, y: -avatarSize / 2.0), size: CGSize(width: avatarSize, height: avatarSize))
|
||||
self.avatarNode.font = avatarPlaceholderFont(size: floor(avatarSize * 16.0 / 37.0))
|
||||
|
||||
if let item = item, case let .image(reference, _, videoRepresentations) = item, let video = videoRepresentations.last, case let .cloud(imageId, _, _) = reference {
|
||||
let id = imageId
|
||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||
if videoContent.id != self.videoContent?.id {
|
||||
let mediaManager = self.context.sharedContext.mediaManager
|
||||
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
||||
videoNode.isUserInteractionEnabled = false
|
||||
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||
if let strongSelf = self {
|
||||
strongSelf.videoNode?.isHidden = !owns
|
||||
}
|
||||
}
|
||||
self.videoContent = videoContent
|
||||
self.videoNode = videoNode
|
||||
|
||||
let maskPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint(), size: self.avatarNode.frame.size))
|
||||
let shape = CAShapeLayer()
|
||||
shape.path = maskPath.cgPath
|
||||
videoNode.layer.mask = shape
|
||||
|
||||
self.addSubnode(videoNode)
|
||||
}
|
||||
} else if let videoNode = self.videoNode {
|
||||
self.videoContent = nil
|
||||
self.videoNode = nil
|
||||
|
||||
videoNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let videoNode = self.videoNode {
|
||||
videoNode.updateLayout(size: self.avatarNode.frame.size, transition: .immediate)
|
||||
videoNode.frame = self.avatarNode.frame
|
||||
|
||||
videoNode.canAttachContent = !isExpanded
|
||||
if videoNode.hasAttachedContext {
|
||||
videoNode.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -922,6 +916,9 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
||||
|
||||
let isReady = Promise<Bool>()
|
||||
|
||||
var arguments: (Peer?, PresentationTheme, CGFloat, Bool)?
|
||||
var item: PeerInfoAvatarListItem?
|
||||
|
||||
init(context: AccountContext, readyWhenGalleryLoads: Bool) {
|
||||
self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context)
|
||||
self.listContainerTransformNode = ASDisplayNode()
|
||||
@ -965,10 +962,20 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
||||
return value
|
||||
}
|
||||
|> take(1))
|
||||
|
||||
self.listContainerNode.itemsUpdated = { [weak self] items in
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = items.first
|
||||
if let (peer, theme, avatarSize, isExpanded) = strongSelf.arguments {
|
||||
strongSelf.avatarContainerNode.update(peer: peer, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
|
||||
self.avatarContainerNode.update(peer: peer, theme: theme, avatarSize: avatarSize)
|
||||
self.arguments = (peer, theme, avatarSize, isExpanded)
|
||||
self.avatarContainerNode.update(peer: peer, item: self.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded)
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
@ -2073,7 +2080,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale)
|
||||
}
|
||||
|
||||
self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, transition: transition)
|
||||
self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, isExpanded: self.isAvatarExpanded, transition: transition)
|
||||
|
||||
let panelWithAvatarHeight: CGFloat = 112.0 + avatarSize
|
||||
let buttonsCollapseStart = titleCollapseOffset
|
||||
|
||||
@ -829,7 +829,9 @@ public func drawThemeImage(context c: CGContext, theme: PresentationTheme, wallp
|
||||
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
||||
if incoming.fill.rgb != incoming.gradientFill.rgb {
|
||||
let gradientColors = [incoming.fill, incoming.gradientFill].map { $0.cgColor } as CFArray
|
||||
c.clip()
|
||||
|
||||
let gradientColors = [incoming.fill.withAlphaComponent(1.0), incoming.gradientFill.withAlphaComponent(1.0)].map { $0.cgColor } as CFArray
|
||||
var locations: [CGFloat] = [0.0, 1.0]
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
@ -855,7 +857,7 @@ public func drawThemeImage(context c: CGContext, theme: PresentationTheme, wallp
|
||||
if outgoing.fill.rgb != outgoing.gradientFill.rgb {
|
||||
c.clip()
|
||||
|
||||
let gradientColors = [outgoing.fill, outgoing.gradientFill].map { $0.cgColor } as CFArray
|
||||
let gradientColors = [outgoing.fill.withAlphaComponent(1.0), outgoing.gradientFill.withAlphaComponent(1.0)].map { $0.cgColor } as CFArray
|
||||
var locations: [CGFloat] = [0.0, 1.0]
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
@ -139,7 +139,7 @@ class WebSearchGalleryController: ViewController {
|
||||
if strongSelf.isViewLoaded {
|
||||
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
||||
$0.item(context: context, presentationData: strongSelf.presentationData, controllerInteraction: strongSelf.controllerInteraction)
|
||||
}), centralItemIndex: centralIndex, keepFirst: false)
|
||||
}), centralItemIndex: centralIndex)
|
||||
|
||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
||||
strongSelf?.didSetReady = true
|
||||
|
||||
@ -35,13 +35,13 @@ class WebSearchVideoGalleryItem: GalleryItem {
|
||||
self.controllerInteraction = controllerInteraction
|
||||
}
|
||||
|
||||
func node() -> GalleryItemNode {
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = WebSearchVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, controllerInteraction: self.controllerInteraction)
|
||||
node.setupItem(self)
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode) {
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? WebSearchVideoGalleryItemNode {
|
||||
node.setupItem(self)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user