Merge commit '32251e1ef2d2852be730292229767385bed0b2d7'

This commit is contained in:
Ali 2023-04-12 20:48:31 +04:00
commit 5f1d7970ce
19 changed files with 480 additions and 279 deletions

View File

@ -68,6 +68,8 @@ typedef enum {
@property (nonatomic, strong) UIView<TGPhotoDrawingEntitiesView> *entitiesView;
@property (nonatomic, assign) bool ignoreCropForResult;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id<TGMediaEditableItem>)item intent:(TGPhotoEditorControllerIntent)intent adjustments:(id<TGMediaEditAdjustments>)adjustments caption:(NSAttributedString *)caption screenImage:(UIImage *)screenImage availableTabs:(TGPhotoEditorTab)availableTabs selectedTab:(TGPhotoEditorTab)selectedTab;
- (void)dismissEditor;

View File

@ -46,6 +46,7 @@ CGSize TGPhotoThumbnailSizeForCurrentScreen();
CGSize TGPhotoEditorScreenImageMaxSize();
extern const CGSize TGPhotoEditorResultImageMaxSize;
extern const CGSize TGPhotoEditorResultImageWallpaperMaxSize;
#ifdef __cplusplus
}

View File

@ -6,6 +6,6 @@
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView *)mainSnapshot snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
+ (void)presentEditorWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item fromRect:(CGRect)fromRect mainSnapshot:(UIView *)mainSnapshot snapshots:(NSArray *)snapshots completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
+ (void)presentEditorWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller withItem:(id<TGMediaEditableItem>)item cropRect:(CGRect)cropRect adjustments:(id<TGMediaEditAdjustments>)adjustments referenceView:(UIView *)referenceView completion:(void (^)(UIImage *, id<TGMediaEditAdjustments>))completion fullSizeCompletion:(void (^)(UIImage *))fullSizeCompletion beginTransitionOut:(void (^)())beginTransitionOut finishTransitionOut:(void (^)())finishTransitionOut;
@end

View File

