diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h index dc724dfd84..fb42bcd69d 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h @@ -107,9 +107,6 @@ #import #import #import -#import -#import -#import #import #import #import @@ -125,7 +122,6 @@ #import #import #import -#import #import #import #import @@ -137,7 +133,6 @@ #import #import #import -#import #import #import #import @@ -217,7 +212,6 @@ #import #import #import -#import #import #import #import @@ -280,7 +274,6 @@ #import #import #import -#import #import #import #import diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerControls.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerControls.h deleted file mode 100644 index 1e098c0979..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerControls.h +++ /dev/null @@ -1,51 +0,0 @@ -#import - -@class TGModernButton; -@class TGEmbedPlayerState; - -typedef enum { - TGEmbedPlayerControlsTypeNone, - TGEmbedPlayerControlsTypeSimple, - TGEmbedPlayerControlsTypeFull -} TGEmbedPlayerControlsType; - -typedef enum { - TGEmbedPlayerWatermarkPositionTopLeft, - TGEmbedPlayerWatermarkPositionBottomLeft, - TGEmbedPlayerWatermarkPositionBottomRight -} TGEmbedPlayerWatermarkPosition; - -@interface TGEmbedPlayerControls : UIView - -@property (nonatomic, copy) void (^panelVisibilityChange)(bool hidden); - -@property (nonatomic, copy) void (^playPressed)(void); -@property (nonatomic, copy) void (^pausePressed)(void); -@property (nonatomic, copy) void (^fullscreenPressed)(void); -@property (nonatomic, copy) void (^seekToPosition)(CGFloat position); -@property (nonatomic, copy) void (^pictureInPicturePressed)(void); - -@property (nonatomic, assign) TGEmbedPlayerWatermarkPosition watermarkPosition; -@property (nonatomic, strong) UIImage *watermarkImage; -@property (nonatomic, assign) bool watermarkPrerenderedOpacity; -@property (nonatomic, assign) CGPoint watermarkOffset; -@property (nonatomic, copy) void(^watermarkPressed)(void); - -- (instancetype)initWithFrame:(CGRect)frame type:(TGEmbedPlayerControlsType)type; - -- (void)setWatermarkHidden:(bool)hidden; -- (void)setDisabled; -- (void)hidePlayButton; -- (void)setPictureInPictureHidden:(bool)hidden; - -- (void)showLargePlayButton:(bool)force; - -- (void)setState:(TGEmbedPlayerState *)state; -- (void)notifyOfPlaybackStart; - -- (void)setHidden:(bool)hidden animated:(bool)animated; - -@property (nonatomic, assign) bool inhibitFullscreenButton; -- (void)setFullscreenButtonHidden:(bool)hidden animated:(bool)animated; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerState.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerState.h deleted file mode 100644 index 8a67cb1660..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerState.h +++ /dev/null @@ -1,9 +0,0 @@ -#import -#import "TGPIPAblePlayerView.h" - -@interface TGEmbedPlayerState : NSObject - -+ (instancetype)stateWithPlaying:(bool)playing; -+ (instancetype)stateWithPlaying:(bool)playing duration:(NSTimeInterval)duration position:(NSTimeInterval)position downloadProgress:(CGFloat)downloadProgress buffering:(bool)buffering; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerView.h deleted file mode 100644 index 2178838cf5..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGEmbedPlayerView.h +++ /dev/null @@ -1,105 +0,0 @@ -#import - -#import - -#import -#import -#import -#import -#import - -@class TGEmbedPlayerView; - -@protocol TGEmbedPlayerWrapperView - -- (void)reattachPlayerView; -- (void)reattachPlayerView:(TGEmbedPlayerView *)playerView; - -@end - -@interface TGEmbedPlayerView : UIView -{ - TGWebPageMediaAttachment *_webPage; - - TGMessageImageViewOverlayView *_overlayView; - CGSize _embedSize; -} - -@property (nonatomic, readonly) TGEmbedPlayerState *state; -@property (nonatomic, readonly) TGEmbedPlayerControls *controlsView; -@property (nonatomic, readonly) UIView *dimWrapperView; - -@property (nonatomic, assign) bool disableWatermarkAction; -@property (nonatomic, assign) bool inhibitFullscreenButton; - -@property (nonatomic, assign) UIRectCorner roundCorners; - -@property (nonatomic, assign) bool disallowAutoplay; -@property (nonatomic, assign) bool disallowPIP; -@property (nonatomic, assign) bool disableControls; - -@property (nonatomic, assign) CGRect initialFrame; - -@property (nonatomic, copy) void (^onWatermarkAction)(void); - -@property (nonatomic, copy) void (^requestFullscreen)(NSTimeInterval duration); -@property (nonatomic, copy) void (^onMetadataLoaded)(NSString *title, NSString *subtitle); - -@property (nonatomic, copy) void (^onBeganLoading)(void); -@property (nonatomic, copy) void (^onBeganPlaying)(void); -@property (nonatomic, copy) void (^onRealLoadProgress)(CGFloat progress, NSTimeInterval duration); - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage; -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal; -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal alternateCachePathSignal:(SSignal *)alternateCachePathSignal; -- (void)setupWithEmbedSize:(CGSize)embedSize; - -- (void)setDimmed:(bool)dimmed animated:(bool)animated shouldDelay:(bool)shouldDelay; -- (void)setCoverImage:(UIImage *)image; - -- (void)pauseVideo:(bool)manually; - -- (void)updateState:(TGEmbedPlayerState *)state; - -- (void)hideControls; - -- (void)enterFullscreen:(NSTimeInterval)duration; -- (void)enterPictureInPicture:(TGEmbedPIPCorner)corner; - -- (void)_onPageReady; -- (void)_didBeginPlayback; -- (void)_onPanelAppearance; -- (void)_watermarkAction; - -- (void)_openWebPage:(NSURL *)url; - -- (bool)_scaleViewToMaxSize; - -- (void)onLockInPlace; - -- (bool)_useFakeLoadingProgress; -- (void)setLoadProgress:(CGFloat)value duration:(NSTimeInterval)duration; -- (void)setDimmed:(bool)dimmed animated:(bool)animated; - -- (TGEmbedPlayerControlsType)_controlsType; -- (void)_evaluateJS:(NSString *)jsString completion:(void (^)(NSString *))completion; -- (NSURL *)_embedURL; -- (NSString *)_embedHTML; -- (NSURL *)_baseURL; -- (void)_notifyOfCallbackURL:(NSURL *)url; -- (void)_setupUserScripts:(WKUserContentController *)contentController; -- (bool)_applyViewportUserScript; -- (UIView *)_webView; -- (CGFloat)_compensationEdges; - -- (void)_cleanWebView; - -- (SSignal *)loadProgress; - -+ (bool)_supportsWebPage:(TGWebPageMediaAttachment *)webPage; -+ (bool)hasNativeSupportForX:(TGWebPageMediaAttachment *)webPage; - -+ (Class)playerViewClassForWebPage:(TGWebPageMediaAttachment *)webPage onlySpecial:(bool)onlySpecial; -+ (TGEmbedPlayerView *)makePlayerViewForWebPage:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)signal; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGImagePickerController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGImagePickerController.h deleted file mode 100644 index 9de4561e46..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGImagePickerController.h +++ /dev/null @@ -1,32 +0,0 @@ -#import - -#import - -#ifdef __cplusplus -extern "C" { -#endif - -void dispatchOnAssetsProcessingQueue(dispatch_block_t block); -void sharedAssetsLibraryRetain(); -void sharedAssetsLibraryRelease(); - -#ifdef __cplusplus -} -#endif - -@protocol TGImagePickerControllerDelegate; - -@interface TGImagePickerController : NSObject - -+ (id)sharedAssetsLibrary; -+ (id)preloadLibrary; -+ (void)loadAssetWithUrl:(NSURL *)url completion:(void (^)(ALAsset *asset))completion; -+ (void)storeImageAsset:(NSData *)data; - -@end - -@protocol TGImagePickerControllerDelegate - -- (void)imagePickerController:(TGImagePickerController *)imagePicker didFinishPickingWithAssets:(NSArray *)assets; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLegacyCameraController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLegacyCameraController.h deleted file mode 100644 index 72d8845651..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLegacyCameraController.h +++ /dev/null @@ -1,27 +0,0 @@ -#import - -#import - -@protocol TGLegacyCameraControllerDelegate - -@optional - -- (void)legacyCameraControllerCapturedVideoWithTempFilePath:(NSString *)tempVideoFilePath fileSize:(int32_t)fileSize previewImage:(UIImage *)previewImage duration:(NSTimeInterval)duration dimensions:(CGSize)dimenstions assetUrl:(NSString *)assetUrl; -- (void)legacyCameraControllerCompletedWithExistingMedia:(id)media; -- (void)legacyCameraControllerCompletedWithNoResult; -- (void)legacyCameraControllerCompletedWithDocument:(NSURL *)fileUrl fileName:(NSString *)fileName mimeType:(NSString *)mimeType; - -@end - -@interface TGLegacyCameraController : UIImagePickerController - -@property (nonatomic, copy) void (^finishedWithImage)(UIImage *); - -@property (nonatomic, weak) id completionDelegate; -@property (nonatomic) bool storeCapturedAssets; -@property (nonatomic) bool isInDocumentMode; -@property (nonatomic) bool avatarMode; - -- (instancetype)initWithContext:(id)context; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernGalleryEmbeddedStickersHeaderView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernGalleryEmbeddedStickersHeaderView.h deleted file mode 100644 index 788df0fd88..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernGalleryEmbeddedStickersHeaderView.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface TGModernGalleryEmbeddedStickersHeaderView : UIView - -@property (nonatomic, copy) void (^showEmbeddedStickers)(); - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h index 98f4b11d96..fd0ee10637 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h @@ -20,7 +20,7 @@ @property (nonatomic, readonly) bool isTracking; @property (nonatomic, readonly) bool isAnimating; -- (instancetype)initWithOriginalSize:(CGSize)originalSize screenSize:(CGSize)screenSize fullPreviewView:(PGPhotoEditorView *)fullPreviewView; +- (instancetype)initWithOriginalSize:(CGSize)originalSize screenSize:(CGSize)screenSize fullPreviewView:(PGPhotoEditorView *)fullPreviewView fullPaintingView:(UIImageView *)fullPaintingView; - (void)setSnapshotImage:(UIImage *)image; - (void)setSnapshotView:(UIView *)snapshotView; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGStickerKeyboardTabPanel.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGStickerKeyboardTabPanel.h deleted file mode 100644 index f19f4ceb38..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGStickerKeyboardTabPanel.h +++ /dev/null @@ -1,60 +0,0 @@ -#import - -typedef enum -{ - TGStickerKeyboardViewDefaultStyle, - TGStickerKeyboardViewDarkBlurredStyle, - TGStickerKeyboardViewPaintStyle, - TGStickerKeyboardViewPaintDarkStyle -} TGStickerKeyboardViewStyle; - -@interface TGStickerKeyboardPallete : NSObject - -@property (nonatomic, readonly) UIColor *backgroundColor; -@property (nonatomic, readonly) UIColor *separatorColor; -@property (nonatomic, readonly) UIColor *selectionColor; - -@property (nonatomic, readonly) UIImage *gifIcon; -@property (nonatomic, readonly) UIImage *trendingIcon; -@property (nonatomic, readonly) UIImage *favoritesIcon; -@property (nonatomic, readonly) UIImage *recentIcon; -@property (nonatomic, readonly) UIImage *settingsIcon; -@property (nonatomic, readonly) UIImage *badge; -@property (nonatomic, readonly) UIColor *badgeTextColor; - -+ (instancetype)palleteWithBackgroundColor:(UIColor *)backgroundColor separatorColor:(UIColor *)separatorColor selectionColor:(UIColor *)selectionColor gifIcon:(UIImage *)gifIcon trendingIcon:(UIImage *)trendingIcon favoritesIcon:(UIImage *)favoritesIcon recentIcon:(UIImage *)recentIcon settingsIcon:(UIImage *)settingsIcon badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor; - -@end - -@interface TGStickerKeyboardTabPanel : UIView - -@property (nonatomic, copy) void (^currentStickerPackIndexChanged)(NSUInteger); -@property (nonatomic, copy) void (^navigateToGifs)(); -@property (nonatomic, copy) void (^navigateToTrendingFirst)(); -@property (nonatomic, copy) void (^navigateToTrendingLast)(); -@property (nonatomic, copy) void (^openSettings)(); - -@property (nonatomic, copy) void (^toggleExpanded)(void); -@property (nonatomic, copy) void (^expandInteraction)(CGFloat offset); - -@property (nonatomic, strong) TGStickerKeyboardPallete *pallete; -@property (nonatomic, assign) UIEdgeInsets safeAreaInset; - -- (instancetype)initWithFrame:(CGRect)frame style:(TGStickerKeyboardViewStyle)style; - -- (void)setStickerPacks:(NSArray *)stickerPacks showRecent:(bool)showRecent showFavorite:(bool)showFavorite showGroup:(bool)showGroup showGroupLast:(bool)showGroupLast showGifs:(bool)showGifs showTrendingFirst:(bool)showTrendingFirst showTrendingLast:(bool)showTrendingLast; -- (void)setCurrentStickerPackIndex:(NSUInteger)currentStickerPackIndex animated:(bool)animated; -- (void)setCurrentGifsModeSelected; -- (void)setCurrentTrendingModeSelected; -- (void)setTrendingStickersBadge:(NSString *)badge; - -- (void)setAvatarUrl:(NSString *)avatarUrl peerId:(int64_t)peerId title:(NSString *)title; - -- (void)setInnerAlpha:(CGFloat)alpha; - -- (void)setExpanded:(bool)expanded; -- (void)updateExpanded:(bool)expanded; - -- (void)setHidden:(bool)hidden animated:(bool)animated; - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedCoubPlayerView.h b/submodules/LegacyComponents/Sources/TGEmbedCoubPlayerView.h deleted file mode 100644 index 0e4c94ee48..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedCoubPlayerView.h +++ /dev/null @@ -1,12 +0,0 @@ -#import "TGEmbedPlayerView.h" - -@interface TGEmbedCoubPlayerView : TGEmbedPlayerView - -+ (NSString *)_coubVideoIdFromText:(NSString *)text; - -+ (NSDictionary *)coubJSONByPermalink:(NSString *)permalink; -+ (void)setCoubJSON:(NSDictionary *)json forPermalink:(NSString *)permalink; - -- (void)setVideoPath:(NSString *)videoPath; - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedCoubPlayerView.m b/submodules/LegacyComponents/Sources/TGEmbedCoubPlayerView.m deleted file mode 100644 index 9007a46539..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedCoubPlayerView.m +++ /dev/null @@ -1,561 +0,0 @@ -#import "TGEmbedCoubPlayerView.h" -#import "TGEmbedPlayerState.h" - -#import "LegacyComponentsInternal.h" - -#import - -#import - -#import "CBPlayerView.h" -#import "CBCoubAsset.h" -#import "CBCoubPlayer.h" -#import "CBCoubNew.h" - -#import - -@interface TGEmbedCoubURLTaskAdapter : NSObject -{ - NSURLSession *_session; -} - -@property (nonatomic, copy) void (^redirectUrl)(NSString *); - -- (instancetype)initWithURL:(NSString *)url; -- (void)invalidate; - -@end - -@interface TGEmbedCoubPlayerView () -{ - NSString *_permalink; - - bool _started; - UIImage *_coverImage; - - CBPlayerView *_playerView; - CBCoubPlayer *_coubPlayer; - SVariable *_videoPath; - - SDisposableSet *_disposables; - - id _asset; -} -@end - -@implementation TGEmbedCoubPlayerView - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal alternateCachePathSignal:(SSignal *)alternateCachePathSignal -{ - self = [super initWithWebPageAttachment:webPage thumbnailSignal:thumbnailSignal alternateCachePathSignal:alternateCachePathSignal]; - if (self != nil) - { - _permalink = [TGEmbedCoubPlayerView _coubVideoIdFromText:webPage.embedUrl]; - _disposables = [[SDisposableSet alloc] init]; - - TGDocumentMediaAttachment *document = webPage.document; - NSString *videoPath = nil; - if ([document.mimeType isEqualToString:@"video/mp4"]) - { - if (document.localDocumentId != 0) { - videoPath = [[[LegacyComponentsGlobals provider] localDocumentDirectoryForLocalDocumentId:document.localDocumentId version:document.version] stringByAppendingPathComponent:[document safeFileName]]; - } else { - videoPath = [[[LegacyComponentsGlobals provider] localDocumentDirectoryForDocumentId:document.documentId version:document.version] stringByAppendingPathComponent:[document safeFileName]]; - } - } - - __weak TGEmbedCoubPlayerView *weakSelf = self; - if (videoPath != nil && [[NSFileManager defaultManager] fileExistsAtPath:videoPath isDirectory:NULL]) - { - _videoPath = [[SVariable alloc] init]; - [_videoPath set:[SSignal single:[NSURL fileURLWithPath:videoPath]]]; - - if (thumbnailSignal == nil) - { - [_disposables add:[[[TGMediaAssetImageSignals videoThumbnailForAVAsset:[AVURLAsset assetWithURL:[NSURL fileURLWithPath:videoPath]] size:CGSizeMake(480, 480) timestamp:CMTimeMake(1, 100)] deliverOn:[SQueue mainQueue]] startWithNext:^(id next) - { - __strong TGEmbedCoubPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if ([next isKindOfClass:[UIImage class]]) - [strongSelf setCoverImage:next]; - }]]; - } - } - else if (alternateCachePathSignal != nil) - { - _videoPath = [[SVariable alloc] init]; - - [_disposables add:[alternateCachePathSignal startWithNext:^(NSString *path) - { - __strong TGEmbedCoubPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:NULL]) - { - if (path.pathExtension.length == 0) - { - [[NSFileManager defaultManager] createSymbolicLinkAtPath:[path stringByAppendingString:@".mov"] withDestinationPath:[path lastPathComponent] error:nil]; - path = [path stringByAppendingString:@".mov"]; - } - - NSURL *url = [NSURL fileURLWithPath:path]; - [strongSelf->_videoPath set:[SSignal single:url]]; - - if (thumbnailSignal == nil) - { - [strongSelf->_disposables add:[[[TGMediaAssetImageSignals videoThumbnailForAVAsset:[AVURLAsset assetWithURL:url] size:CGSizeMake(480, 480) timestamp:CMTimeMake(1, 100)] deliverOn:[SQueue mainQueue]] startWithNext:^(id next) - { - __strong TGEmbedCoubPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if ([next isKindOfClass:[UIImage class]]) - [strongSelf setCoverImage:next]; - }]]; - } - } - else - { - [strongSelf->_videoPath set:[SSignal single:nil]]; - } - }]]; - } - - self.controlsView.watermarkImage = TGComponentsImageNamed(@"CoubWatermark"); - self.controlsView.watermarkOffset = CGPointMake(12.0f, 12.0f); - } - return self; -} - -- (void)dealloc -{ - [_disposables dispose]; -} - -- (bool)supportsPIP -{ - return false; -} - -- (void)_watermarkAction -{ - [super _watermarkAction]; - - if (self.onWatermarkAction != nil) - self.onWatermarkAction(); - - NSString *permalink = _permalink; - NSString *coubId = nil; - if ([_asset isKindOfClass:[CBCoubNew class]]) - coubId = ((CBCoubNew *)_asset).coubID; - - NSURL *appUrl = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"coub://view/%@", coubId]]; - - if ([[LegacyComponentsGlobals provider] canOpenURL:appUrl]) - { - [[LegacyComponentsGlobals provider] openURL:appUrl]; - return; - } - - NSURL *webUrl = [NSURL URLWithString:[NSString stringWithFormat:@"https://coub.com/view/%@", permalink]]; - [[LegacyComponentsGlobals provider] openURL:webUrl]; -} - -- (void)setupWithEmbedSize:(CGSize)embedSize -{ - [super setupWithEmbedSize:embedSize]; - - _playerView = [[CBPlayerView alloc] initWithFrame:[self _webView].bounds]; - [[self _webView].superview insertSubview:_playerView aboveSubview:[self _webView]]; - - _coubPlayer = [[CBCoubPlayer alloc] initWithVideoLayer:(AVPlayerLayer *)_playerView.videoPlayerView.layer]; - _coubPlayer.withoutAudio = false; - _coubPlayer.delegate = self; - - [self _cleanWebView]; - - [self setDimmed:true animated:false shouldDelay:false]; - [self initializePlayer]; - - [self setLoadProgress:0.01f duration:0.01]; -} - -- (void)playVideo -{ - [_coubPlayer resume]; -} - -- (void)pauseVideo:(bool)manually -{ - [super pauseVideo:manually]; - [_coubPlayer pause]; -} - - -- (void)_onPageReady -{ - -} - -- (void)_didBeginPlayback -{ - [super _didBeginPlayback]; - - [self setDimmed:false animated:true shouldDelay:false]; -} - -- (TGEmbedPlayerControlsType)_controlsType -{ - return TGEmbedPlayerControlsTypeSimple; -} - -- (NSString *)_embedHTML -{ - NSError *error = nil; - NSString *path = TGComponentsPathForResource(@"DefaultPlayer", @"html"); - - NSString *embedHTMLTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - if (error != nil) - { - TGLegacyLog(@"[CoubEmbedPlayer]: Received error rendering template: %@", error); - return nil; - } - - NSString *embedHTML = [NSString stringWithFormat:embedHTMLTemplate, @"about:blank"]; - return embedHTML; -} - -- (NSURL *)_baseURL -{ - return [NSURL URLWithString:@"https://coub.com/"]; -} - -#pragma mark - - -- (bool)_useFakeLoadingProgress -{ - return false; -} - -+ (SSignal *)webHeadersRequestSignal:(NSString *)url -{ - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - TGEmbedCoubURLTaskAdapter *adapter = [[TGEmbedCoubURLTaskAdapter alloc] initWithURL:url]; - adapter.redirectUrl = ^(NSString *redirectUrl) - { - [subscriber putNext:redirectUrl]; - [subscriber putCompletion]; - }; - return [[SBlockDisposable alloc] initWithBlock:^ - { - [adapter invalidate]; - }]; - }]; -} - -- (void)initializePlayer -{ - NSString *url = [NSString stringWithFormat:@"http://coub.com/api/v2/coubs/%@", _permalink]; - - __weak TGEmbedCoubPlayerView *weakSelf = self; - SSignal *cachedSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - __strong TGEmbedCoubPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - { - [subscriber putCompletion]; - return nil; - } - - NSDictionary *json = [TGEmbedCoubPlayerView coubJSONByPermalink:strongSelf->_permalink]; - if (json != nil) - { - [subscriber putNext:json]; - [subscriber putCompletion]; - } - else - { - [subscriber putError:nil]; - } - - return nil; - }]; - - SSignal *dataSignal = [[cachedSignal mapToSignal:^SSignal *(NSDictionary *json) - { - return [[SSignal single:@{ @"json": json, @"cached": @true }] delay:0.2 onQueue:[SQueue mainQueue]]; - }] catch:^SSignal *(__unused id error) - { - return [[[LegacyComponentsGlobals provider] jsonForHttpLocation:url] map:^id(NSDictionary *json) - { - return @{ @"json": json, @"cached": @false }; - }]; - }]; - - SSignal *locationSignal = [dataSignal mapToSignal:^SSignal *(NSDictionary *data) - { - NSDictionary *attributes = data[@"json"]; - NSString *remoteVideoLocation = nil; - NSDictionary *fileVersions = attributes[@"file_versions"]; - - if (fileVersions != nil) - remoteVideoLocation = fileVersions[@"iphone"][@"url"]; - if (!remoteVideoLocation || [remoteVideoLocation isKindOfClass:[NSNull class]]) - remoteVideoLocation = attributes[@"file"]; - if (!remoteVideoLocation || [remoteVideoLocation isKindOfClass:[NSNull class]]) - remoteVideoLocation = fileVersions[@"html5"][@"video"][@"med"][@"url"]; - - if ([remoteVideoLocation rangeOfString:@"getvideo?"].location != NSNotFound) - { - NSString *location = [remoteVideoLocation stringByReplacingOccurrencesOfString:@"//coub" withString:@"https://coub"]; - return [[TGEmbedCoubPlayerView webHeadersRequestSignal:location] map:^id(id result) { - NSMutableDictionary *updatedJson = [attributes mutableCopy]; - updatedJson[@"explicitVideoLocation"] = result; - return updatedJson; - }]; - } - else - { - return [SSignal single:attributes]; - } - }]; - - [_disposables add:[[locationSignal deliverOn:[SQueue mainQueue]] startWithNext:^(NSDictionary *data) - { - __strong TGEmbedCoubPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - SSignal *signal = [SSignal single:nil]; - if (strongSelf->_videoPath != nil) - signal = strongSelf->_videoPath.signal; - - [strongSelf->_disposables add:[signal startWithNext:^(NSURL *videoPath) - { - __strong TGEmbedCoubPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - CBCoubNew *coub = [CBCoubNew coubWithAttributes:data]; - coub.customLocalVideoFileURL = videoPath; - strongSelf->_asset = coub; - - if ([coub isKindOfClass:[CBCoubNew class]]) - { - CBCoubNew *coubNew = (CBCoubNew *)coub; - if (strongSelf.onMetadataLoaded != nil) - strongSelf.onMetadataLoaded(coubNew.title, coubNew.author.name); - } - - [strongSelf->_coubPlayer playAsset:strongSelf->_asset]; - - if (![data[@"cached"] boolValue]) - [TGEmbedCoubPlayerView setCoubJSON:data[@"json"] forPermalink:strongSelf->_permalink]; - }]]; - }]]; -} - -- (void)setVideoPath:(NSString *)videoPath { - [_videoPath set:[SSignal single:[NSURL fileURLWithPath:videoPath]]]; -} - -- (void)playerReadyToPlay:(CBCoubPlayer *)__unused player -{ - [self setLoadProgress:1.0f duration:0.2]; - [_playerView play]; - - if (self.onRealLoadProgress != nil) - self.onRealLoadProgress(1.0f, 0.2); -} - -- (void)playerDidStartPlaying:(CBCoubPlayer *)__unused player -{ - if (!_started) - { - _started = true; - [self _didBeginPlayback]; - - TGEmbedPlayerState *state = [TGEmbedPlayerState stateWithPlaying:true]; - [self updateState:state]; - } -} - -- (void)player:(CBCoubPlayer *)__unused player didReachProgressWhileDownloading:(float)progress -{ - [self setLoadProgress:progress duration:0.3]; - - if (self.onRealLoadProgress != nil) - self.onRealLoadProgress(progress, 0.3); -} - -- (void)playerDidPause:(CBCoubPlayer *)__unused player withUserAction:(BOOL)isUserAction -{ - if (!isUserAction) - return; - - TGEmbedPlayerState *state = [TGEmbedPlayerState stateWithPlaying:false]; - [self updateState:state]; -} - -- (void)playerDidResume:(CBCoubPlayer *)__unused player -{ - TGEmbedPlayerState *state = [TGEmbedPlayerState stateWithPlaying:true]; - [self updateState:state]; -} - -- (void)playerDidFail:(CBCoubPlayer *)__unused player error:(NSError *)error -{ - TGLegacyLog(@"[CoubPlayer] ERROR: %@", error.localizedDescription); -} - -- (void)playerDidStop:(CBCoubPlayer *)__unused player -{ - -} - -#pragma mark - - -+ (NSString *)_coubVideoIdFromText:(NSString *)text -{ - NSMutableArray *prefixes = [NSMutableArray arrayWithArray:@ - [ - @"http://coub.com/v/", - @"https://coub.com/v/", - @"http://coub.com/embed/", - @"https://coub.com/embed/", - @"http://coub.com/view/", - @"https://coub.com/view/" - ]]; - - NSString *prefix = nil; - for (NSString *p in prefixes) - { - if ([text hasPrefix:p]) - { - prefix = p; - break; - } - } - - if (prefix != nil) - { - NSString *suffix = [text substringFromIndex:prefix.length]; - - for (int i = 0; i < (int)suffix.length; i++) - { - unichar c = [suffix characterAtIndex:i]; - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '=' || c == '&' || c == '#')) - return nil; - } - - return suffix; - } - - return nil; -} - -+ (bool)_supportsWebPage:(TGWebPageMediaAttachment *)webPage -{ - NSString *url = webPage.embedUrl; - return ([url hasPrefix:@"http://coub.com/embed/"] || [url hasPrefix:@"https://coub.com/embed/"]); -} - -+ (PSLMDBKeyValueStore *)coubMetaStore -{ - static PSLMDBKeyValueStore *store = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - NSString *documentsPath = [[LegacyComponentsGlobals provider] dataStoragePath]; - store = [PSLMDBKeyValueStore storeWithPath:[documentsPath stringByAppendingPathComponent:@"misc/coubmetadata"] size:1 * 1024 * 1024]; - }); - return store; -} - -+ (NSDictionary *)coubJSONByPermalink:(NSString *)permalink -{ - if (permalink.length == 0) - return nil; - - __block NSData *jsonData = nil; - [[self coubMetaStore] readInTransaction:^(id reader) - { - NSMutableData *keyData = [[NSMutableData alloc] init]; - int8_t keyspace = 0; - [keyData appendBytes:&keyspace length:1]; - [keyData appendData:[permalink dataUsingEncoding:NSUTF8StringEncoding]]; - PSData key = {.data = (uint8_t *)keyData.bytes, .length = keyData.length}; - PSData value; - if ([reader readValueForRawKey:&key value:&value]) - jsonData = [[NSData alloc] initWithBytes:value.data length:value.length]; - }]; - - if (jsonData.length > 0) - { - @try - { - NSDictionary *json = [NSKeyedUnarchiver unarchiveObjectWithData:jsonData]; - return json; - } - @catch(NSException *) - { - } - } - - return nil; -} - -+ (void)setCoubJSON:(NSDictionary *)json forPermalink:(NSString *)permalink -{ - if (permalink.length == 0 || json.allKeys.count == 0) - return; - - NSData *data = [NSKeyedArchiver archivedDataWithRootObject:json]; - if (data.length == 0) - return; - - [[self coubMetaStore] readWriteInTransaction:^(id writer) - { - NSMutableData *keyData = [[NSMutableData alloc] init]; - int8_t keyspace = 0; - [keyData appendBytes:&keyspace length:1]; - [keyData appendData:[permalink dataUsingEncoding:NSUTF8StringEncoding]]; - PSData key = {.data = (uint8_t *)keyData.bytes, .length = keyData.length}; - PSData value = {.data = (uint8_t *)data.bytes, .length = data.length}; - [writer writeValueForRawKey:key.data keyLength:key.length value:value.data valueLength:value.length]; - }]; -} - -@end - - -@implementation TGEmbedCoubURLTaskAdapter - -- (instancetype)initWithURL:(NSString *)url -{ - self = [super init]; - if (self != nil) - { - NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; - _session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; - [[_session dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}] resume]; - } - return self; -} - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler -{ - if (self.redirectUrl != nil) - self.redirectUrl(response.allHeaderFields[@"Location"]); -} - -- (void)invalidate -{ - [_session invalidateAndCancel]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedInstagramPlayerView.h b/submodules/LegacyComponents/Sources/TGEmbedInstagramPlayerView.h deleted file mode 100644 index e103032699..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedInstagramPlayerView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGEmbedPlayerView.h" - -@interface TGEmbedInstagramPlayerView : TGEmbedPlayerView - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedInstagramPlayerView.m b/submodules/LegacyComponents/Sources/TGEmbedInstagramPlayerView.m deleted file mode 100644 index f416302265..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedInstagramPlayerView.m +++ /dev/null @@ -1,113 +0,0 @@ -#import "TGEmbedInstagramPlayerView.h" -#import "TGEmbedPlayerState.h" - -#import "LegacyComponentsInternal.h" - -NSString *const TGInstagramPlayerCallbackOnPlayback = @"onPlayback"; - -@interface TGEmbedInstagramPlayerView () -{ - NSString *_url; - bool _playing; - bool _started; -} -@end - -@implementation TGEmbedInstagramPlayerView - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal alternateCachePathSignal:(SSignal *)alternateCachePathSignal -{ - self = [super initWithWebPageAttachment:webPage thumbnailSignal:thumbnailSignal alternateCachePathSignal:alternateCachePathSignal]; - if (self != nil) - { - _url = webPage.embedUrl; - } - return self; -} - -- (void)playVideo -{ - _playing = true; - [self _evaluateJS:@"play()" completion:nil]; - - TGEmbedPlayerState *state = [TGEmbedPlayerState stateWithPlaying:_playing]; - [self updateState:state]; -} - -- (void)pauseVideo:(bool)manually -{ - [super pauseVideo:manually]; - - _playing = false; - [self _evaluateJS:@"pause();" completion:nil]; - - TGEmbedPlayerState *state = [TGEmbedPlayerState stateWithPlaying:_playing]; - [self updateState:state]; -} - -- (TGEmbedPlayerControlsType)_controlsType -{ - return TGEmbedPlayerControlsTypeSimple; -} - -- (void)_onPageReady -{ - -} - -- (void)_didBeginPlayback -{ - [super _didBeginPlayback]; - [self setDimmed:false animated:true shouldDelay:false]; -} - -- (void)_notifyOfCallbackURL:(NSURL *)url -{ - NSString *action = url.host; - - NSString *query = url.query; - NSString *data; - if (query != nil) - data = [query componentsSeparatedByString:@"="][1]; - - if ([action isEqual:TGInstagramPlayerCallbackOnPlayback]) - { - if (!_started) - { - _started = true; - [self _didBeginPlayback]; - } - _playing = true; - TGEmbedPlayerState *state = [TGEmbedPlayerState stateWithPlaying:true]; - [self updateState:state]; - } -} - -- (NSString *)_embedHTML -{ - NSError *error = nil; - NSString *path = TGComponentsPathForResource(@"InstagramPlayer", @"html"); - - NSString *embedHTMLTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - if (error != nil) - { - TGLegacyLog(@"[InstagramEmbedPlayer]: Received error rendering template: %@", error); - return nil; - } - - NSString *embedHTML = [NSString stringWithFormat:embedHTMLTemplate, _url]; - return embedHTML; -} - -- (NSURL *)_baseURL -{ - return [NSURL URLWithString:@"https://instagram.com/"]; -} - -+ (bool)_supportsWebPage:(TGWebPageMediaAttachment *)webPage -{ - NSURL *url = [NSURL URLWithString:webPage.embedUrl]; - return ([url.host containsString:@"cdninstagram"] && [url.pathExtension isEqualToString:@"mp4"]); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPIPScrubber.h b/submodules/LegacyComponents/Sources/TGEmbedPIPScrubber.h deleted file mode 100644 index ade95f7089..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPIPScrubber.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface TGEmbedPIPScrubber : UIView - -@property (nonatomic, assign) CGFloat playProgress; -@property (nonatomic, assign) CGFloat downloadProgress; - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPIPScrubber.m b/submodules/LegacyComponents/Sources/TGEmbedPIPScrubber.m deleted file mode 100644 index ccc862cea3..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPIPScrubber.m +++ /dev/null @@ -1,67 +0,0 @@ -#import "TGEmbedPIPScrubber.h" - -#import "LegacyComponentsInternal.h" - -@interface TGEmbedPIPScrubber () -{ - UIVisualEffectView *_playProgressView; - UIVisualEffectView *_remainingProgressView; - UIView *_downloadProgressView; -} -@end - -@implementation TGEmbedPIPScrubber - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.userInteractionEnabled = false; - - UIVisualEffect *lightBlurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; - _playProgressView = [[UIVisualEffectView alloc] initWithEffect:lightBlurEffect]; - [self addSubview:_playProgressView]; - - _downloadProgressView = [[UIView alloc] init]; - _downloadProgressView.backgroundColor = UIColorRGBA(0x000000, 0.45f); - [self addSubview:_downloadProgressView]; - - UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; - _remainingProgressView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; - [self addSubview:_remainingProgressView]; - } - return self; -} - -- (void)setPlayProgress:(CGFloat)playProgress -{ - if (isnan(playProgress)) - playProgress = 0.0f; - - _playProgress = playProgress; - [self setNeedsLayout]; -} - -- (void)setDownloadProgress:(CGFloat)downloadProgress -{ - _downloadProgress = downloadProgress; - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - CGFloat playedWidth = floor(self.frame.size.width * _playProgress); - if (isnan(playedWidth)) - playedWidth = 0.0f; - - _playProgressView.frame = CGRectMake(0, 0, playedWidth, self.frame.size.height); - _remainingProgressView.frame = CGRectMake(playedWidth, 0, self.frame.size.width - playedWidth, self.frame.size.height); - - CGFloat downloadedWidth = MAX(0.0f, playedWidth - floor(self.frame.size.width * _downloadProgress)); - _downloadProgressView.frame = CGRectMake(playedWidth, 0, downloadedWidth, self.frame.size.height); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPlayerControls.m b/submodules/LegacyComponents/Sources/TGEmbedPlayerControls.m deleted file mode 100644 index 52dcf186d2..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPlayerControls.m +++ /dev/null @@ -1,689 +0,0 @@ -#import "TGEmbedPlayerControls.h" - -#import "LegacyComponentsInternal.h" -#import "TGFont.h" - -#import - -#import -#import -#import - -#import "TGEmbedPlayerScrubber.h" - -#import "TGEmbedPlayerState.h" - -const CGFloat TGEmbedPlayerControlsPanelHeight = 32.0f; - -@interface TGEmbedPlayerControls () -{ - TGEmbedPlayerControlsType _type; - - UIButton *_screenAreaButton; - - UIView *_backgroundView; - UIView *_backgroundContentView; - TGModernButton *_playButton; - TGModernButton *_pauseButton; - - UILabel *_positionLabel; - UILabel *_remainingLabel; - TGEmbedPlayerScrubber *_scrubber; - TGModernButton *_pictureInPictureButton; - - UIView *_fullscreenButtonWrapper; - TGModernButton *_fullscreenButton; - - UIView *_largePlayButtonBack; - TGModernButton *_largePlayButton; - - UIButton *_watermarkView; - bool _watermarkDenyHiding; - - bool _disabled; - bool _controlsHidden; - bool _panelHidden; - bool _animatingPanel; - bool _playing; - bool _hasPlaybackButton; - bool _showingLargeButton; - - bool _wasPlayingBeforeScrubbing; - - NSTimer *_hidePanelTimer; -} -@end - -@implementation TGEmbedPlayerControls - -- (instancetype)initWithFrame:(CGRect)frame type:(TGEmbedPlayerControlsType)type -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _type = type; - - _panelHidden = true; - self.clipsToBounds = true; - - _screenAreaButton = [[UIButton alloc] initWithFrame:self.bounds]; - _screenAreaButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _screenAreaButton.exclusiveTouch = true; - [_screenAreaButton addTarget:self action:@selector(screenAreaPressed) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_screenAreaButton]; - - if (type == TGEmbedPlayerControlsTypeFull) - { - if (iosMajorVersion() >= 8) - { - UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - _backgroundView = effectView; - _backgroundContentView = effectView.contentView; - - UIView *whiteView = [[UIView alloc] initWithFrame:effectView.bounds]; - whiteView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - whiteView.backgroundColor = UIColorRGBA(0xffffff, 0.3f); - [effectView.contentView addSubview:whiteView]; - } - else - { - _backgroundView = [[UIView alloc] initWithFrame:CGRectZero]; - _backgroundContentView = _backgroundView; - } - [self addSubview:_backgroundView]; - - _pauseButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 38, TGEmbedPlayerControlsPanelHeight)]; - _pauseButton.exclusiveTouch = true; - [_pauseButton setImage:TGComponentsImageNamed(@"EmbedVideoPauseIcon") forState:UIControlStateNormal]; - [_pauseButton addTarget:self action:@selector(pauseButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [_backgroundContentView addSubview:_pauseButton]; - - _playButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 38, TGEmbedPlayerControlsPanelHeight)]; - _playButton.exclusiveTouch = true; - [_playButton setImage:TGComponentsImageNamed(@"EmbedVideoPlayIcon") forState:UIControlStateNormal]; - [_playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [_backgroundContentView addSubview:_playButton]; - - _positionLabel = [[UILabel alloc] initWithFrame:CGRectMake(24.0f, 0, 56.0f, TGEmbedPlayerControlsPanelHeight)]; - _positionLabel.backgroundColor = [UIColor clearColor]; - _positionLabel.font = TGSystemFontOfSize(13.0f); - _positionLabel.text = @"0:00"; - _positionLabel.textAlignment = NSTextAlignmentCenter; - _positionLabel.textColor = UIColorRGB(0x302e2e); - _positionLabel.userInteractionEnabled = false; - [_backgroundContentView addSubview:_positionLabel]; - - _remainingLabel = [[UILabel alloc] initWithFrame:CGRectMake(frame.size.width - 56.0f, 0, 56, TGEmbedPlayerControlsPanelHeight)]; - _remainingLabel.backgroundColor = [UIColor clearColor]; - _remainingLabel.font = TGSystemFontOfSize(13.0f); - _remainingLabel.text = @"-0:00"; - _remainingLabel.textAlignment = NSTextAlignmentCenter; - _remainingLabel.textColor = UIColorRGB(0x302e2e); - _remainingLabel.userInteractionEnabled = false; - [_backgroundContentView addSubview:_remainingLabel]; - - _pictureInPictureButton = [[TGModernButton alloc] initWithFrame:CGRectMake(frame.size.width - 45.0f, 0, 45.0f, TGEmbedPlayerControlsPanelHeight)]; - _pictureInPictureButton.exclusiveTouch = true; - [_pictureInPictureButton setImage:TGComponentsImageNamed(@"EmbedVideoPIPIcon") forState:UIControlStateNormal]; - [_pictureInPictureButton addTarget:self action:@selector(pictureInPictureButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [_backgroundContentView addSubview:_pictureInPictureButton]; - - __weak TGEmbedPlayerControls *weakSelf = self; - _scrubber = [[TGEmbedPlayerScrubber alloc] initWithFrame:CGRectZero]; - _scrubber.onInteractionStart = ^ - { - __strong TGEmbedPlayerControls *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (strongSelf->_playing) - { - strongSelf->_wasPlayingBeforeScrubbing = true; - if (strongSelf.pausePressed != nil) - strongSelf.pausePressed(); - } - [strongSelf _invalidateTimer]; - }; - _scrubber.onSeek = ^(CGFloat position) - { - __strong TGEmbedPlayerControls *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (strongSelf.seekToPosition != nil) - strongSelf.seekToPosition(position); - }; - _scrubber.onInteractionEnd = ^ - { - __strong TGEmbedPlayerControls *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - [strongSelf _startTimerIfNeeded]; - - if (strongSelf->_wasPlayingBeforeScrubbing) - { - strongSelf->_wasPlayingBeforeScrubbing = false; - if (strongSelf.playPressed != nil) - strongSelf.playPressed(); - } - }; - [_scrubber setTintColor:UIColorRGB(0x2f2e2e)]; - [_backgroundContentView addSubview:_scrubber]; - } - - if (type == TGEmbedPlayerControlsTypeSimple) - { - [self showLargePlayButton:false]; - } - - if (type == TGEmbedPlayerControlsTypeSimple || type == TGEmbedPlayerControlsTypeFull) - { - _fullscreenButtonWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 51.0f, 51.0f)]; - _fullscreenButtonWrapper.alpha = 0.0f; - _fullscreenButtonWrapper.userInteractionEnabled = false; - [self addSubview:_fullscreenButtonWrapper]; - - if (iosMajorVersion() >= 8) - { - UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - effectView.contentView.backgroundColor = UIColorRGBA(0xffffff, 0.3f); - effectView.clipsToBounds = true; - effectView.frame = CGRectMake(12.0f, 12.0f, 27.0f, 27.0f); - effectView.layer.cornerRadius = 13.5f; - [_fullscreenButtonWrapper addSubview:effectView]; - } - - _fullscreenButton = [[TGModernButton alloc] initWithFrame:_fullscreenButtonWrapper.bounds]; - _fullscreenButton.exclusiveTouch = true; - [_fullscreenButton setImage:TGComponentsImageNamed(@"EmbedVideoFullScreenIcon") forState:UIControlStateNormal]; - [_fullscreenButton addTarget:self action:@selector(fullscreenButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [_fullscreenButtonWrapper addSubview:_fullscreenButton]; - } - - _watermarkView = [[UIButton alloc] init]; - _watermarkView.alpha = 0.6f; - _watermarkView.adjustsImageWhenHighlighted = false; - _watermarkView.exclusiveTouch = true; - _watermarkView.hitTestEdgeInsets = UIEdgeInsetsMake(-12.0f, -12.0f, -12.0f, -12.0f); - [_watermarkView addTarget:self action:@selector(watermarkButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_watermarkView]; - - _watermarkDenyHiding = true; - } - return self; -} - -- (void)showLargePlayButton:(bool)force -{ - if (_largePlayButton != nil) - return; - - if (iosMajorVersion() >= 8) - { - UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; - - UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect]; - effectView.alpha = 1.0f; - effectView.clipsToBounds = true; - effectView.frame = CGRectMake(0.0f, 0.0f, 72.0f, 72.0f); - effectView.layer.cornerRadius = 36.0f; - [self addSubview:effectView]; - - UIVisualEffectView *vibrancyView = [[UIVisualEffectView alloc] initWithEffect:[UIVibrancyEffect effectForBlurEffect:effect]]; - vibrancyView.contentView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f]; - vibrancyView.frame = effectView.bounds; - [effectView.contentView addSubview:vibrancyView]; - - _largePlayButtonBack = effectView; - - if (!force) - _largePlayButtonBack.hidden = true; - - static dispatch_once_t onceToken; - static UIImage *largePlayIcon; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(72, 72), false, 0.0f); - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:0.8f alpha:0.09f].CGColor); - CGContextFillRect(ctx, CGRectMake(0, 0, 72, 72)); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, 25.0f, 18.0f); - CGContextAddLineToPoint(ctx, 58.0f, 36.5f); - CGContextAddLineToPoint(ctx, 25.0f, 55.0f); - CGContextClosePath(ctx); - - CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:0.0f alpha:0.7f].CGColor); - CGContextFillPath(ctx); - - largePlayIcon = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - _largePlayButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 72, 72)]; - [_largePlayButton setImage:largePlayIcon forState:UIControlStateNormal]; - [_largePlayButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [effectView.contentView addSubview:_largePlayButton]; - - _showingLargeButton = force; - } -} - -- (void)setHidden:(bool)hidden animated:(bool)__unused animated -{ - if (hidden == _controlsHidden) - return; - - _controlsHidden = hidden; - - _backgroundView.hidden = hidden; - _fullscreenButtonWrapper.hidden = hidden; - - if (_type == TGEmbedPlayerControlsTypeSimple) - _largePlayButtonBack.hidden = hidden || _playing; - - if (hidden) - [self setPanelHidden:true animated:false]; -} - -#pragma mark - - -- (void)watermarkButtonPressed -{ - if (self.watermarkPressed != nil) - self.watermarkPressed(); -} - -- (void)setWatermarkHidden:(bool)hidden -{ - _watermarkView.hidden = hidden; -} - -- (void)setWatermarkPrerenderedOpacity:(bool)watermarkPrerenderedOpacity -{ - _watermarkPrerenderedOpacity = watermarkPrerenderedOpacity; - if (watermarkPrerenderedOpacity && _watermarkView.alpha > FLT_EPSILON) - _watermarkView.alpha = 1.0f; -} - -- (void)setInternalWatermarkHidden:(bool)hidden animated:(bool)animated -{ - if (_type != TGEmbedPlayerControlsTypeFull) - return; - - CGFloat visibleAlpha = _watermarkPrerenderedOpacity ? 1.0f : 0.6f; - - if (animated) - { - [UIView animateWithDuration:0.25 animations:^ - { - _watermarkView.alpha = hidden ? 0.0f : visibleAlpha; - }]; - } - else - { - _watermarkView.alpha = hidden ? 0.0f : visibleAlpha; - } -} - -- (UIImage *)watermarkImage -{ - return [_watermarkView imageForState:UIControlStateNormal]; -} - -- (void)setWatermarkImage:(UIImage *)watermarkImage -{ - [_watermarkView setImage:watermarkImage forState:UIControlStateNormal]; - [_watermarkView sizeToFit]; - [self setNeedsLayout]; -} - -- (void)setWatermarkOffset:(CGPoint)watermarkOffset -{ - _watermarkOffset = watermarkOffset; - [self setNeedsLayout]; -} - -- (void)setWatermarkPosition:(TGEmbedPlayerWatermarkPosition)watermarkPosition -{ - _watermarkPosition = watermarkPosition; - [self setNeedsLayout]; -} - -#pragma mark - - -- (void)setState:(TGEmbedPlayerState *)state -{ - _playing = state.isPlaying; - - if (_type == TGEmbedPlayerControlsTypeFull) - { - _playButton.hidden = _playing; - _pauseButton.hidden = !_playing; - - NSInteger position = (NSInteger)state.position; - NSString *positionString = [[NSString alloc] initWithFormat:@"%d:%02d", (int)position / 60, (int)position % 60]; - _positionLabel.text = positionString; - - NSInteger remaining = (NSInteger)(state.duration - state.position); - NSString *remainingString = [[NSString alloc] initWithFormat:@"-%d:%02d", (int)remaining / 60, (int)remaining % 60]; - _remainingLabel.text = remainingString; - - CGFloat fractPosition = state.position / MAX(state.duration, 0.001); - if (state.duration <= 0.01 || isnan(state.downloadProgress)) - { - _remainingLabel.hidden = true; - _scrubber.hidden = true; - } - else - { - _remainingLabel.hidden = false; - _scrubber.hidden = false; - } - - _positionLabel.hidden = (state.position < 0.0); - - if (!_scrubber.hidden) - { - [_scrubber setDownloadProgress:state.downloadProgress]; - [_scrubber setPosition:fractPosition]; - } - - if (!_watermarkDenyHiding) - [self setInternalWatermarkHidden:_playing animated:true]; - - if (_playing) - { - _largePlayButtonBack.hidden = true; - _showingLargeButton = false; - } - - if (!_playing && !_animatingPanel && _panelHidden && !_showingLargeButton) - { - [self setPanelHidden:false animated:true]; - } - else - { - if (!_playing && _hidePanelTimer != nil) - [self _invalidateTimer]; - else - [self _startTimerIfNeeded]; - } - } - else if (_type == TGEmbedPlayerControlsTypeSimple) - { - _largePlayButtonBack.hidden = _controlsHidden || _playing; - } -} - -- (void)hidePanelEvent -{ - [self _invalidateTimer]; - [self setPanelHidden:true animated:true]; -} - -- (void)_startTimer -{ - _hidePanelTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(hidePanelEvent) interval:3.0 repeat:false]; -} - -- (void)_startTimerIfNeeded -{ - if (_playing && !_panelHidden && _hidePanelTimer == nil) - [self _startTimer]; -} - -- (void)_invalidateTimer -{ - [_hidePanelTimer invalidate]; - _hidePanelTimer = nil; -} - -- (void)screenAreaPressed -{ - if (_type == TGEmbedPlayerControlsTypeFull) - { - if (_panelHidden) - { - [self setPanelHidden:false animated:true]; - } - else - { - if (_playing) - [self pauseButtonPressed]; - else - [self playButtonPressed]; - } - } - else if (_type == TGEmbedPlayerControlsTypeSimple) - { - if (_playing) - [self pauseButtonPressed]; - else - [self playButtonPressed]; - } -} - -- (void)playButtonPressed -{ - if (_type == TGEmbedPlayerControlsTypeFull) - { - _largePlayButtonBack.hidden = true; - } - - if (self.playPressed != nil) - self.playPressed(); -} - -- (void)pauseButtonPressed -{ - _watermarkDenyHiding = false; - - if (self.pausePressed != nil) - self.pausePressed(); -} - -- (void)fullscreenButtonPressed -{ - if (self.fullscreenPressed != nil) - self.fullscreenPressed(); -} - -- (void)pictureInPictureButtonPressed -{ - if (self.pictureInPicturePressed != nil) - self.pictureInPicturePressed(); -} - -- (void)setPictureInPictureHidden:(bool)hidden -{ - _pictureInPictureButton.hidden = hidden; - [self setNeedsLayout]; -} - -- (void)setPanelHidden:(bool)hidden animated:(bool)animated -{ - if (_panelHidden == hidden) - return; - - _panelHidden = hidden; - - if (self.panelVisibilityChange != nil) - self.panelVisibilityChange(hidden); - - [self setFullscreenButtonDimmed:hidden animated:true]; - - if (animated) - { - UIViewAnimationOptions options = kNilOptions; - if (!hidden && iosMajorVersion() >= 7) - options |= (7 << 16); - else if (hidden) - options |= UIViewAnimationOptionCurveEaseOut; - - _animatingPanel = true; - - NSTimeInterval duration = hidden ? 0.4 : 0.25; - [UIView animateWithDuration:duration delay:0.0 options:options animations:^ - { - if (hidden) - _backgroundView.frame = CGRectMake(0, self.frame.size.height, self.frame.size.width, TGEmbedPlayerControlsPanelHeight); - else - _backgroundView.frame = CGRectMake(0, self.frame.size.height - _backgroundView.frame.size.height, self.frame.size.width, TGEmbedPlayerControlsPanelHeight); - - [self _layoutWatermark]; - } completion:^(__unused BOOL finished) - { - _animatingPanel = false; - }]; - } - else - { - _animatingPanel = false; - if (hidden) - _backgroundView.frame = CGRectMake(0, self.frame.size.height, self.frame.size.width, TGEmbedPlayerControlsPanelHeight); - else - _backgroundView.frame = CGRectMake(0, self.frame.size.height - _backgroundView.frame.size.height, self.frame.size.width, TGEmbedPlayerControlsPanelHeight); - - [self _layoutWatermark]; - } -} - -- (void)setFullscreenButtonHidden:(bool)hidden animated:(bool)animated -{ - CGFloat visibleAlpha = self.inhibitFullscreenButton ? 0.65f : 1.0f; - if (animated) - { - _fullscreenButtonWrapper.userInteractionEnabled = !hidden; - [UIView animateWithDuration:0.25 animations:^ - { - _fullscreenButtonWrapper.alpha = hidden ? 0.0f : visibleAlpha; - }]; - } - else - { - _fullscreenButtonWrapper.userInteractionEnabled = !hidden; - _fullscreenButtonWrapper.alpha = hidden ? 0.0f : visibleAlpha; - } -} - -- (void)setFullscreenButtonDimmed:(bool)dimmed animated:(bool)animated -{ - if (self.inhibitFullscreenButton && dimmed && _fullscreenButtonWrapper.alpha < FLT_EPSILON) - return; - - if (animated) - { - NSTimeInterval duration = dimmed ? 0.5 : 0.25; - [UIView animateWithDuration:duration animations:^ - { - _fullscreenButtonWrapper.alpha = dimmed ? 0.65f : 1.0f; - }]; - } - else - { - _fullscreenButtonWrapper.alpha = dimmed ? 0.65f : 1.0f; - } -} - -- (void)setDisabled -{ - _disabled = true; - _screenAreaButton.userInteractionEnabled = false; -} - -- (void)hidePlayButton -{ - [_largePlayButtonBack removeFromSuperview]; -} - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - UIView *view = [super hitTest:point withEvent:event]; - if (!_disabled) - return view; - - if (view == _watermarkView) - return view; - - return nil; -} - -- (void)notifyOfPlaybackStart -{ - TGDispatchAfter(0.1, dispatch_get_main_queue(), ^ - { - if (!self.inhibitFullscreenButton) - [self setFullscreenButtonHidden:false animated:true]; - - TGDispatchAfter(2.5, dispatch_get_main_queue(), ^ - { - if (_panelHidden) - [self setFullscreenButtonDimmed:true animated:true]; - - if (_playing) - [self setInternalWatermarkHidden:true animated:true]; - - _watermarkDenyHiding = false; - }); - }); -} - -- (void)_layoutWatermark -{ - CGFloat visiblePanelHeight = _panelHidden ? 0.0f : TGEmbedPlayerControlsPanelHeight; - CGRect watermarkFrame = CGRectMake(0, 0, _watermarkView.frame.size.width, _watermarkView.frame.size.height); - switch (_watermarkPosition) - { - case TGEmbedPlayerWatermarkPositionTopLeft: - { - watermarkFrame.origin = _watermarkOffset; - } - break; - - case TGEmbedPlayerWatermarkPositionBottomLeft: - { - watermarkFrame.origin = CGPointMake(_watermarkOffset.x, self.frame.size.height - watermarkFrame.size.height - visiblePanelHeight + _watermarkOffset.y); - } - break; - - case TGEmbedPlayerWatermarkPositionBottomRight: - { - watermarkFrame.origin = CGPointMake(self.frame.size.width - watermarkFrame.size.width + _watermarkOffset.x, self.frame.size.height - watermarkFrame.size.height - visiblePanelHeight + _watermarkOffset.y); - } - break; - - default: - break; - } - _watermarkView.frame = watermarkFrame; -} - -- (void)layoutSubviews -{ - _fullscreenButtonWrapper.frame = CGRectMake(self.bounds.size.width - _fullscreenButtonWrapper.frame.size.width, 0, _fullscreenButtonWrapper.frame.size.width, _fullscreenButtonWrapper.frame.size.height); - - CGFloat rightOffset = _pictureInPictureButton.hidden ? 0.0f : 35.0f; - _remainingLabel.frame = CGRectMake(self.frame.size.width - _remainingLabel.frame.size.width - rightOffset, 0.0f, _remainingLabel.frame.size.width, _remainingLabel.frame.size.height); - - _pictureInPictureButton.frame = CGRectMake(self.frame.size.width - _pictureInPictureButton.frame.size.width, 0, _pictureInPictureButton.frame.size.width, _pictureInPictureButton.frame.size.height); - - _scrubber.frame = CGRectMake(CGRectGetMaxX(_positionLabel.frame), 14.5f, self.frame.size.width - CGRectGetMaxX(_positionLabel.frame) - _remainingLabel.frame.size.width - rightOffset, 3.0f); - - if (!_animatingPanel || _backgroundView.frame.size.width < FLT_EPSILON) - { - if (_panelHidden) - _backgroundView.frame = CGRectMake(0, self.frame.size.height, self.frame.size.width, TGEmbedPlayerControlsPanelHeight); - else - _backgroundView.frame = CGRectMake(0, self.frame.size.height - _backgroundView.frame.size.height, self.frame.size.width, TGEmbedPlayerControlsPanelHeight); - } - - [self _layoutWatermark]; - - _largePlayButtonBack.frame = CGRectMake(CGFloor((self.frame.size.width - _largePlayButtonBack.frame.size.width) / 2.0f), CGFloor((self.frame.size.height - _largePlayButtonBack.frame.size.height) / 2.0f), _largePlayButtonBack.frame.size.width, _largePlayButtonBack.frame.size.height); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPlayerScrubber.h b/submodules/LegacyComponents/Sources/TGEmbedPlayerScrubber.h deleted file mode 100644 index 0d9487735a..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPlayerScrubber.h +++ /dev/null @@ -1,16 +0,0 @@ -#import - -@interface TGEmbedPlayerScrubber : UIControl - -@property (nonatomic, copy) void (^onInteractionStart)(); -@property (nonatomic, copy) void (^onSeek)(CGFloat position); -@property (nonatomic, copy) void (^onInteractionEnd)(); - -@property (nonatomic, readonly) bool isTracking; - -- (void)setPosition:(CGFloat)position; -- (void)setDownloadProgress:(CGFloat)progress; - -- (void)setTintColor:(UIColor *)tintColor; - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPlayerScrubber.m b/submodules/LegacyComponents/Sources/TGEmbedPlayerScrubber.m deleted file mode 100644 index 3837876bb9..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPlayerScrubber.m +++ /dev/null @@ -1,174 +0,0 @@ -#import "TGEmbedPlayerScrubber.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -#import - -const CGFloat TGEmbedPlayerKnobMargin = 8.0f; - -@interface TGEmbedPlayerScrubber () -{ - UIImageView *_backgroundView; - UIView *_downloadProgressView; - UIImageView *_playPositionView; - - UIControl *_knobView; - - CGFloat _position; - CGFloat _downloadProgress; - - CGFloat _knobDragPosition; - bool _tracking; - - UIPanGestureRecognizer *_panGestureRecognizer; -} -@end - -@implementation TGEmbedPlayerScrubber - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.hitTestEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20); - - UIImage *hollowTrackImage = [TGComponentsImageNamed(@"EmbedVideoTrackHollow") resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)]; - _backgroundView = [[UIImageView alloc] initWithImage:hollowTrackImage]; - [self addSubview:_backgroundView]; - - _downloadProgressView = [[UIView alloc] initWithFrame:CGRectZero]; - _downloadProgressView.backgroundColor = [UIColor blackColor]; - [self addSubview:_downloadProgressView]; - - static UIImage *trackImage = nil; - static dispatch_once_t onceToken1; - dispatch_once(&onceToken1, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(3.0f, 3.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0, 0, 3.0f, 3.0f)); - trackImage = [UIGraphicsGetImageFromCurrentImageContext() resizableImageWithCapInsets:UIEdgeInsetsMake(0, 1, 0, 1)]; - UIGraphicsEndImageContext(); - }); - - _playPositionView = [[UIImageView alloc] initWithImage:trackImage]; - [self addSubview:_playPositionView]; - - static UIImage *knobViewImage = nil; - static dispatch_once_t onceToken2; - dispatch_once(&onceToken2, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(21.0f, 21.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetShadowWithColor(context, CGSizeMake(0, 1.0f), 2.0f, [UIColor colorWithWhite:0.0f alpha:0.5f].CGColor); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(3.0f, 3.0f, 15.0f, 15.0f)); - knobViewImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - _knobView = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 21.0f, 21.0f)]; - _knobView.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10); - [self addSubview:_knobView]; - - UIImageView *knobBackground = [[UIImageView alloc] initWithImage:knobViewImage]; - [_knobView addSubview:knobBackground]; - - _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - [_knobView addGestureRecognizer:_panGestureRecognizer]; - } - return self; -} - -- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer -{ - CGPoint touchLocation = [gestureRecognizer locationInView:self]; - - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateBegan: - { - _tracking = true; - - if (self.onInteractionStart != nil) - self.onInteractionStart(); - } - case UIGestureRecognizerStateChanged: - { - _knobDragPosition = [self knobPositionForX:touchLocation.x]; - - [self setNeedsLayout]; - - if (self.onSeek != nil) - self.onSeek(_knobDragPosition); - } - break; - - case UIGestureRecognizerStateEnded: - case UIGestureRecognizerStateCancelled: - { - _tracking = false; - _position = _knobDragPosition; - [self setNeedsLayout]; - - if (self.onInteractionEnd != nil) - self.onInteractionEnd(); - } - break; - - default: - break; - } -} - -- (bool)isTracking -{ - return _knobView.highlighted; -} - -- (void)setPosition:(CGFloat)position -{ - _position = position; - [self setNeedsLayout]; -} - -- (void)setDownloadProgress:(CGFloat)progress -{ - _downloadProgress = progress; - [self setNeedsLayout]; -} - -- (void)setTintColor:(UIColor *)tintColor -{ - UIImage *tintedImage = [TGTintedImage(TGComponentsImageNamed(@"EmbedVideoTrackHollow"), tintColor) resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)]; - _backgroundView.image = tintedImage; - _downloadProgressView.backgroundColor = tintColor; -} - -- (CGFloat)knobPositionRange -{ - return MAX(0.0f, self.bounds.size.width - TGEmbedPlayerKnobMargin * 2); -} - -- (CGFloat)knobPositionForX:(CGFloat)x -{ - return MAX(0, MIN(1.0f, (x - TGEmbedPlayerKnobMargin) / [self knobPositionRange])); -} - -- (void)layoutSubviews -{ - _backgroundView.frame = self.bounds; - - CGFloat downloadProgressRange = MAX(0.0f, self.bounds.size.width - 2.0f); - _downloadProgressView.frame = CGRectMake(1.0f, 1.0f, TGRetinaFloor(_downloadProgress * downloadProgressRange), 1.0f); - - CGFloat position = _tracking ? _knobDragPosition : _position; - _knobView.center = CGPointMake(TGRetinaCeil(TGEmbedPlayerKnobMargin + position * [self knobPositionRange]), 1.5f); - - _playPositionView.frame = CGRectMake(0, 0, _knobView.center.x, 3.0f); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPlayerState.m b/submodules/LegacyComponents/Sources/TGEmbedPlayerState.m deleted file mode 100644 index b861c4fea9..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPlayerState.m +++ /dev/null @@ -1,29 +0,0 @@ -#import "TGEmbedPlayerState.h" - -@implementation TGEmbedPlayerState - -@synthesize playing = _playing; -@synthesize duration = _duration; -@synthesize position = _position; -@synthesize downloadProgress = _downloadProgress; -@synthesize buffering = _buffering; - -+ (instancetype)stateWithPlaying:(bool)playing -{ - TGEmbedPlayerState *state = [[TGEmbedPlayerState alloc] init]; - state->_playing = playing; - return state; -} - -+ (instancetype)stateWithPlaying:(bool)playing duration:(NSTimeInterval)duration position:(NSTimeInterval)position downloadProgress:(CGFloat)downloadProgress buffering:(bool)buffering -{ - TGEmbedPlayerState *state = [[TGEmbedPlayerState alloc] init]; - state->_playing = playing; - state->_duration = duration; - state->_position = position; - state->_downloadProgress = downloadProgress; - state->_buffering = buffering; - return state; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedPlayerView.m b/submodules/LegacyComponents/Sources/TGEmbedPlayerView.m deleted file mode 100644 index 9d4430164b..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedPlayerView.m +++ /dev/null @@ -1,948 +0,0 @@ -#import "TGEmbedPlayerView.h" - -#import "LegacyComponentsInternal.h" - -#import - -#import - -#import "TGEmbedPlayerState.h" - -#import "TGEmbedYoutubePlayerView.h" -#import "TGEmbedVimeoPlayerView.h" -#import "TGEmbedCoubPlayerView.h" -#import "TGEmbedVKPlayerView.h" -#import "TGEmbedVinePlayerView.h" -#import "TGEmbedInstagramPlayerView.h" -#import "TGEmbedSoundCloudPlayerView.h" -#import "TGEmbedTwitchPlayerView.h" -#import "TGEmbedVideoPlayerView.h" - -#import - -@interface TGEmbedPlayerView () -{ - CGFloat _embedScale; - - TGImageView *_coverView; - UIView *_dimView; - UILabel *_errorLabel; - - UIWebView *_uiWebView; - WKWebView *_wkWebView; - - UIView *_interactionView; - - CGSize _maxPlayerSize; - - bool _loading; - - dispatch_semaphore_t _sema; - SQueue *_jsQueue; - - SPipe *_statePipe; - - bool _pausedManually; - bool _shouldResumePIPPlayback; - - id _currentAudioSession; - - SVariable *_loadProgressValue; -} -@end - -@implementation TGEmbedPlayerView - -@synthesize requestPictureInPicture = _requestPictureInPicture; -@synthesize disallowPIP = _disallowPIP; -@synthesize initialFrame = _initialFrame; - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage -{ - return [self initWithWebPageAttachment:webPage thumbnailSignal:nil]; -} - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal -{ - return [self initWithWebPageAttachment:webPage thumbnailSignal:nil alternateCachePathSignal:nil]; -} - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal alternateCachePathSignal:(SSignal *)__unused alternateCachePathSignal -{ - self = [super initWithFrame:CGRectZero]; - if (self != nil) - { - self.clipsToBounds = true; - - _statePipe = [[SPipe alloc] init]; - _loadProgressValue = [[SVariable alloc] init]; - - _webPage = webPage; - _state = [TGEmbedPlayerState stateWithPlaying:false duration:0.0 position:0.0 downloadProgress:0.0f buffering:false]; - - TGEmbedPlayerControlsType controlsType = [self _controlsType]; - if (controlsType != TGEmbedPlayerControlsTypeNone) - { - __weak TGEmbedPlayerView *weakSelf = self; - _controlsView = [[TGEmbedPlayerControls alloc] initWithFrame:CGRectZero type:controlsType]; - _controlsView.playPressed = ^ - { - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf playVideo]; - }; - _controlsView.pausePressed = ^ - { - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf pauseVideo]; - }; - _controlsView.seekToPosition = ^(CGFloat position) - { - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf seekToFractPosition:position]; - }; - _controlsView.fullscreenPressed = ^ - { - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf enterFullscreen:0.0]; - }; - _controlsView.pictureInPicturePressed = ^ - { - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf _pictureInPicturePressed]; - }; - _controlsView.watermarkPressed = ^ - { - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil && !strongSelf.disableWatermarkAction) - [strongSelf _watermarkAction]; - }; - _controlsView.panelVisibilityChange = ^(bool hidden) - { - if (hidden) - return; - - __strong TGEmbedPlayerView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf _onPanelAppearance]; - }; - [_controlsView setPictureInPictureHidden:![self supportsPIP]]; - [self addSubview:_controlsView]; - } - - CGSize imageSize = CGSizeZero; - if (webPage.photo != nil) - [webPage.photo.imageInfo closestImageUrlWithSize:CGSizeMake(1136, 1136) resultingSize:&imageSize]; - - CGFloat imageAspect = imageSize.width / imageSize.height; - CGSize fitSize = CGSizeMake(215.0f, 180.0f); - if (ABS(imageAspect - 1.0f) < FLT_EPSILON) - fitSize = CGSizeMake(215.0f, 215.0f); - - imageSize = TGScaleToFill(imageSize, fitSize); - - _dimWrapperView = [[UIView alloc] init]; - _dimWrapperView.backgroundColor = [UIColor blackColor]; - [self addSubview:_dimWrapperView]; - - SSignal *coverSignal = thumbnailSignal ?: [[LegacyComponentsGlobals provider] squarePhotoThumbnail:webPage.photo ofSize:imageSize threadPool:[[LegacyComponentsGlobals provider] sharedMediaImageProcessingThreadPool] memoryCache:[[LegacyComponentsGlobals provider] sharedMediaMemoryImageCache] pixelProcessingBlock:nil downloadLargeImage:false placeholder:nil]; - - _coverView = [[TGImageView alloc] init]; - _coverView.contentMode = UIViewContentModeScaleAspectFill; - [_coverView setSignal:coverSignal]; - [_dimWrapperView addSubview:_coverView]; - - _dimView = [[UIView alloc] init]; - _dimView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _dimView.backgroundColor = UIColorRGBA(0x000000, 0.5f); - [_dimWrapperView addSubview:_dimView]; - - _overlayView = [[TGMessageImageViewOverlayView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 44.0f, 44.0f)]; - [_overlayView setRadius:44.0f]; - [_dimWrapperView addSubview:_overlayView]; - - _errorLabel = [[UILabel alloc] init]; - _errorLabel.backgroundColor = [UIColor clearColor]; - _errorLabel.font = TGSystemFontOfSize(16.0f); - _errorLabel.hidden = true; - _errorLabel.text = TGLocalized(@"Web.Error"); - _errorLabel.textColor = [UIColor whiteColor]; - [_errorLabel sizeToFit]; - [_dimWrapperView addSubview:_errorLabel]; - - if (iosMajorVersion() >= 11) - { - _coverView.accessibilityIgnoresInvertColors = true; - _dimView.accessibilityIgnoresInvertColors = true; - _overlayView.accessibilityIgnoresInvertColors = true; - _errorLabel.accessibilityIgnoresInvertColors = true; - } - - _interactionView = [[UIView alloc] initWithFrame:self.bounds]; - _interactionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _interactionView.hidden = true; - [self addSubview:_interactionView]; - - _jsQueue = [[SQueue alloc] init]; - _sema = dispatch_semaphore_create(0); - } - return self; -} - -- (void)dealloc -{ - WKWebView *wkWebView = _wkWebView; - [_jsQueue dispatchSync:^ - { - wkWebView.navigationDelegate = nil; - }]; - - _uiWebView.delegate = nil; - - [_currentAudioSession dispose]; - - [[LegacyComponentsGlobals provider] resumePictureInPicturePlayback]; - - TGDispatchAfter(0.1, dispatch_get_main_queue(), ^ - { - [[LegacyComponentsGlobals provider] maybeReleaseVolumeOverlay]; - }); -} - -- (void)setDisallowPIP:(bool)disallowPIP -{ - _disallowPIP = disallowPIP; - [_controlsView setPictureInPictureHidden:disallowPIP]; -} - -- (void)setDisallowAutoplay:(bool)disallowAutoplay -{ - _disallowAutoplay = disallowAutoplay; - _dimView.hidden = true; - - [_controlsView showLargePlayButton:true]; - [self insertSubview:_dimWrapperView belowSubview:_controlsView]; -} - -- (void)setDisableControls:(bool)disableControls { - _disableControls = disableControls; - if (disableControls) { - for (UIView *view in [_dimWrapperView.subviews copy]) { - if (view != _coverView) { - view.alpha = 0.0f; - view.hidden = true; - } - } - _controlsView.hidden = true; - _dimView.hidden = true; - } -} - -- (void)_setupAudioSessionIfNeeded -{ - if (_currentAudioSession != nil) - return; - - _currentAudioSession = [[LegacyComponentsGlobals provider] requestAudioSession:TGAudioSessionTypePlayEmbedVideo interrupted:^{}]; -} - -- (void)setupWithEmbedSize:(CGSize)embedSize -{ - if (!self.disallowAutoplay || iosMajorVersion() < 8) - [self _setupAudioSessionIfNeeded]; - - CGFloat horEdge = [self _compensationEdges]; - CGFloat verEdge = horEdge * embedSize.width / embedSize.height; - - _embedSize = CGSizeMake(embedSize.width + horEdge * 2.0f, embedSize.height + verEdge * 2.0f); - - CGSize screenSize = TGScreenSize(); - screenSize = CGSizeMake(screenSize.height, screenSize.width); - _maxPlayerSize = [self _scaleViewToMaxSize] ? TGScaleToSize(embedSize, screenSize) : _embedSize; - _embedScale = _embedSize.width / _maxPlayerSize.width; - - if (iosMajorVersion() >= 8) - [self setupWKWebView]; - else - [self setupUIWebView]; - - if (!self.disallowAutoplay) - { - _overlayView.hidden = false; - [self setLoadProgress:0.01f duration:0.01]; - [_loadProgressValue set:[SSignal single:@(0.01f)]]; - } -} - -- (CGFloat)_compensationEdges -{ - return 0.0f; -} - -- (SSignal *)loadProgress { - return [_loadProgressValue signal]; -} - -- (void)hideControls -{ - [_controlsView hidePlayButton]; -} - -- (void)switchToPictureInPicture -{ - [self _pictureInPicturePressed]; -} - -- (void)_requestSystemPictureInPictureMode -{ - [self _evaluateJS:@"injectCmd('switchToPIP');" completion:^(__unused NSString *result) - { - }]; -} - -- (void)pausePIPPlayback -{ - if (_pausedManually) - return; - - _shouldResumePIPPlayback = true; - [self pauseVideo:false]; -} - -- (void)resumePIPPlayback -{ - if (_shouldResumePIPPlayback) - [self playVideo]; - - _shouldResumePIPPlayback = false; -} - -- (bool)supportsPIP -{ - CGSize screenSize = TGScreenSize(); - return !self.disallowPIP && (int)screenSize.height != 480; -} - -- (void)setDimmed:(bool)dimmed animated:(bool)animated -{ - [self setDimmed:dimmed animated:animated shouldDelay:false]; -} - -- (void)setDimmed:(bool)dimmed animated:(bool)animated shouldDelay:(bool)shouldDelay -{ - bool useFakeProgress = [self _useFakeLoadingProgress]; - if (animated) - { - if (dimmed) - { - _overlayView.hidden = false; - if (useFakeProgress) { - [self setLoadProgress:0.88f duration:3.0]; - [_loadProgressValue set:[SSignal single:@(0.88f)]]; - } - - _dimWrapperView.hidden = false; - _dimWrapperView.alpha = 1.0f; - } - else - { - [self setLoadProgress:1.0f duration:0.2]; - [_loadProgressValue set:[SSignal single:@(1.0f)]]; - - NSTimeInterval delay = shouldDelay ? 0.4 : 0.0; - [UIView animateWithDuration:0.2 delay:delay options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionCurveLinear animations:^ - { - _dimWrapperView.alpha = 0.0f; - } completion:^(__unused BOOL finished) - { - _dimWrapperView.hidden = true; - _dimWrapperView.alpha = 1.0f; - }]; - } - } - else - { - _dimWrapperView.hidden = !dimmed; - - _overlayView.hidden = !dimmed; - if (dimmed && useFakeProgress) { - [self setLoadProgress:0.88f duration:3.0]; - [_loadProgressValue set:[SSignal single:@(0.88f)]]; - } - else - [_overlayView setNone]; - } -} - -- (void)setLoadProgress:(CGFloat)value duration:(NSTimeInterval)duration -{ - [_overlayView setProgressAnimated:value duration:duration cancelEnabled:false]; - [_loadProgressValue set:[SSignal single:@(value)]]; -} - -- (bool)_useFakeLoadingProgress -{ - return true; -} - -- (void)setCoverImage:(UIImage *)image -{ - [_coverView setSignal:[SSignal single:image]]; -} - -#pragma mark - - -- (void)beginLeavingFullscreen -{ - UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:self.roundCorners cornerRadii:CGSizeMake(14.5f, 14.5f)]; - - CAShapeLayer *maskLayer = [CAShapeLayer layer]; - maskLayer.frame = self.bounds; - maskLayer.path = maskPath.CGPath; - - self.layer.mask = maskLayer; -} - -- (void)finishedLeavingFullscreen -{ - self.layer.mask = nil; -} - -- (void)onLockInPlace -{ - [_controlsView setFullscreenButtonHidden:false animated:true]; -} - -- (void)setInhibitFullscreenButton:(bool)inhibitFullscreenButton -{ - _inhibitFullscreenButton = inhibitFullscreenButton; - _controlsView.inhibitFullscreenButton = inhibitFullscreenButton; -} - -#pragma mark - - -- (void)setupWKWebView -{ - WKUserContentController *contentController = [[WKUserContentController alloc] init]; - - if ([self _applyViewportUserScript]) - { - NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"; - WKUserScript *viewportScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:true]; - [contentController addUserScript:viewportScript]; - } - - [self _setupUserScripts:contentController]; - - WKWebViewConfiguration *conf = [[WKWebViewConfiguration alloc] init]; - conf.allowsInlineMediaPlayback = true; - conf.userContentController = contentController; - - if ([conf respondsToSelector:@selector(setRequiresUserActionForMediaPlayback:)]) - conf.requiresUserActionForMediaPlayback = false; - else if ([conf respondsToSelector:@selector(setMediaPlaybackRequiresUserAction:)]) - conf.mediaPlaybackRequiresUserAction = false; - - if ([conf respondsToSelector:@selector(setAllowsPictureInPictureMediaPlayback:)] && !TGIsPad()) - conf.allowsPictureInPictureMediaPlayback = false; - - _wkWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf]; - _wkWebView.navigationDelegate = self; - _wkWebView.scrollView.scrollEnabled = false; - if (iosMajorVersion() >= 11) - _wkWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; - - NSString *embedHTML = [self _embedHTML]; - bool useURL = (embedHTML.length == 0); - [self commonSetupWithWebView:_wkWebView useURL:useURL completion:^(NSURLRequest *request) - { - if (useURL) - [_wkWebView loadRequest:request]; - else - [_wkWebView loadHTMLString:embedHTML baseURL:[self _baseURL]]; - }]; -} - -- (void)webView:(WKWebView *)__unused webView didStartProvisionalNavigation:(WKNavigation *)__unused navigation -{ - if (_loading) - return; - - _loading = true; - if (!self.disallowAutoplay) - [self setDimmed:true animated:false]; - - if (self.onBeganLoading != nil) - self.onBeganLoading(); -} - -- (void)webView:(WKWebView *)__unused webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler -{ - NSURL *url = navigationAction.request.URL; - if (![url.scheme isEqualToString:@"http"] && ![url.scheme isEqualToString:@"https"] && ![url.absoluteString isEqualToString:@"about:blank"]) - { - [self _notifyOfCallbackURL:url]; - decisionHandler(WKNavigationActionPolicyCancel); - } - else - { - if (navigationAction.targetFrame == nil) - { - [self _openWebPage:url]; - decisionHandler(WKNavigationActionPolicyCancel); - } - else - { - decisionHandler(WKNavigationActionPolicyAllow); - } - } -} - -- (void)webView:(WKWebView *)__unused webView didFinishNavigation:(WKNavigation *)__unused navigation -{ - if (!_loading) - return; - - _loading = false; - [self _onPageReady]; -} - -- (void)webView:(WKWebView *)__unused webView didFailNavigation:(WKNavigation *)__unused navigation withError:(NSError *)__unused error -{ - if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 204) - return; - - if (!_loading) - return; - - _loading = false; - _overlayView.hidden = true; - [_overlayView setNone]; - _errorLabel.hidden = false; -} - -#pragma mark - - -- (void)setupUIWebView -{ - _uiWebView = [[UIWebView alloc] initWithFrame:CGRectZero]; - _uiWebView.mediaPlaybackRequiresUserAction = false; - _uiWebView.delegate = self; - _uiWebView.scrollView.scrollEnabled = false; - - NSString *embedHTML = [self _embedHTML]; - bool useURL = (embedHTML.length == 0); - [self commonSetupWithWebView:_uiWebView useURL:useURL completion:^(NSURLRequest *request) - { - if (useURL) - [_uiWebView loadRequest:request]; - else - [_uiWebView loadHTMLString:embedHTML baseURL:[self _baseURL]]; - }]; -} - -- (BOOL)webView:(UIWebView *)__unused webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)__unused navigationType -{ - NSURL *url = request.URL; - if (![url.scheme isEqualToString:@"http"] && ![url.scheme isEqualToString:@"https"] && ![url.absoluteString isEqualToString:@"about:blank"]) - { - [self _notifyOfCallbackURL:url]; - return false; - } - - return true; -} - -- (void)webViewDidStartLoad:(UIWebView *)__unused webView -{ - if (_loading) - return; - - _loading = true; - [self setDimmed:true animated:false]; - - if (self.onBeganLoading != nil) - self.onBeganLoading(); -} - -- (void)webViewDidFinishLoad:(UIWebView *)__unused webView -{ - if (!_loading) - return; - - _loading = false; - [self _onPageReady]; -} - -- (void)webView:(UIWebView *)__unused webView didFailLoadWithError:(NSError *)__unused error -{ - if (!_loading) - return; - - _loading = false; - _overlayView.hidden = true; - [_overlayView setNone]; - _errorLabel.hidden = false; -} - -- (void)commonSetupWithWebView:(UIView *)webView useURL:(bool)useURL completion:(void (^)(NSURLRequest *))completion -{ - CGFloat horEdge = [self _compensationEdges]; - CGFloat verEdge = horEdge * _embedSize.width / _embedSize.height; - - if (iosMajorVersion() >= 11) - webView.accessibilityIgnoresInvertColors = true; - - webView.backgroundColor = [UIColor blackColor]; - webView.frame = CGRectMake(0, 0, _maxPlayerSize.width, _maxPlayerSize.height); - webView.transform = CGAffineTransformMakeScale(_embedScale, _embedScale); - webView.center = CGPointMake((_embedSize.width - horEdge * 2.0f) / 2.0f, (_embedSize.height - verEdge * 2.0f) / 2.0f); - - if (_controlsView != nil && !_disallowAutoplay) - [self insertSubview:webView belowSubview:_controlsView]; - else - [self insertSubview:webView belowSubview:_dimWrapperView]; - - if (useURL) - { - NSURL *url = [self _embedURL]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - NSString *referer = [[NSString alloc] initWithFormat:@"%@://%@", [url scheme], [url host]]; - [request setValue:referer forHTTPHeaderField:@"Referer"]; - - if (completion != nil) - completion(request); - } - else - { - if (completion != nil) - completion(nil); - } -} - -#pragma mark - - -- (void)_openWebPage:(NSURL *)url -{ - [[LegacyComponentsGlobals provider] openURLNative:url]; -} - -- (void)playVideo -{ - if (_disallowAutoplay) - _dimWrapperView.hidden = true; - - [self _setupAudioSessionIfNeeded]; -} - -- (void)pauseVideo -{ - [self pauseVideo:true]; -} - -- (void)pauseVideo:(bool)manually -{ - _pausedManually = manually; -} - -- (void)seekToPosition:(NSTimeInterval)__unused position -{ - -} - -- (void)seekToFractPosition:(CGFloat)position -{ - NSTimeInterval timePosition = self.state.duration * position; - [self seekToPosition:timePosition]; -} - -- (void)enterFullscreen:(NSTimeInterval)duration -{ - if (self.requestFullscreen != nil) - self.requestFullscreen(duration); -} - -- (void)enterPictureInPicture:(TGEmbedPIPCorner)corner -{ - if (self.requestPictureInPicture != nil) - self.requestPictureInPicture(corner); -} - -- (void)_pictureInPicturePressed -{ - [self enterPictureInPicture:TGEmbedPIPCornerNone]; -} - -- (SSignal *)stateSignal -{ - return _statePipe.signalProducer(); -} - -- (void)updateState:(TGEmbedPlayerState *)state -{ - _state = state; - [_controlsView setState:state]; - - _statePipe.sink(state); -} - -#pragma mark - - -- (void)_onPageReady -{ - [self setDimmed:false animated:true]; -} - -- (void)_didBeginPlayback -{ - [_controlsView notifyOfPlaybackStart]; - - [[LegacyComponentsGlobals provider] pausePictureInPicturePlayback]; - - if (self.onBeganPlaying != nil) - self.onBeganPlaying(); -} - -- (void)_onPanelAppearance -{ - -} - -- (void)_watermarkAction -{ - [self pauseVideo]; -} - -- (void)_prepareToEnterFullscreen -{ - [_controlsView setWatermarkHidden:true]; - [_controlsView setHidden:true animated:true]; - _interactionView.hidden = false; -} - -- (void)_prepareToLeaveFullscreen -{ - [_controlsView setWatermarkHidden:false]; - [_controlsView setHidden:false animated:true]; - _interactionView.hidden = true; -} - -#pragma mark - - -- (TGEmbedPlayerControlsType)_controlsType -{ - return TGEmbedPlayerControlsTypeNone; -} - -- (void)_evaluateJS:(NSString *)jsString completion:(void (^)(NSString *))completion -{ - if (_wkWebView != nil) - { - [_jsQueue dispatch:^ - { - void (^block)(void) = ^ - { - [_wkWebView evaluateJavaScript:jsString completionHandler:^(id result, __unused NSError *error) - { - dispatch_semaphore_signal(_sema); - TGDispatchOnMainThread(^ - { - if (completion != nil) - completion(result); - }); - }]; - }; - - if (iosMajorVersion() >= 11) - TGDispatchOnMainThread(block); - else - block(); - - dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER); - }]; - } - else if (_uiWebView != nil) - { - NSString *result = [_uiWebView stringByEvaluatingJavaScriptFromString:jsString]; - if (completion != nil) - completion(result); - } -} - -- (NSString *)_embedHTML -{ - NSString *path = TGComponentsPathForResource(@"DefaultPlayer", @"html"); - NSError *error = nil; - NSString *embedHTMLTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - if (error != nil) - { - TGLegacyLog(@"[DefaultEmbedPlayer]: Received error rendering template: %@", error); - return nil; - } - - NSString *embedHTML = [NSString stringWithFormat:embedHTMLTemplate, [self _embedURL].absoluteString]; - return embedHTML; -} - -- (NSURL *)_embedURL -{ - return [NSURL URLWithString:_webPage.embedUrl]; -} - -- (NSURL *)_baseURL -{ - return [NSURL URLWithString:@"about:blank"]; -} - -- (void)_setupUserScripts:(WKUserContentController *)__unused contentController -{ - NSError *error = nil; - NSString *path = TGComponentsPathForResource(@"DefaultPlayerInject", @"js"); - NSString *scriptText = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - if (error != nil) - TGLegacyLog(@"[DefaultEmbedPlayer]: Received error loading inject script: %@", error); - - WKUserScript *script = [[WKUserScript alloc] initWithSource:scriptText injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:false]; - [contentController addUserScript:script]; -} - -- (bool)_applyViewportUserScript -{ - return true; -} - -- (void)_notifyOfCallbackURL:(NSURL *)__unused url -{ - -} - -- (UIView *)_webView -{ - if (_wkWebView != nil) - return _wkWebView; - else if (_uiWebView != nil) - return _uiWebView; - - return nil; -} - -- (bool)_scaleViewToMaxSize -{ - return false; -} - -- (void)_cleanWebView -{ - _wkWebView.navigationDelegate = nil; - [_wkWebView removeFromSuperview]; - _wkWebView = nil; - - _uiWebView.delegate = nil; - [_uiWebView removeFromSuperview]; - _uiWebView = nil; -} - -+ (bool)_supportsWebPage:(TGWebPageMediaAttachment *)__unused webPage -{ - return true; -} - -+ (Class)playerViewClassForWebPage:(TGWebPageMediaAttachment *)webPage onlySpecial:(bool)onlySpecial -{ - static dispatch_once_t onceToken; - static NSArray *playerViewClasses; - dispatch_once(&onceToken, ^ - { - playerViewClasses = @ - [ - [TGEmbedYoutubePlayerView class], - [TGEmbedVimeoPlayerView class], - [TGEmbedCoubPlayerView class], - [TGEmbedVKPlayerView class], - [TGEmbedVinePlayerView class], - [TGEmbedInstagramPlayerView class], - [TGEmbedSoundCloudPlayerView class], - [TGEmbedTwitchPlayerView class], - [TGEmbedVideoPlayerView class] - ]; - }); - - if (iosMajorVersion() >= 8) - { - for (Class playerViewClass in playerViewClasses) - { - if ([playerViewClass _supportsWebPage:webPage]) - { - if (playerViewClass == [TGEmbedVideoPlayerView class] && onlySpecial) - return nil; - - return playerViewClass; - } - } - } - - if (onlySpecial) - return nil; - - return self; -} - -- (void)layoutSubviews -{ - _dimWrapperView.frame = self.bounds; - _coverView.frame = _dimWrapperView.bounds; - _overlayView.center = CGPointMake(CGRectGetMidX(_dimWrapperView.bounds), CGRectGetMidY(_dimWrapperView.bounds)); - _errorLabel.center = _overlayView.center; - _controlsView.frame = self.bounds; -} - -+ (TGEmbedPlayerView *)makePlayerViewForWebPage:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)signal { - Class playerClass = [self playerViewClassForWebPage:webPage onlySpecial:false]; - if (playerClass != nil) { - return [[playerClass alloc] initWithWebPageAttachment:webPage thumbnailSignal:signal]; - } else { - return nil; - } -} - -+ (bool)hasNativeSupportForX:(TGWebPageMediaAttachment *)webPage { - static dispatch_once_t onceToken; - static NSArray *playerViewClasses; - dispatch_once(&onceToken, ^ - { - playerViewClasses = @ - [ - [TGEmbedYoutubePlayerView class], - /*[TGEmbedVimeoPlayerView class], - [TGEmbedCoubPlayerView class], - [TGEmbedVKPlayerView class], - [TGEmbedVinePlayerView class], - [TGEmbedInstagramPlayerView class], - [TGEmbedSoundCloudPlayerView class], - [TGEmbedTwitchPlayerView class], - [TGEmbedVideoPlayerView class]*/ - ]; - }); - - if (iosMajorVersion() >= 8) - { - for (Class playerViewClass in playerViewClasses) - { - if ([playerViewClass _supportsWebPage:webPage]) - { - if (playerViewClass == [TGEmbedVideoPlayerView class]) - return false; - - return true; - } - } - } - - return false; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedSoundCloudPlayerView.h b/submodules/LegacyComponents/Sources/TGEmbedSoundCloudPlayerView.h deleted file mode 100644 index 15d33b7e5c..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedSoundCloudPlayerView.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "TGEmbedPlayerView.h" - -@interface TGEmbedSoundCloudPlayerView : TGEmbedPlayerView - -+ (NSString *)_soundCloudIdFromText:(NSString *)text; - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedSoundCloudPlayerView.m b/submodules/LegacyComponents/Sources/TGEmbedSoundCloudPlayerView.m deleted file mode 100644 index 924bc693a8..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedSoundCloudPlayerView.m +++ /dev/null @@ -1,64 +0,0 @@ -#import "TGEmbedSoundCloudPlayerView.h" - -@implementation TGEmbedSoundCloudPlayerView - -- (NSURL *)_embedURL -{ - NSString *trackId = [TGEmbedSoundCloudPlayerView _soundCloudIdFromText:_webPage.embedUrl]; - - NSString *url = [NSString stringWithFormat:@"https://w.soundcloud.com/player/?url=https%%3A%%2F%%2Fapi.soundcloud.com%%2Ftracks%%2F%@&auto_play=true&show_artwork=true&visual=true&liking=false&download=false&sharing=false&buying=false&hide_related=true&show_comments=false&show_user=true&show_reposts=false", trackId]; - return [NSURL URLWithString:url]; -} - -+ (NSString *)_soundCloudIdFromText:(NSString *)text -{ - NSMutableArray *prefixes = [NSMutableArray arrayWithArray:@ - [ - @"http://w.soundcloud.com/player/?url=", - @"https://w.soundcloud.com/player/?url=" - ]]; - - NSString *prefix = nil; - for (NSString *p in prefixes) - { - if ([text hasPrefix:p]) - { - prefix = p; - break; - } - } - - if (prefix == nil) - return nil; - - NSString *suffix = [[text substringFromIndex:prefix.length] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSArray *components = [suffix componentsSeparatedByString:@"&"]; - if (components.count < 2) - return nil; - - - NSString *url = components.firstObject; - components = [url componentsSeparatedByString:@"/"]; - - if (components.count < 1) - return nil; - - NSString *identifier = components.lastObject; - - for (int i = 0; i < (int)identifier.length; i++) - { - unichar c = [identifier characterAtIndex:i]; - if (!(c >= '0' && c <= '9')) - return nil; - } - - return identifier; -} - -+ (bool)_supportsWebPage:(TGWebPageMediaAttachment *)webPage -{ - NSString *url = webPage.embedUrl; - return ([url hasPrefix:@"http://w.soundcloud.com/player/"] || [url hasPrefix:@"https://w.soundcloud.com/player/"]); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedTwitchPlayerView.h b/submodules/LegacyComponents/Sources/TGEmbedTwitchPlayerView.h deleted file mode 100644 index 12697a35e1..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedTwitchPlayerView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface TGEmbedTwitchPlayerView : TGEmbedPlayerView - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedTwitchPlayerView.m b/submodules/LegacyComponents/Sources/TGEmbedTwitchPlayerView.m deleted file mode 100644 index 73ed01b515..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedTwitchPlayerView.m +++ /dev/null @@ -1,107 +0,0 @@ -#import "TGEmbedTwitchPlayerView.h" -#import "TGEmbedPlayerState.h" - -#import "LegacyComponentsInternal.h" - -@interface TGEmbedTwitchPlayerView () -{ - bool _started; -} -@end - -@implementation TGEmbedTwitchPlayerView - -- (void)playVideo -{ - if (!_started) - return; - - [self _evaluateJS:@"injectCmd('play')" completion:nil]; - - TGEmbedPlayerState *newState = [TGEmbedPlayerState stateWithPlaying:true duration:0.0 position:-1.0 downloadProgress:0.0 buffering:false]; - [self updateState:newState]; -} - -- (void)pauseVideo:(bool)manually -{ - [super pauseVideo:manually]; - [self _evaluateJS:@"injectCmd('play')" completion:nil]; - - TGEmbedPlayerState *newState = [TGEmbedPlayerState stateWithPlaying:false duration:0.0 position:-1.0 downloadProgress:0.0 buffering:false]; - [self updateState:newState]; -} - -- (void)_onPageReady -{ - TGDispatchAfter(0.5, dispatch_get_main_queue(), ^ - { - [super _onPageReady]; - }); - - TGEmbedPlayerState *newState = [TGEmbedPlayerState stateWithPlaying:false duration:0.0 position:-1.0 downloadProgress:0.0 buffering:false]; - [self updateState:newState]; -} - -- (TGEmbedPlayerControlsType)_controlsType -{ - return TGEmbedPlayerControlsTypeFull; -} - -- (void)_notifyOfCallbackURL:(NSURL *)url -{ - NSString *action = url.host; - - NSString *query = url.query; - NSString *data; - if (query != nil) - data = [query componentsSeparatedByString:@"="][1]; - - if ([action isEqualToString:@"onPlayback"]) - { - if (!_started) - { - _started = true; - [self _didBeginPlayback]; - } - - TGEmbedPlayerState *newState = [TGEmbedPlayerState stateWithPlaying:true duration:0.0 position:-1.0 downloadProgress:0.0 buffering:false]; - [self updateState:newState]; - } -} - -- (NSString *)_embedHTML -{ - NSError *error = nil; - NSString *path = TGComponentsPathForResource(@"TwitchPlayer", @"html"); - - NSString *embedHTMLTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - if (error != nil) - { - TGLegacyLog(@"[TwitchEmbedPlayer]: Received error rendering template: %@", error); - return nil; - } - - NSString *embedHTML = [NSString stringWithFormat:embedHTMLTemplate, _webPage.embedUrl]; - return embedHTML; -} - -- (void)_setupUserScripts:(WKUserContentController *)contentController -{ - NSError *error = nil; - NSString *path = TGComponentsPathForResource(@"TwitchPlayerInject", @"js"); - NSString *scriptText = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - if (error != nil) - TGLegacyLog(@"[TwitchEmbedPlayer]: Received error loading inject script: %@", error); - - WKUserScript *script = [[WKUserScript alloc] initWithSource:scriptText injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:false]; - [contentController addUserScript:script]; -} - -+ (bool)_supportsWebPage:(TGWebPageMediaAttachment *)webPage -{ - NSString *url = webPage.embedUrl; - return ([url hasPrefix:@"http://player.twitch.tv/"] || [url hasPrefix:@"https://player.twitch.tv/"]) - || ([url hasPrefix:@"http://clips.twitch.tv/"] || [url hasPrefix:@"https://clips.twitch.tv/"]); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedVKPlayerView.h b/submodules/LegacyComponents/Sources/TGEmbedVKPlayerView.h deleted file mode 100644 index 9e91fd7590..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedVKPlayerView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGEmbedPlayerView.h" - -@interface TGEmbedVKPlayerView : TGEmbedPlayerView - -@end diff --git a/submodules/LegacyComponents/Sources/TGEmbedVKPlayerView.m b/submodules/LegacyComponents/Sources/TGEmbedVKPlayerView.m deleted file mode 100644 index a7ebebe7d2..0000000000 --- a/submodules/LegacyComponents/Sources/TGEmbedVKPlayerView.m +++ /dev/null @@ -1,288 +0,0 @@ -#import "TGEmbedVKPlayerView.h" - -#import - -#import "TGEmbedYoutubePlayerView.h" -#import "TGEmbedVimeoPlayerView.h" -#import "TGEmbedCoubPlayerView.h" -#import "TGEmbedVideoPlayerView.h" - -@interface TGEmbedVKPlayerView () -{ - NSString *_url; - - TGEmbedPlayerView *_subPlayerView; - SMetaDisposable *_disposable; -} -@end - -@implementation TGEmbedVKPlayerView - -- (instancetype)initWithWebPageAttachment:(TGWebPageMediaAttachment *)webPage thumbnailSignal:(SSignal *)thumbnailSignal alternateCachePathSignal:(SSignal *)alternateCachePathSignal -{ - self = [super initWithWebPageAttachment:webPage thumbnailSignal:thumbnailSignal alternateCachePathSignal:alternateCachePathSignal]; - if (self != nil) - { - _url = webPage.embedUrl; - } - return self; -} - -- (void)dealloc -{ - [_disposable dispose]; -} - -- (void)setFrame:(CGRect)frame -{ - [super setFrame:frame]; - - if (_subPlayerView != nil) - _subPlayerView.frame = self.bounds; -} - -- (void)setRequestFullscreen:(void (^)(NSTimeInterval))requestFullscreen -{ - [super setRequestFullscreen:requestFullscreen]; - - if (_subPlayerView != nil) - [_subPlayerView setRequestFullscreen:requestFullscreen]; -} - -- (void)setRequestPictureInPicture:(void (^)(TGEmbedPIPCorner))requestPictureInPicture -{ - [super setRequestPictureInPicture:requestPictureInPicture]; - - if (_subPlayerView != nil) - [_subPlayerView setRequestPictureInPicture:requestPictureInPicture]; -} - -- (void)_prepareToEnterFullscreen -{ - [super _prepareToEnterFullscreen]; - - if (_subPlayerView != nil) - [_subPlayerView _prepareToEnterFullscreen]; -} - -- (void)_prepareToLeaveFullscreen -{ - [super _prepareToLeaveFullscreen]; - - if (_subPlayerView != nil) - [_subPlayerView _prepareToLeaveFullscreen]; -} - -- (void)playVideo -{ - [super playVideo]; - - if (_subPlayerView != nil) - { - [_subPlayerView playVideo]; - return; - } -} - -- (void)pauseVideo:(bool)manually -{ - [super pauseVideo:manually]; - - if (_subPlayerView != nil) - { - [_subPlayerView pauseVideo:manually]; - return; - } -} - -- (void)seekToPosition:(NSTimeInterval)position -{ - if (_subPlayerView != nil) - { - [_subPlayerView seekToPosition:position]; - return; - } -} - -- (void)onLockInPlace -{ - [super onLockInPlace]; - - if (_subPlayerView != nil) - { - [_subPlayerView onLockInPlace]; - return; - } -} - -- (void)setupWithEmbedSize:(CGSize)embedSize -{ - [super setupWithEmbedSize:embedSize]; - - [self initializePlayer]; - - [self setLoadProgress:0.01f duration:0.01]; -} - -- (void)_requestSystemPictureInPictureMode -{ - if (_subPlayerView != nil) - [_subPlayerView _requestSystemPictureInPictureMode]; - else - [super _requestSystemPictureInPictureMode]; -} - -- (TGEmbedPlayerState *)state -{ - if (_subPlayerView != nil) - return [_subPlayerView state]; - else - return [super state]; -} - -- (SSignal *)stateSignal -{ - if (_subPlayerView != nil) - return [_subPlayerView stateSignal]; - else - return [super stateSignal]; -} - -- (void)initializePlayer -{ - __weak TGEmbedVKPlayerView *weakSelf = self; - SSignal *signal = [[[LegacyComponentsGlobals provider] dataForHttpLocation:_url] map:^NSString *(NSData *data) - { - return [[NSString alloc] initWithData:data encoding:NSWindowsCP1251StringEncoding]; - }]; - - _disposable = [[SMetaDisposable alloc] init]; - [_disposable setDisposable:[[signal deliverOn:[SQueue mainQueue]] startWithNext:^(NSString *next) - { - __strong TGEmbedVKPlayerView *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - NSRange ytRange = [next rangeOfString:@"youtube.com/embed/"]; - if (ytRange.location != NSNotFound) - { - NSString *videoId = [self _getVideoId:next location:ytRange.location + @"youtube.com/embed/".length stopChar:'?']; - if (videoId.length > 0) - { - TGWebPageMediaAttachment *webPage = [[TGWebPageMediaAttachment alloc] init]; - webPage.embedUrl = [NSString stringWithFormat:@"https://www.youtube.com/embed/%@", videoId]; - - [self _setupWithSubPlayerView:[[TGEmbedYoutubePlayerView alloc] initWithWebPageAttachment:webPage]]; - } - } - - NSRange vimeoRange = [next rangeOfString:@"vimeo.com/video/"]; - if (vimeoRange.location != NSNotFound) - { - NSString *videoId = [self _getVideoId:next location:vimeoRange.location + @"vimeo.com/video/".length stopChar:'?']; - if (videoId.length > 0) - { - TGWebPageMediaAttachment *webPage = [[TGWebPageMediaAttachment alloc] init]; - webPage.embedUrl = [NSString stringWithFormat:@"https://player.vimeo.com/video/%@", videoId]; - - [self _setupWithSubPlayerView:[[TGEmbedVimeoPlayerView alloc] initWithWebPageAttachment:webPage]]; - } - } - - NSRange coubRange = [next rangeOfString:@"coub.com/embed/"]; - if (coubRange.location != NSNotFound) - { - NSString *videoId = [self _getVideoId:next location:coubRange.location + @"coub.com/embed/".length stopChar:'"']; - if (videoId.length > 0) - { - TGWebPageMediaAttachment *webPage = [[TGWebPageMediaAttachment alloc] init]; - webPage.embedUrl = [NSString stringWithFormat:@"https://coub.com/embed/%@", videoId]; - - [self _setupWithSubPlayerView:[[TGEmbedCoubPlayerView alloc] initWithWebPageAttachment:webPage]]; - } - } - - NSRange vkRange = [next rangeOfString:@"