@ -81,9 +81,6 @@
[[NSFileManager defaultManager] removeItemAtPath:[self filePath] error:nil];
}
#define PGTick NSDate *startTime = [NSDate date]
#define PGTock NSLog(@"!=========== %s Time: %f", __func__, -[startTime timeIntervalSinceNow])
- (void)_saveToDisk:(UIImage *)image
{
if (image == nil)

View File

@ -982,14 +982,23 @@
bool hasImageAdjustments = editorValues.toolsApplied || saveOnly;
bool hasPainting = editorValues.hasPainting;
bool hasAnimation = editorValues.paintingData.hasAnimation;
bool ignoreCropForResult = self.ignoreCropForResult;
SSignal *(^imageCropSignal)(UIImage *, bool) = ^(UIImage *image, bool resize)
{
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
{
UIImage *paintingImage = !hasImageAdjustments ? editorValues.paintingData.image : nil;
UIImage *croppedImage = TGPhotoEditorCrop(image, paintingImage, photoEditor.cropOrientation, photoEditor.cropRotation, photoEditor.cropRect, photoEditor.cropMirrored, TGPhotoEditorResultImageMaxSize, photoEditor.originalSize, resize);
[subscriber putNext:croppedImage];
if (ignoreCropForResult) {
if (image.size.width > TGPhotoEditorResultImageWallpaperMaxSize.width || image.size.height > TGPhotoEditorResultImageWallpaperMaxSize.width) {
[subscriber putNext:TGPhotoEditorFitImage(image, TGPhotoEditorResultImageWallpaperMaxSize)];
} else {
[subscriber putNext:image];
}
} else {
UIImage *paintingImage = !hasImageAdjustments ? editorValues.paintingData.image : nil;
UIImage *croppedImage = TGPhotoEditorCrop(image, paintingImage, photoEditor.cropOrientation, photoEditor.cropRotation, photoEditor.cropRect, photoEditor.cropMirrored, TGPhotoEditorResultImageMaxSize, photoEditor.originalSize, resize);
[subscriber putNext:croppedImage];
}
[subscriber putCompletion];
return nil;
@ -1045,12 +1054,18 @@
void (^didFinishRenderingFullSizeImage)(UIImage *) = self.didFinishRenderingFullSizeImage;
void (^didFinishEditing)(id<TGMediaEditAdjustments>, UIImage *, UIImage *, bool , void(^)(void)) = self.didFinishEditing;
TGPhotoEditorControllerIntent intent = _intent;
[[[[renderedImageSignal map:^id(UIImage *image)
{
if (!hasImageAdjustments)
{
if (hasPainting && !hasAnimation && didFinishRenderingFullSizeImage != nil)
didFinishRenderingFullSizeImage(image);
if (didFinishRenderingFullSizeImage != nil) {
if (hasPainting && !hasAnimation) {
didFinishRenderingFullSizeImage(image);
} else if (intent == TGPhotoEditorControllerWallpaperIntent) {
didFinishRenderingFullSizeImage(nil);
}
}
return image;
}
@ -1155,6 +1170,13 @@
_portraitToolbarView.alpha = 1.0f;
_landscapeToolbarView.alpha = 1.0f;
} completion:nil];
if (_intent == TGPhotoEditorControllerWallpaperIntent) {
[UIView animateWithDuration:0.25f delay:0.15 options:UIViewAnimationOptionCurveLinear animations:^
{
_backgroundView.alpha = 1.0f;
} completion:nil];
}
}
- (void)transitionOutSaving:(bool)saving completion:(void (^)(void))completion
@ -1170,6 +1192,13 @@
_landscapeToolbarView.alpha = 0.0f;
}];
if (_intent == TGPhotoEditorControllerWallpaperIntent) {
[UIView animateWithDuration:0.1f animations:^
{
_backgroundView.alpha = 0.0f;
}];
}
_currentTabController.beginTransitionOut = self.beginTransitionOut;
[self setToolbarHidden:false animated:true];

View File

@ -28,6 +28,9 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
UIView *_transitionInReferenceView;
UIView *_transitionInParentView;
CGRect _transitionTargetFrame;
UIView *_upperTransitionView;
CGRect _upperTransitionTargetFrame;
}
@end
@ -114,6 +117,9 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
_dismissing = false;
CGRect targetFrame = [self _targetFrameForTransitionInFromFrame:referenceFrame];
if (self.intent == TGPhotoEditorControllerWallpaperIntent) {
targetFrame = [self.view convertRect:targetFrame toView: parentView];
}
if (_CGRectEqualToRectWithEpsilon(targetFrame, referenceFrame, FLT_EPSILON))
{
@ -157,12 +163,20 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
_transitionView = referenceView;
}
transitionViewSuperview = parentView;
if (self.intent == TGPhotoEditorControllerWallpaperIntent) {
_upperTransitionView = [referenceView snapshotViewAfterScreenUpdates:false];
_upperTransitionView.alpha = 0.0;
_upperTransitionView.frame = [parentView convertRect:referenceFrame toView:self.view];
_upperTransitionTargetFrame = [self _targetFrameForTransitionInFromFrame:referenceFrame];
[self.view insertSubview:_upperTransitionView atIndex:0];
}
}
_transitionView.hidden = false;
_transitionView.frame = referenceFrame;
_transitionTargetFrame = [self _targetFrameForTransitionInFromFrame:referenceFrame];
_transitionTargetFrame = targetFrame;
[transitionViewSuperview addSubview:_transitionView];
}
@ -174,6 +188,9 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
_transitionInProgress = true;
CGAffineTransform initialTransform = _transitionView.transform;
[UIView animateWithDuration:0.25 animations:^{
_upperTransitionView.alpha = 1.0;
}];
[UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionLayoutSubviews animations:^
{
if (_animateScale) {
@ -182,6 +199,7 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
_transitionView.transform = CGAffineTransformScale(initialTransform, scale, scale);
} else {
_transitionView.frame = _transitionTargetFrame;
_upperTransitionView.frame = _upperTransitionTargetFrame;
}
} completion:^(BOOL finished) {
_transitionInProgress = false;
@ -201,6 +219,8 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
}
[self _finishedTransitionInWithView:transitionView];
[_upperTransitionView removeFromSuperview];
_upperTransitionView = nil;
}];
}
@ -275,7 +295,11 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
if (saving)
{
[self _animatePreviewViewTransitionOutToFrame:CGRectNull saving:saving parentView:parentView completion:^
CGRect targetFrame = CGRectNull;
if (self.intent == TGPhotoEditorControllerWallpaperIntent) {
targetFrame = referenceFrame;
}
[self _animatePreviewViewTransitionOutToFrame:targetFrame saving:saving parentView:parentView completion:^
{
if (completion != nil)
completion();
@ -316,6 +340,9 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
orientation = UIInterfaceOrientationPortrait;
CGRect sourceFrame = [self transitionOutSourceFrameForReferenceFrame:referenceView.frame orientation:orientation];
if (self.intent == TGPhotoEditorControllerWallpaperIntent) {
sourceFrame = [self.view convertRect:sourceFrame toView: parentView];
}
CGRect targetFrame = referenceFrame;
toTransitionView.frame = sourceFrame;
@ -334,7 +361,12 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
};
[animations addObject:@1];
[self _animatePreviewViewTransitionOutToFrame:targetFrame saving:saving parentView:nil completion:^
CGRect previewTargetFrame = targetFrame;
if (self.intent == TGPhotoEditorControllerWallpaperIntent) {
previewTargetFrame = [referenceView convertRect:referenceView.bounds toView:self.view];
}
[self _animatePreviewViewTransitionOutToFrame:previewTargetFrame saving:saving parentView:nil completion:^
{
onAnimationCompletion(@1);
}];

View File

@ -6,7 +6,8 @@
#import <AVFoundation/AVFoundation.h>
#import <Accelerate/Accelerate.h>
const CGSize TGPhotoEditorResultImageMaxSize = { 2560, 2560 };
const CGSize TGPhotoEditorResultImageMaxSize = { 1280, 1280 };
const CGSize TGPhotoEditorResultImageWallpaperMaxSize = { 2048, 2048 };
const CGSize TGPhotoEditorScreenImageHardLimitSize = { 1280, 1280 };
const CGSize TGPhotoEditorScreenImageHardLimitLegacySize = { 750, 750 };

View File

@ -454,24 +454,40 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
UIView *snapshotView = nil;
POPSpringAnimation *snapshotAnimation = nil;
if (saving && CGRectIsNull(targetFrame) && parentView != nil)
if (saving && parentView != nil)
{
snapshotView = [previewView snapshotViewAfterScreenUpdates:false];
snapshotView.frame = previewView.frame;
CGSize fittedSize = TGScaleToSize(previewView.frame.size, self.view.frame.size);
targetFrame = CGRectMake((self.view.frame.size.width - fittedSize.width) / 2, (self.view.frame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
[parentView addSubview:snapshotView];
snapshotAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewFrame];
snapshotAnimation.fromValue = [NSValue valueWithCGRect:snapshotView.frame];
snapshotAnimation.toValue = [NSValue valueWithCGRect:targetFrame];
if (CGRectIsNull(targetFrame)) {
snapshotView = [previewView snapshotViewAfterScreenUpdates:false];
snapshotView.frame = previewView.frame;
CGSize fittedSize = TGScaleToSize(previewView.frame.size, self.view.frame.size);
targetFrame = CGRectMake((self.view.frame.size.width - fittedSize.width) / 2, (self.view.frame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
[parentView addSubview:snapshotView];
snapshotAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewFrame];
snapshotAnimation.fromValue = [NSValue valueWithCGRect:snapshotView.frame];
snapshotAnimation.toValue = [NSValue valueWithCGRect:targetFrame];
} else if (self.intent == TGPhotoEditorControllerWallpaperIntent) {
snapshotView = [previewView snapshotViewAfterScreenUpdates:false];
snapshotView.frame = [self.view convertRect:previewView.frame toView:parentView];
[parentView addSubview:snapshotView];
snapshotAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewFrame];
snapshotAnimation.fromValue = [NSValue valueWithCGRect:snapshotView.frame];
snapshotAnimation.toValue = [NSValue valueWithCGRect:targetFrame];
}
}
CGRect previewTargetFrame = targetFrame;
if (self.intent == TGPhotoEditorControllerWallpaperIntent && saving) {
previewTargetFrame = [parentView convertRect:targetFrame toView:self.view];
}
POPSpringAnimation *previewAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewFrame];
previewAnimation.fromValue = [NSValue valueWithCGRect:previewView.frame];
previewAnimation.toValue = [NSValue valueWithCGRect:targetFrame];
previewAnimation.toValue = [NSValue valueWithCGRect:previewTargetFrame];
POPSpringAnimation *previewAlphaAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewAlpha];
previewAlphaAnimation.fromValue = @(previewView.alpha);

View File

@ -283,7 +283,7 @@
}
}
+ (void)presentEditorWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item fromRect:(CGRect)fromRect mainSnapshot:(UIView *)mainSnapshot snapshots:(NSArray *)snapshots completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed
+ (void)presentEditorWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller withItem:(id<TGMediaEditableItem>)item cropRect:(CGRect)cropRect adjustments:(id<TGMediaEditAdjustments>)adjustments referenceView:(UIView *)referenceView completion:(void (^)(UIImage *, id<TGMediaEditAdjustments>))completion fullSizeCompletion:(void (^)(UIImage *))fullSizeCompletion beginTransitionOut:(void (^)())beginTransitionOut finishTransitionOut:(void (^)())finishTransitionOut;
{
id<LegacyComponentsOverlayWindowManager> windowManager = [context makeOverlayWindowManager];
@ -291,40 +291,67 @@
UIImage *thumbnailImage;
TGPhotoEditorController *editorController = [[TGPhotoEditorController alloc] initWithContext:[windowManager context] item:item intent:TGPhotoEditorControllerWallpaperIntent adjustments:nil caption:nil screenImage:thumbnailImage availableTabs:TGPhotoEditorToolsTab selectedTab:TGPhotoEditorToolsTab];
NSDictionary *toolValues;
if (adjustments != nil) {
toolValues = adjustments.toolValues;
} else {
toolValues = @{};
}
PGPhotoEditorValues *editorValues = [PGPhotoEditorValues editorValuesWithOriginalSize:item.originalSize cropRect:cropRect cropRotation:0.0f cropOrientation:UIImageOrientationUp cropLockedAspectRatio:0.0 cropMirrored:false toolValues:toolValues paintingData:nil sendAsGif:false];
TGPhotoEditorController *editorController = [[TGPhotoEditorController alloc] initWithContext:[windowManager context] item:item intent:TGPhotoEditorControllerWallpaperIntent adjustments:editorValues caption:nil screenImage:thumbnailImage availableTabs:TGPhotoEditorToolsTab selectedTab:TGPhotoEditorToolsTab];
editorController.editingContext = editingContext;
editorController.dontHideStatusBar = true;
editorController.ignoreCropForResult = true;
editorController.beginTransitionIn = ^UIView *(CGRect *referenceFrame, __unused UIView **parentView)
CGRect fromRect = referenceView.frame;// [referenceView convertRect:referenceView.bounds toView:nil];
editorController.beginTransitionIn = ^UIView *(CGRect *referenceFrame, UIView **parentView)
{
*referenceFrame = fromRect;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:fromRect];
*parentView = referenceView.superview;
//UIImageView *imageView = [[UIImageView alloc] initWithFrame:fromRect];
//imageView.image = image;
return imageView;
return referenceView;
};
editorController.beginTransitionOut = ^UIView *(CGRect *referenceFrame, __unused UIView **parentView)
editorController.beginTransitionOut = ^UIView *(CGRect *referenceFrame, UIView **parentView)
{
CGRect startFrame = CGRectZero;
if (referenceFrame != NULL)
{
startFrame = *referenceFrame;
*referenceFrame = fromRect;
*parentView = referenceView.superview;
}
//[strongSelf transitionBackFromResultControllerWithReferenceFrame:startFrame];
if (beginTransitionOut) {
beginTransitionOut();
}
return nil; //strongSelf->_previewView;
return referenceView;
};
__weak TGPhotoEditorController *weakController = editorController;
editorController.finishedTransitionOut = ^(bool saved) {
TGPhotoEditorController *strongGalleryController = weakController;
if (strongGalleryController != nil && strongGalleryController.overlayWindow == nil)
{
TGNavigationController *navigationController = (TGNavigationController *)strongGalleryController.navigationController;
TGOverlayControllerWindow *window = (TGOverlayControllerWindow *)navigationController.view.window;
if ([window isKindOfClass:[TGOverlayControllerWindow class]])
[window dismiss];
}
if (finishTransitionOut) {
finishTransitionOut();
}
};
editorController.didFinishRenderingFullSizeImage = ^(UIImage *resultImage)
{
fullSizeCompletion(resultImage);
};
__weak TGPhotoEditorController *weakController = editorController;
editorController.didFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges, void(^commit)(void))
{
if (!hasChanges)
@ -334,6 +361,8 @@
if (strongController == nil)
return;
completion(resultImage, adjustments);
};
editorController.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem)
{
@ -347,17 +376,7 @@
editorController.requestOriginalFullSizeImage = ^(id<TGMediaEditableItem> editableItem, NSTimeInterval position)
{
if (editableItem.isVideo) {
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
return ((TGCameraCapturedVideo *)editableItem).avAsset;
} else {
return [editableItem originalImageSignal:position];
}
} else {
return [editableItem originalImageSignal:position];
}
return [editableItem originalImageSignal:position];
};
TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:editorController];

View File

@ -63,9 +63,8 @@ public enum LegacyMediaEditorMode {
case adjustments
}
public func legacyWallpaperEditor(context: AccountContext, image: UIImage, fromRect: CGRect, mainSnapshot: UIView, snapshots: [UIView], transitionCompletion: (() -> Void)?, completion: @escaping (UIImage, TGMediaEditAdjustments?) -> Void, present: @escaping (ViewController, Any?) -> Void) {
let item = TGCameraCapturedPhoto(existing: image)
public func legacyWallpaperEditor(context: AccountContext, item: TGMediaEditableItem, cropRect: CGRect, adjustments: TGMediaEditAdjustments?, referenceView: UIView, beginTransitionOut: (() -> Void)?, finishTransitionOut: (() -> Void)?, completion: @escaping (UIImage?, TGMediaEditAdjustments?) -> Void, fullSizeCompletion: @escaping (UIImage?) -> Void, present: @escaping (ViewController, Any?) -> Void) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
legacyController.blocksBackgroundWhenInOverlay = true
@ -85,17 +84,17 @@ public func legacyWallpaperEditor(context: AccountContext, image: UIImage, fromR
present(legacyController, nil)
TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, withItem: item, from: fromRect, mainSnapshot: mainSnapshot, snapshots: snapshots as [Any], completion: { item, editingContext in
let adjustments = editingContext?.adjustments(for: item)
if let imageSignal = editingContext?.fullSizeImageUrl(for: item) {
imageSignal.start(next: { value in
if let value = value as? NSURL, let data = try? Data(contentsOf: value as URL), let image = UIImage(data: data) {
completion(image, adjustments)
}
}, error: { _ in }, completed: {})
TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, with: item, cropRect: cropRect, adjustments: adjustments, referenceView: referenceView, completion: { image, adjustments in
completion(image, adjustments)
}, fullSizeCompletion: { image in
Queue.mainQueue().async {
fullSizeCompletion(image)
}
}, dismissed: { [weak legacyController] in
}, beginTransitionOut: {
beginTransitionOut?()
}, finishTransitionOut: { [weak legacyController] in
legacyController?.dismiss()
finishTransitionOut?()
})
}

View File

@ -303,7 +303,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
var intensity: Int32?
if let brightness {
intensity = max(1, Int32(brightness * 100.0))
intensity = max(0, min(100, Int32(brightness * 100.0)))
}
let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: intensity)
@ -318,3 +318,77 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
return croppedImage
}).start()
}
class LegacyWallpaperItem: NSObject, TGMediaEditableItem, TGMediaSelectableItem {
var isVideo: Bool {
return false
}
var uniqueIdentifier: String! {
return self.asset.localIdentifier
}
let asset: PHAsset
let screenImage: UIImage
private(set) var thumbnailResource: TelegramMediaResource?
private(set) var imageResource: TelegramMediaResource?
let dimensions: CGSize
init(asset: PHAsset, screenImage: UIImage, dimensions: CGSize) {
self.asset = asset
self.screenImage = screenImage
self.dimensions = dimensions
}
var originalSize: CGSize {
return self.dimensions
}
func thumbnailImageSignal() -> SSignal! {
return SSignal.complete()
// return SSignal(generator: { subscriber -> SDisposable? in
// let disposable = self.thumbnailImage.start(next: { image in
// subscriber.putNext(image)
// subscriber.putCompletion()
// })
//
// return SBlockDisposable(block: {
// disposable.dispose()
// })
// })
}
func screenImageSignal(_ position: TimeInterval) -> SSignal! {
return SSignal.single(self.screenImage)
}
var originalImage: Signal<UIImage, NoError> {
return fetchPhotoLibraryImage(localIdentifier: self.asset.localIdentifier, thumbnail: false)
|> filter { value in
return !(value?.1 ?? true)
}
|> mapToSignal { result -> Signal<UIImage, NoError> in
if let result = result {
return .single(result.0)
} else {
return .complete()
}
}
}
func originalImageSignal(_ position: TimeInterval) -> SSignal! {
return SSignal(generator: { subscriber -> SDisposable? in
let disposable = self.originalImage.start(next: { image in
subscriber.putNext(image)
if !image.degraded() {
subscriber.putCompletion()
}
})
return SBlockDisposable(block: {
disposable.dispose()
})
})
}
}

View File

@ -4,7 +4,7 @@ import Display
import AsyncDisplayKit
final class WallpaperCropNode: ASDisplayNode, UIScrollViewDelegate {
private let scrollNode: ASScrollNode
let scrollNode: ASScrollNode
private var ignoreZoom = false
private var ignoreZoomTransition: ContainedViewLayoutTransition?

View File

@ -167,10 +167,16 @@ private func updatedFileWallpaper(id: Int64? = nil, accessHash: Int64? = nil, sl
}
class WallpaperGalleryInteraction {
let editMedia: (UIImage, CGRect, UIView, [UIView], @escaping (UIImage, TGMediaEditAdjustments?) -> Void) -> Void
let editMedia: (PHAsset, UIImage, CGRect, TGMediaEditAdjustments?, UIView, @escaping (UIImage?, TGMediaEditAdjustments?) -> Void, @escaping (UIImage?) -> Void) -> Void
let beginTransitionToEditor: () -> Void
let beginTransitionFromEditor: () -> Void
let finishTransitionFromEditor: () -> Void
init(editMedia: @escaping (UIImage, CGRect, UIView, [UIView], @escaping (UIImage, TGMediaEditAdjustments?) -> Void) -> Void) {
init(editMedia: @escaping (PHAsset, UIImage, CGRect, TGMediaEditAdjustments?, UIView, @escaping (UIImage?, TGMediaEditAdjustments?) -> Void, @escaping (UIImage?) -> Void) -> Void, beginTransitionToEditor: @escaping () -> Void, beginTransitionFromEditor: @escaping () -> Void, finishTransitionFromEditor: @escaping () -> Void) {
self.editMedia = editMedia
self.beginTransitionToEditor = beginTransitionToEditor
self.beginTransitionFromEditor = beginTransitionFromEditor
self.finishTransitionFromEditor = finishTransitionFromEditor
}
}
@ -242,25 +248,50 @@ public class WallpaperGalleryController: ViewController {
//self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
self.interaction = WallpaperGalleryInteraction(editMedia: { [weak self] image, fromRect, mainSnapshot, snapshots, apply in
self.interaction = WallpaperGalleryInteraction(editMedia: { [weak self] asset, image, cropRect, adjustments, referenceView, apply, fullSizeApply in
guard let self else {
return
}
var snapshots = snapshots
if let toolbarNode = self.toolbarNode, let snapshotView = toolbarNode.view.snapshotContentTree() {
snapshotView.frame = toolbarNode.view.convert(toolbarNode.view.bounds, to: nil)
snapshots.append(snapshotView)
}
legacyWallpaperEditor(context: context, image: image, fromRect: fromRect, mainSnapshot: mainSnapshot, snapshots: snapshots, transitionCompletion: {
let item = LegacyWallpaperItem(asset: asset, screenImage: image, dimensions: CGSize(width: asset.pixelWidth, height: asset.pixelHeight))
legacyWallpaperEditor(context: context, item: item, cropRect: cropRect, adjustments: adjustments, referenceView: referenceView, beginTransitionOut: { [weak self] in
self?.interaction?.beginTransitionFromEditor()
}, finishTransitionOut: { [weak self] in
self?.interaction?.finishTransitionFromEditor()
}, completion: { image, adjustments in
apply(image, adjustments)
}, fullSizeCompletion: { image in
fullSizeApply(image)
}, present: { [weak self] c, a in
if let self {
self.present(c, in: .window(.root))
}
})
}, beginTransitionToEditor: { [weak self] in
guard let self else {
return
}
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
if let toolbarNode = self.toolbarNode {
transition.updateAlpha(node: toolbarNode, alpha: 0.0)
}
}, beginTransitionFromEditor: { [weak self] in
guard let self else {
return
}
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
if let toolbarNode = self.toolbarNode {
transition.updateAlpha(node: toolbarNode, alpha: 1.0)
}
if let centralItemNode = self.galleryNode.pager.centralItemNode() as? WallpaperGalleryItemNode {
centralItemNode.beginTransitionFromEditor()
}
}, finishTransitionFromEditor: { [weak self] in
guard let self else {
return
}
if let centralItemNode = self.galleryNode.pager.centralItemNode() as? WallpaperGalleryItemNode {
centralItemNode.finishTransitionFromEditor()
}
})
var entries: [WallpaperGalleryEntry] = []
@ -491,7 +522,7 @@ public class WallpaperGalleryController: ViewController {
let entry = strongSelf.entries[centralItemNode.index]
if case .peer = strongSelf.mode {
strongSelf.apply?(entry, options, centralItemNode.editedImage, centralItemNode.cropRect, centralItemNode.brightness)
strongSelf.apply?(entry, options, centralItemNode.editedFullSizeImage, centralItemNode.editedCropRect, centralItemNode.brightness)
return
}

View File

@ -99,6 +99,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let wrapperNode: ASDisplayNode
let imageNode: TransformImageNode
private let temporaryImageNode: ASImageNode
let nativeNode: WallpaperBackgroundNode
let brightnessNode: ASDisplayNode
private let statusNode: RadialStatusNode
@ -110,6 +111,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
private let dayNightButtonNode: WallpaperNavigationButtonNode
private let editButtonNode: WallpaperNavigationButtonNode
private let buttonsContainerNode: SparseNode
private let blurButtonNode: WallpaperOptionButtonNode
private let motionButtonNode: WallpaperOptionButtonNode
private let patternButtonNode: WallpaperOptionButtonNode
@ -159,6 +161,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.wrapperNode = ASDisplayNode()
self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = .subsequentUpdates
self.temporaryImageNode = ASImageNode()
self.temporaryImageNode.isUserInteractionEnabled = false
self.nativeNode = createWallpaperBackgroundNode(context: context, forChatDisplay: false)
self.cropNode = WallpaperCropNode()
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
@ -173,6 +177,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
self.messagesContainerNode.isUserInteractionEnabled = false
self.buttonsContainerNode = SparseNode()
self.blurButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_Blurred, value: .check(false))
self.blurButtonNode.setEnabled(false)
self.motionButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_Motion, value: .check(false))
@ -248,20 +253,22 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.imageNode.clipsToBounds = true
self.addSubnode(self.wrapperNode)
self.addSubnode(self.temporaryImageNode)
//self.addSubnode(self.statusNode)
self.addSubnode(self.serviceBackgroundNode)
self.addSubnode(self.messagesContainerNode)
self.addSubnode(self.buttonsContainerNode)
self.addSubnode(self.blurButtonNode)
self.addSubnode(self.motionButtonNode)
self.addSubnode(self.patternButtonNode)
self.addSubnode(self.colorsButtonNode)
self.addSubnode(self.playButtonNode)
self.addSubnode(self.sliderNode)
self.addSubnode(self.cancelButtonNode)
self.addSubnode(self.shareButtonNode)
self.addSubnode(self.dayNightButtonNode)
self.addSubnode(self.editButtonNode)
self.buttonsContainerNode.addSubnode(self.blurButtonNode)
self.buttonsContainerNode.addSubnode(self.motionButtonNode)
self.buttonsContainerNode.addSubnode(self.patternButtonNode)
self.buttonsContainerNode.addSubnode(self.colorsButtonNode)
self.buttonsContainerNode.addSubnode(self.playButtonNode)
self.buttonsContainerNode.addSubnode(self.sliderNode)
self.buttonsContainerNode.addSubnode(self.cancelButtonNode)
self.buttonsContainerNode.addSubnode(self.shareButtonNode)
self.buttonsContainerNode.addSubnode(self.dayNightButtonNode)
self.buttonsContainerNode.addSubnode(self.editButtonNode)
self.imageNode.addSubnode(self.brightnessNode)
@ -295,25 +302,31 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
switch entry {
case .asset, .contextResult:
if let editedImage = self.editedImage {
let scale = editedImage.size.height / self.cropNode.cropRect.height
let cropRect = self.cropNode.cropRect
return CGRect(origin: CGPoint(x: cropRect.minX * scale, y: cropRect.minY * scale), size: CGSize(width: cropRect.width * scale, height: cropRect.height * scale))
} else {
return self.cropNode.cropRect
}
return self.cropNode.cropRect
default:
return nil
}
}
var editedCropRect: CGRect? {
guard let cropRect = self.cropRect, let contentSize = self.contentSize else {
return nil
}
if let editedFullSizeImage = self.editedFullSizeImage {
let scale = editedFullSizeImage.size.height / contentSize.height
return CGRect(origin: CGPoint(x: cropRect.minX * scale, y: cropRect.minY * scale), size: CGSize(width: cropRect.width * scale, height: cropRect.height * scale))
} else {
return cropRect
}
}
var brightness: CGFloat? {
guard let entry = self.entry else {
return nil
}
switch entry {
case .asset, .contextResult:
return self.sliderNode.value
return 1.0 - self.sliderNode.value
default:
return nil
}
@ -467,67 +480,56 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
@objc private func editPressed() {
guard let image = self.imageNode.image else {
guard let image = self.imageNode.image, case let .asset(asset) = self.entry else {
return
}
let originalImage = self.originalImage ?? image
var nodesToSnapshot = [
self.cancelButtonNode,
self.editButtonNode,
self.blurButtonNode,
self.motionButtonNode,
self.serviceBackgroundNode
]
if let messageNodes = self.messageNodes {
for node in messageNodes {
nodesToSnapshot.append(node)
guard let cropRect = self.cropRect else {
return
}
self.interaction?.editMedia(asset, originalImage, cropRect, self.currentAdjustments, self.cropNode.view, { [weak self] result, adjustments in
guard let self else {
return
}
}
var snapshots: [UIView] = []
for node in nodesToSnapshot {
if let snapshotView = node.view.snapshotContentTree() {
snapshotView.frame = node.view.convert(node.view.bounds, to: nil)
snapshots.append(snapshotView)
}
}
if let snapshotView = self.dayNightButtonNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.dayNightButtonNode.view.convert(self.dayNightButtonNode.view.bounds, to: nil)
snapshots.append(snapshotView)
}
let mainSnapshotView: UIView
if let snapshotView = self.imageNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.imageNode.view.convert(self.imageNode.view.bounds, to: nil)
mainSnapshotView = snapshotView
} else {
mainSnapshotView = UIView()
}
let fromRect = self.imageNode.view.convert(self.imageNode.bounds, to: nil)
self.interaction?.editMedia(originalImage, fromRect, mainSnapshotView, snapshots, { [weak self] result, adjustments in
self?.originalImage = originalImage
self?.editedImage = result
self?.currentAdjustments = adjustments
self.originalImage = originalImage
self.editedImage = result
self.currentAdjustments = adjustments
self?.imageNode.setSignal(.single({ arguments in
self.imageNode.setSignal(.single({ arguments in
let context = DrawingContext(size: arguments.drawingSize, opaque: false)
context?.withFlippedContext({ context in
if let cgImage = result.cgImage {
let image = result ?? originalImage
if let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: .zero, size: arguments.drawingSize))
}
})
return context
}))
self.temporaryImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, delay: 0.2, removeOnCompletion: false, completion: { [weak self] _ in
self?.temporaryImageNode.image = nil
self?.temporaryImageNode.layer.removeAllAnimations()
})
}, { [weak self] image in
guard let self else {
return
}
self.editedFullSizeImage = image
self.temporaryImageNode.frame = self.imageNode.view.convert(self.imageNode.bounds, to: self.view)
self.temporaryImageNode.image = image ?? originalImage
if self.cropNode.isHidden {
self.temporaryImageNode.alpha = 0.0
}
})
self.beginTransitionToEditor()
}
private var originalImage: UIImage?
public private(set) var editedImage: UIImage?
public private(set) var editedFullSizeImage: UIImage?
private var currentAdjustments: TGMediaEditAdjustments?
private func animateIntensityChange(delay: Double) {
@ -557,6 +559,29 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
}
func beginTransitionToEditor() {
self.cropNode.isHidden = true
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
transition.updateAlpha(node: self.messagesContainerNode, alpha: 0.0)
transition.updateAlpha(node: self.buttonsContainerNode, alpha: 0.0)
transition.updateAlpha(node: self.serviceBackgroundNode, alpha: 0.0)
self.interaction?.beginTransitionToEditor()
}
func beginTransitionFromEditor() {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
transition.updateAlpha(node: self.messagesContainerNode, alpha: 1.0)
transition.updateAlpha(node: self.buttonsContainerNode, alpha: 1.0)
transition.updateAlpha(node: self.serviceBackgroundNode, alpha: 1.0)
}
func finishTransitionFromEditor() {
self.cropNode.isHidden = false
self.temporaryImageNode.alpha = 1.0
}
@objc private func cancelPressed() {
self.dismiss()
}
@ -579,11 +604,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
var showPreviewTooltip = false
if self.entry != entry || self.arguments.colorPreview != previousArguments.colorPreview {
let previousEntry = self.entry
self.entry = entry
if previousEntry != entry {
self.preparePatternEditing()
}
self.colorsButtonNode.colors = self.calculateGradientColors() ?? defaultBuiltinWallpaperGradientColors
@ -1204,9 +1225,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
}
private func preparePatternEditing() {
}
func setMotionEnabled(_ enabled: Bool, animated: Bool) {
if enabled {
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
@ -1606,6 +1624,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.wrapperNode.bounds = CGRect(origin: CGPoint(), size: layout.size)
self.updateWrapperLayout(layout: layout, offset: offset, transition: transition)
self.messagesContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.buttonsContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
if self.cropNode.supernode == nil {
self.imageNode.frame = self.wrapperNode.bounds

View File

@ -13,23 +13,17 @@ public final class PeerMediaUploadingItem: Equatable {
case generic
}
public enum PreviousState: Equatable {
case wallpaper(TelegramWallpaper?)
}
public enum Content: Equatable {
case wallpaper(TelegramWallpaper)
}
public let content: Content
public let messageId: EngineMessage.Id?
public let previousState: PreviousState?
public let progress: Float
init(content: Content, messageId: EngineMessage.Id?, previousState: PreviousState?, progress: Float) {
init(content: Content, messageId: EngineMessage.Id?, progress: Float) {
self.content = content
self.messageId = messageId
self.previousState = previousState
self.progress = progress
}
@ -40,9 +34,6 @@ public final class PeerMediaUploadingItem: Equatable {
if lhs.messageId != rhs.messageId {
return false
}
if lhs.previousState != rhs.previousState {
return false
}
if lhs.progress != rhs.progress {
return false
}
@ -50,15 +41,11 @@ public final class PeerMediaUploadingItem: Equatable {
}
func withMessageId(_ messageId: EngineMessage.Id) -> PeerMediaUploadingItem {
return PeerMediaUploadingItem(content: self.content, messageId: messageId, previousState: self.previousState, progress: self.progress)
return PeerMediaUploadingItem(content: self.content, messageId: messageId, progress: self.progress)
}
func withProgress(_ progress: Float) -> PeerMediaUploadingItem {
return PeerMediaUploadingItem(content: self.content, messageId: self.messageId, previousState: self.previousState, progress: progress)
}
func withPreviousState(_ previousState: PreviousState?) -> PeerMediaUploadingItem {
return PeerMediaUploadingItem(content: self.content, messageId: self.messageId, previousState: previousState, progress: self.progress)
return PeerMediaUploadingItem(content: self.content, messageId: self.messageId, progress: progress)
}
}
@ -129,38 +116,6 @@ private func generatePeerMediaMessage(network: Network, accountPeerId: EnginePee
return StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: accountPeerId, text: "", attributes: attributes, media: media)
}
private func preparePeerMediaUpload(transaction: Transaction, peerId: EnginePeer.Id, content: PeerMediaUploadingItem.Content) -> PeerMediaUploadingItem.PreviousState? {
var previousState: PeerMediaUploadingItem.PreviousState?
switch content {
case let .wallpaper(wallpaper):
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
if let cachedData = cachedData as? CachedUserData {
previousState = .wallpaper(cachedData.wallpaper)
return cachedData.withUpdatedWallpaper(wallpaper)
} else {
return cachedData
}
})
}
return previousState
}
private func cancelPeerMediaUpload(transaction: Transaction, peerId: EnginePeer.Id, previousState: PeerMediaUploadingItem.PreviousState?) {
guard let previousState = previousState else {
return
}
switch previousState {
case let .wallpaper(previousWallpaper):
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
if let cachedData = cachedData as? CachedUserData {
return cachedData.withUpdatedWallpaper(previousWallpaper)
} else {
return cachedData
}
})
}
}
private final class PendingPeerMediaUploadContext {
var value: PeerMediaUploadingItem
let disposable = MetaDisposable()
@ -225,98 +180,93 @@ private final class PendingPeerMediaUploadManagerImpl {
let accountPeerId = self.accountPeerId
let queue = self.queue
let context = PendingPeerMediaUploadContext(value: PeerMediaUploadingItem(content: content, messageId: nil, previousState: nil, progress: 0.0))
let context = PendingPeerMediaUploadContext(value: PeerMediaUploadingItem(content: content, messageId: nil, progress: 0.0))
self.contexts[peerId] = context
context.disposable.set(
(self.postbox.transaction({ transaction -> (EngineMessage.Id, PeerMediaUploadingItem.PreviousState?)? in
(self.postbox.transaction({ transaction -> EngineMessage.Id? in
let storeMessage = generatePeerMediaMessage(network: network, accountPeerId: accountPeerId, transaction: transaction, peerId: peerId, content: content)
let globallyUniqueIdToMessageId = transaction.addMessages([storeMessage], location: .Random)
guard let globallyUniqueId = storeMessage.globallyUniqueId, let messageId = globallyUniqueIdToMessageId[globallyUniqueId] else {
return nil
}
let previousState = preparePeerMediaUpload(transaction: transaction, peerId: peerId, content: content)
return (messageId, previousState)
return messageId
})
|> deliverOn(queue)).start(next: { [weak self, weak context] messageIdAndPreviousState in
|> deliverOn(queue)).start(next: { [weak self, weak context] messageId in
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
guard let (messageId, previousState) = messageIdAndPreviousState else {
guard let messageId = messageId else {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
return
}
context.value = context.value.withMessageId(messageId).withPreviousState(previousState)
context.value = context.value.withMessageId(messageId)
strongSelf.updateValues()
context.disposable.set((uploadPeerMedia(postbox: postbox, network: network, stateManager: stateManager, peerId: peerId, content: content)
|> deliverOn(queue)).start(next: { [weak self, weak context] value in
queue.async {
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
switch value {
case let .done(result):
context.disposable.set(
(postbox.transaction({ transaction -> Message? in
return transaction.getMessage(messageId)
})
|> deliverOn(queue)
).start(next: { [weak self, weak context] message in
guard let strongSelf = self, let initialContext = context else {
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
switch value {
case let .done(result):
context.disposable.set(
(postbox.transaction({ transaction -> Message? in
return transaction.getMessage(messageId)
})
|> deliverOn(queue)
).start(next: { [weak self, weak context] message in
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
guard let message = message else {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
guard let message = message else {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
return
}
context.disposable.set(
(applyUpdateMessage(
postbox: postbox,
stateManager: stateManager,
message: message,
cacheReferenceKey: nil,
result: result,
accountPeerId: accountPeerId
)
|> deliverOn(queue)).start(completed: { [weak self, weak context] in
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
}
})
context.disposable.set(
(applyUpdateMessage(
postbox: postbox,
stateManager: stateManager,
message: message,
cacheReferenceKey: nil,
result: result,
accountPeerId: accountPeerId
)
}
})
)
strongSelf.updateValues()
case let .progress(progress):
context.value = context.value.withProgress(progress)
strongSelf.updateValues()
}
|> deliverOn(queue)).start(completed: { [weak self, weak context] in
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
}
})
)
}
})
)
strongSelf.updateValues()
case let .progress(progress):
context.value = context.value.withProgress(progress)
strongSelf.updateValues()
}
}
}, error: { [weak self, weak context] error in
queue.async {
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
}
guard let strongSelf = self, let initialContext = context else {
return
}
if let context = strongSelf.contexts[peerId], context === initialContext {
strongSelf.contexts.removeValue(forKey: peerId)
context.disposable.dispose()
strongSelf.updateValues()
}
}))
}
@ -330,7 +280,6 @@ private final class PendingPeerMediaUploadManagerImpl {
if let messageId = context.value.messageId {
context.disposable.set(self.postbox.transaction({ transaction in
cancelPeerMediaUpload(transaction: transaction, peerId: peerId, previousState: context.value.previousState)
transaction.deleteMessages([messageId], forEachMedia: nil)
}).start())
} else {

View File

@ -125,6 +125,14 @@ func _internal_setChatWallpaper(postbox: Postbox, network: Network, stateManager
return .complete()
}
return postbox.transaction { transaction -> Signal<Api.Updates, NoError> in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
return current.withUpdatedWallpaper(wallpaper)
} else {
return current
}
})
var flags: Int32 = 0
var inputWallpaper: Api.InputWallPaper?
var inputSettings: Api.WallPaperSettings?
@ -139,19 +147,10 @@ func _internal_setChatWallpaper(postbox: Postbox, network: Network, stateManager
return .complete()
}
|> mapToSignal { updates -> Signal<Api.Updates, NoError> in
return postbox.transaction { transaction -> Api.Updates in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
return current.withUpdatedWallpaper(wallpaper)
} else {
return current
}
})
if applyUpdates {
stateManager.addUpdates(updates)
}
return updates
if applyUpdates {
stateManager.addUpdates(updates)
}
return .single(updates)
}
} |> switchToLatest
}

View File

@ -1071,7 +1071,13 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
self.cancelButtonNode.theme = presentationData.theme
if let animatingCrossFade = self.animatingCrossFade {
Queue.mainQueue().after(!animatingCrossFade ? ChatThemeScreen.themeCrossfadeDelay * UIView.animationDurationFactor() : 0.0, {
self.cancelButtonNode.setTheme(presentationData.theme, animated: true)
})
} else {
self.cancelButtonNode.setTheme(presentationData.theme, animated: false)
}
let previousIconColors = iconColors(theme: previousTheme)
let newIconColors = iconColors(theme: self.presentationData.theme)
@ -1164,6 +1170,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
}
}
private var animatingCrossFade: Bool?
private func animateCrossfade(animateIcon: Bool) {
if animateIcon, let snapshotView = self.animationNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.animationNode.frame
@ -1174,6 +1181,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
})
}
self.animatingCrossFade = animateIcon
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay * UIView.animationDurationFactor()) {
if let effectView = self.effectNode.view as? UIVisualEffectView {
UIView.animate(withDuration: ChatThemeScreen.themeCrossfadeDuration, delay: 0.0, options: .curveLinear) {
@ -1185,6 +1193,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
let previousColor = self.contentBackgroundNode.backgroundColor ?? .clear
self.contentBackgroundNode.backgroundColor = self.presentationData.theme.actionSheet.itemBackgroundColor
self.contentBackgroundNode.layer.animate(from: previousColor.cgColor, to: (self.contentBackgroundNode.backgroundColor ?? .clear).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: ChatThemeScreen.themeCrossfadeDuration)
self.animatingCrossFade = nil
}
if let snapshotView = self.contentContainerNode.view.snapshotView(afterScreenUpdates: false) {

View File

@ -917,8 +917,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
default:
break
}
if let intensity, intensity < 100 {
dimAlpha = 1.0 - max(0.0, min(1.0, Float(intensity) / 100.0))
if let intensity, intensity > 0 {
dimAlpha = max(0.0, min(1.0, Float(intensity) / 100.0))
}
}
self.dimLayer.opacity = dimAlpha

View File

@ -38,15 +38,20 @@ public class WebAppCancelButtonNode: ASDisplayNode {
public var state: State = .cancel
private var _theme: PresentationTheme
public var theme: PresentationTheme {
didSet {
self.setState(self.state, animated: false, force: true)
get {
return self._theme
}
set {
self._theme = newValue
self.setState(self.state, animated: false, animateScale: false, force: true)
}
}
private let strings: PresentationStrings
public init(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme
self._theme = theme
self.strings = strings
self.buttonNode = HighlightTrackingButtonNode()
@ -55,6 +60,7 @@ public class WebAppCancelButtonNode: ASDisplayNode {
self.arrowNode.displaysAsynchronously = false
self.labelNode = ImmediateTextNode()
self.labelNode.displaysAsynchronously = false
super.init()
@ -82,23 +88,40 @@ public class WebAppCancelButtonNode: ASDisplayNode {
self.setState(.cancel, animated: false, force: true)
}
public func setState(_ state: State, animated: Bool, force: Bool = false) {
public func setTheme(_ theme: PresentationTheme, animated: Bool) {
self._theme = theme
var animated = animated
if self.animatingStateChange {
animated = false
}
self.setState(self.state, animated: animated, animateScale: false, force: true)
}
private var animatingStateChange = false
public func setState(_ state: State, animated: Bool, animateScale: Bool = true, force: Bool = false) {
guard self.state != state || force else {
return
}
self.state = state
if animated, let snapshotView = self.buttonNode.view.snapshotContentTree() {
self.animatingStateChange = true
snapshotView.layer.sublayerTransform = self.buttonNode.subnodeTransform
self.view.addSubview(snapshotView)
snapshotView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.25, removeOnCompletion: false)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak snapshotView] _ in
let duration: Double = animateScale ? 0.25 : 0.3
if animateScale {
snapshotView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.25, removeOnCompletion: false)
}
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
self.animatingStateChange = false
})
self.buttonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
self.buttonNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.25)
if animateScale {
self.buttonNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.25)
}
self.buttonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
self.arrowNode.isHidden = state == .cancel