Various improvements

This commit is contained in:
Ilya Laktyushin 2023-01-04 11:18:20 +04:00
parent 076129348b
commit c10f020f0a
15 changed files with 203 additions and 154 deletions

View File

@ -58,14 +58,14 @@ public struct SharedMediaPlaybackAlbumArt: Equatable {
} }
public enum SharedMediaPlaybackDisplayData: Equatable { public enum SharedMediaPlaybackDisplayData: Equatable {
case music(title: String?, performer: String?, albumArt: SharedMediaPlaybackAlbumArt?, long: Bool) case music(title: String?, performer: String?, albumArt: SharedMediaPlaybackAlbumArt?, long: Bool, caption: NSAttributedString?)
case voice(author: Peer?, peer: Peer?) case voice(author: Peer?, peer: Peer?)
case instantVideo(author: Peer?, peer: Peer?, timestamp: Int32) case instantVideo(author: Peer?, peer: Peer?, timestamp: Int32)
public static func ==(lhs: SharedMediaPlaybackDisplayData, rhs: SharedMediaPlaybackDisplayData) -> Bool { public static func ==(lhs: SharedMediaPlaybackDisplayData, rhs: SharedMediaPlaybackDisplayData) -> Bool {
switch lhs { switch lhs {
case let .music(lhsTitle, lhsPerformer, lhsAlbumArt, lhsDuration): case let .music(lhsTitle, lhsPerformer, lhsAlbumArt, lhsDuration, lhsCaption):
if case let .music(rhsTitle, rhsPerformer, rhsAlbumArt, rhsDuration) = rhs, lhsTitle == rhsTitle, lhsPerformer == rhsPerformer, lhsAlbumArt == rhsAlbumArt, lhsDuration == rhsDuration { if case let .music(rhsTitle, rhsPerformer, rhsAlbumArt, rhsDuration, rhsCaption) = rhs, lhsTitle == rhsTitle, lhsPerformer == rhsPerformer, lhsAlbumArt == rhsAlbumArt, lhsDuration == rhsDuration, lhsCaption?.string == rhsCaption?.string {
return true return true
} else { } else {
return false return false

View File

@ -2077,6 +2077,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController, U
self._entitiesView = externalEntitiesView self._entitiesView = externalEntitiesView
} else { } else {
self._entitiesView = DrawingEntitiesView(context: self.context, size: controller.size) self._entitiesView = DrawingEntitiesView(context: self.context, size: controller.size)
//self._entitiesView = DrawingEntitiesView(context: self.context, size: controller.originalSize)
} }
self._drawingView?.entitiesView = self._entitiesView self._drawingView?.entitiesView = self._entitiesView
self._entitiesView?.drawingView = self._drawingView self._entitiesView?.drawingView = self._drawingView
@ -2942,7 +2943,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController, U
super.displayNodeDidLoad() super.displayNodeDidLoad()
let dropInteraction = UIDropInteraction(delegate: self) let dropInteraction = UIDropInteraction(delegate: self)
self.view.addInteraction(dropInteraction) self.drawingView.addInteraction(dropInteraction)
} }
public func generateResultData() -> TGPaintingData? { public func generateResultData() -> TGPaintingData? {

View File

@ -94,7 +94,7 @@ final class InstantPageMediaPlaylistItem: SharedMediaPlaylistItem {
albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .standalone(media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .standalone(media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)) albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .standalone(media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .standalone(media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false))
} }
return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: false) return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: false, caption: nil)
} }
case let .Video(_, _, flags): case let .Video(_, _, flags):
if flags.contains(.instantRoundVideo) { if flags.contains(.instantRoundVideo) {
@ -107,7 +107,7 @@ final class InstantPageMediaPlaylistItem: SharedMediaPlaylistItem {
} }
} }
return SharedMediaPlaybackDisplayData.music(title: file.fileName ?? "", performer: "", albumArt: nil, long: false) return SharedMediaPlaybackDisplayData.music(title: file.fileName ?? "", performer: "", albumArt: nil, long: false, caption: nil)
} }
return nil return nil
} }

View File

@ -235,17 +235,7 @@
{ {
void(^block)(void) = ^ void(^block)(void) = ^
{ {
CGAffineTransform transform = CGAffineTransformMakeRotation(-1 * TGRotationForInterfaceOrientation(orientation)); [self updateWrapperTransform];
CGFloat scale = 1.0;
if (self.frame.size.width != 0.0) {
scale = self.frame.size.height / self.frame.size.width;
}
if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
transform = CGAffineTransformScale(transform, scale, scale);
} else if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
transform = CGAffineTransformScale(transform, scale, scale);
}
_wrapperView.transform = transform;
[self layoutSubviews]; [self layoutSubviews];
}; };
@ -257,6 +247,20 @@
block(); block();
} }
- (void)updateWrapperTransform {
CGAffineTransform transform = CGAffineTransformMakeRotation(-1 * TGRotationForInterfaceOrientation(_innerInterfaceOrientation));
CGFloat scale = 1.0;
if (self.frame.size.width != 0.0) {
scale = self.frame.size.height / self.frame.size.width;
}
if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
transform = CGAffineTransformScale(transform, scale, scale);
} else if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
transform = CGAffineTransformScale(transform, scale, scale);
}
_wrapperView.transform = transform;
}
- (void)layoutSubviews - (void)layoutSubviews
{ {
[super layoutSubviews]; [super layoutSubviews];
@ -264,6 +268,8 @@
_wrapperView.bounds = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); _wrapperView.bounds = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
_wrapperView.center = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0); _wrapperView.center = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0);
[self updateWrapperTransform];
TGCameraPreviewView *previewView = _previewView; TGCameraPreviewView *previewView = _previewView;
if (previewView.superview == _wrapperView) if (previewView.superview == _wrapperView)
previewView.frame = self.bounds; previewView.frame = self.bounds;

View File

@ -595,6 +595,10 @@
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON; hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
} }
} }
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && _intent == TGMediaAssetsControllerSendFileIntent) {
hasOnScreenNavigation = false;
}
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"

View File

@ -385,8 +385,8 @@
__weak TGMediaAvatarMenuMixin *weakSelf = self; __weak TGMediaAvatarMenuMixin *weakSelf = self;
UIViewController *(^presentBlock)(TGMediaAssetsController *) = nil; UIViewController *(^presentBlock)(TGMediaAssetsController *) = nil;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) // if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{ // {
presentBlock = ^UIViewController * (TGMediaAssetsController *controller) presentBlock = ^UIViewController * (TGMediaAssetsController *controller)
{ {
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
@ -413,48 +413,51 @@
return controller; return controller;
}; };
} // }
else // else
{ // {
presentBlock = ^UIViewController * (TGMediaAssetsController *controller) // presentBlock = ^UIViewController * (TGMediaAssetsController *controller)
{ // {
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; // __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
if (strongSelf == nil) // if (strongSelf == nil)
return nil; // return nil;
//
controller.presentationStyle = TGNavigationControllerPresentationStyleInFormSheet; // controller.presentationStyle = TGNavigationControllerPresentationStyleInFormSheet;
controller.modalPresentationStyle = UIModalPresentationFormSheet; // controller.modalPresentationStyle = UIModalPresentationFormSheet;
//
TGOverlayFormsheetWindow *formSheetWindow = [[TGOverlayFormsheetWindow alloc] initWithContext:strongSelf->_context parentController:strongSelf->_parentController contentController:controller]; // id<LegacyComponentsOverlayWindowManager> windowManager = nil;
[formSheetWindow showAnimated:true]; // windowManager = [strongSelf->_context makeOverlayWindowManager];
//
__weak TGNavigationController *weakNavController = controller; // TGOverlayFormsheetWindow *formSheetWindow = [[TGOverlayFormsheetWindow alloc] initWithManager:windowManager parentController:strongSelf->_parentController contentController:controller];
__weak TGOverlayFormsheetWindow *weakFormSheetWindow = formSheetWindow; // [formSheetWindow showAnimated:true];
controller.dismissalBlock = ^ //
{ // __weak TGNavigationController *weakNavController = controller;
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; // __weak TGOverlayFormsheetWindow *weakFormSheetWindow = formSheetWindow;
if (strongSelf == nil) // controller.dismissalBlock = ^
return; // {
// __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
__strong TGOverlayFormsheetWindow *strongFormSheetWindow = weakFormSheetWindow; // if (strongSelf == nil)
if (strongFormSheetWindow == nil) // return;
return; //
// __strong TGOverlayFormsheetWindow *strongFormSheetWindow = weakFormSheetWindow;
__strong TGNavigationController *strongNavController = weakNavController; // if (strongFormSheetWindow == nil)
if (strongNavController != nil) // return;
{ //
if (strongNavController.presentingViewController != nil) // __strong TGNavigationController *strongNavController = weakNavController;
[strongNavController.presentingViewController dismissViewControllerAnimated:true completion:nil]; // if (strongNavController != nil)
else // {
[strongFormSheetWindow dismissAnimated:true]; // if (strongNavController.presentingViewController != nil)
} // [strongNavController.presentingViewController dismissViewControllerAnimated:true completion:nil];
// else
if (strongSelf.didDismiss != nil) // [strongFormSheetWindow dismissAnimated:true];
strongSelf.didDismiss(); // }
}; //
return nil; // if (strongSelf.didDismiss != nil)
}; // strongSelf.didDismiss();
} // };
// return nil;
// };
// }
void (^showMediaPicker)(TGMediaAssetGroup *) = ^(TGMediaAssetGroup *group) void (^showMediaPicker)(TGMediaAssetGroup *) = ^(TGMediaAssetGroup *group)
{ {

View File

@ -6,7 +6,7 @@
@interface TGOverlayFormsheetWindow : UIWindow @interface TGOverlayFormsheetWindow : UIWindow
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController contentController:(UIViewController *)contentController; - (instancetype)initWithManager:(id<LegacyComponentsOverlayWindowManager>)manager parentController:(TGViewController *)parentController contentController:(UIViewController *)contentController;
- (void)showAnimated:(bool)animated; - (void)showAnimated:(bool)animated;
- (void)dismissAnimated:(bool)animated; - (void)dismissAnimated:(bool)animated;

View File

@ -14,18 +14,19 @@
SMetaDisposable *_sizeClassDisposable; SMetaDisposable *_sizeClassDisposable;
UIUserInterfaceSizeClass _sizeClass; UIUserInterfaceSizeClass _sizeClass;
id<LegacyComponentsContext> _context; id<LegacyComponentsOverlayWindowManager> _manager;
bool _managedIsHidden;
} }
@end @end
@implementation TGOverlayFormsheetWindow @implementation TGOverlayFormsheetWindow
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController contentController:(UIViewController *)contentController - (instancetype)initWithManager:(id<LegacyComponentsOverlayWindowManager>)manager parentController:(TGViewController *)parentController contentController:(UIViewController *)contentController
{ {
self = [super initWithFrame:[context fullscreenBounds]]; self = [super initWithFrame:[[manager context] fullscreenBounds]];
if (self != nil) if (self != nil)
{ {
_context = context; _manager = manager;
self.windowLevel = parentController.view.window.windowLevel + 0.0001f; self.windowLevel = parentController.view.window.windowLevel + 0.0001f;
self.backgroundColor = [UIColor clearColor]; self.backgroundColor = [UIColor clearColor];
@ -34,8 +35,7 @@
_contentController = contentController; _contentController = contentController;
if (iosMajorVersion() < 9) [_manager bindController:_contentController];
[self createControllerIfNeeded];
} }
return self; return self;
} }
@ -45,88 +45,38 @@
[_sizeClassDisposable dispose]; [_sizeClassDisposable dispose];
} }
- (void)createControllerIfNeeded - (BOOL)isHidden {
{ return _managedIsHidden;
if (self.rootViewController != nil)
return;
TGOverlayFormsheetController *controller = [[TGOverlayFormsheetController alloc] initWithContext:_context contentController:_contentController];
controller.formSheetWindow = self;
self.rootViewController = controller;
_contentController = nil;
} }
- (void)updateSizeClass:(UIUserInterfaceSizeClass)sizeClass animated:(bool)animated - (void)setHidden:(BOOL)hidden {
{ if ([_manager managesWindow]) {
if (_sizeClass == sizeClass) if (![super isHidden]) {
return; [super setHidden:true];
_sizeClass = sizeClass;
if (sizeClass == UIUserInterfaceSizeClassCompact)
{
if ([self contentController].parentViewController != _parentController)
{
[[self contentController] removeFromParentViewController];
[[self.contentController view] removeFromSuperview];
[_parentController presentViewController:[self contentController] animated:animated completion:nil];
self.hidden = true;
} }
}
else if (_managedIsHidden != hidden) {
{ _managedIsHidden = hidden;
if ([self controller] == nil || [self contentController].parentViewController != [self controller]) [_manager setHidden:hidden window:self];
{ }
[self createControllerIfNeeded]; } else {
[super setHidden:hidden];
[self.contentController.presentingViewController dismissViewControllerAnimated:false completion:^
{ if (!hidden) {
[[self controller] setContentController:[self contentController]]; [[[LegacyComponentsGlobals provider] applicationWindows].firstObject endEditing:true];
self.hidden = false;
}];
} }
} }
} }
- (void)showAnimated:(bool)animated - (void)showAnimated:(bool)animated
{ {
if (iosMajorVersion() >= 9) if ([self contentController].parentViewController != _parentController)
{ {
UIUserInterfaceSizeClass sizeClass = [_context currentHorizontalSizeClass]; [[self contentController] removeFromParentViewController];
[[self.contentController view] removeFromSuperview];
if (sizeClass == UIUserInterfaceSizeClassCompact)
{
[self updateSizeClass:sizeClass animated:true];
}
else
{
[self createControllerIfNeeded];
self.hidden = false;
if (animated)
[[self controller] animateInWithCompletion:nil];
}
__weak TGOverlayFormsheetWindow *weakSelf = self; [_parentController presentViewController:[self contentController] animated:animated completion:nil];
_sizeClassDisposable = [[SMetaDisposable alloc] init]; //self.hidden = true;
[_sizeClassDisposable setDisposable:[[_context sizeClassSignal] startWithNext:^(NSNumber *next)
{
__strong TGOverlayFormsheetWindow *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf updateSizeClass:next.integerValue animated:false];
}]];
}
else
{
self.hidden = false;
if (animated)
[[self controller] animateInWithCompletion:nil];
} }
} }
@ -134,7 +84,8 @@
{ {
TGViewController *parentController = _parentController; TGViewController *parentController = _parentController;
[parentController.associatedWindowStack removeObject:self]; [parentController.associatedWindowStack removeObject:self];
self.hidden = true; [_manager setHidden:true window:self];
//self.hidden = true;
} }
- (void)dismissAnimated:(bool)animated - (void)dismissAnimated:(bool)animated

View File

@ -190,7 +190,10 @@
controller.presentationStyle = TGNavigationControllerPresentationStyleInFormSheet; controller.presentationStyle = TGNavigationControllerPresentationStyleInFormSheet;
controller.modalPresentationStyle = UIModalPresentationFormSheet; controller.modalPresentationStyle = UIModalPresentationFormSheet;
TGOverlayFormsheetWindow *formSheetWindow = [[TGOverlayFormsheetWindow alloc] initWithContext:context parentController:strongParentController contentController:controller]; id<LegacyComponentsOverlayWindowManager> windowManager = nil;
windowManager = [context makeOverlayWindowManager];
TGOverlayFormsheetWindow *formSheetWindow = [[TGOverlayFormsheetWindow alloc] initWithManager:windowManager parentController:strongParentController contentController:controller];
[formSheetWindow showAnimated:true]; [formSheetWindow showAnimated:true];
__weak TGNavigationController *weakNavController = controller; __weak TGNavigationController *weakNavController = controller;

View File

@ -41,7 +41,7 @@ private class MediaHeaderItemNode: ASDisplayNode {
var subtitleString: NSAttributedString? var subtitleString: NSAttributedString?
if let playbackItem = playbackItem, let displayData = playbackItem.displayData { if let playbackItem = playbackItem, let displayData = playbackItem.displayData {
switch displayData { switch displayData {
case let .music(title, performer, _, long): case let .music(title, performer, _, long, _):
rateButtonHidden = !long rateButtonHidden = !long
let titleText: String = title ?? strings.MediaPlayer_UnknownTrack let titleText: String = title ?? strings.MediaPlayer_UnknownTrack
let subtitleText: String = performer ?? strings.MediaPlayer_UnknownArtist let subtitleText: String = performer ?? strings.MediaPlayer_UnknownArtist

View File

@ -6803,7 +6803,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(index.id) { if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(index.id) {
let highlightedState = ChatInterfaceHighlightedState(messageStableId: message.stableId) let highlightedState = ChatInterfaceHighlightedState(messageStableId: message.stableId)
controllerInteraction.highlightedState = highlightedState controllerInteraction.highlightedState = highlightedState
strongSelf.updateItemNodesHighlightedStates(animated: false) strongSelf.updateItemNodesHighlightedStates(animated: initial)
strongSelf.scrolledToMessageIdValue = ScrolledToMessageId(id: index.id, allowedReplacementDirection: []) strongSelf.scrolledToMessageIdValue = ScrolledToMessageId(id: index.id, allowedReplacementDirection: [])
strongSelf.messageContextDisposable.set((Signal<Void, NoError>.complete() |> delay(0.7, queue: Queue.mainQueue())).start(completed: { strongSelf.messageContextDisposable.set((Signal<Void, NoError>.complete() |> delay(0.7, queue: Queue.mainQueue())).start(completed: {

View File

@ -248,7 +248,7 @@ public final class MediaManagerImpl: NSObject, MediaManager {
var artwork: SharedMediaPlaybackAlbumArt? var artwork: SharedMediaPlaybackAlbumArt?
switch displayData { switch displayData {
case let .music(title, performer, artworkValue, _): case let .music(title, performer, artworkValue, _, _):
artwork = artworkValue artwork = artworkValue
let titleText: String = title ?? presentationData.strings.MediaPlayer_UnknownTrack let titleText: String = title ?? presentationData.strings.MediaPlayer_UnknownTrack

View File

@ -61,19 +61,21 @@ private func timestampLabelWidthForDuration(_ timestamp: Double) -> CGFloat {
private let titleFont = Font.semibold(18.0) private let titleFont = Font.semibold(18.0)
private let descriptionFont = Font.regular(18.0) private let descriptionFont = Font.regular(18.0)
private func stringsForDisplayData(_ data: SharedMediaPlaybackDisplayData?, presentationData: PresentationData) -> (NSAttributedString?, NSAttributedString?, Bool) { private func stringsForDisplayData(_ data: SharedMediaPlaybackDisplayData?, presentationData: PresentationData) -> (NSAttributedString?, NSAttributedString?, Bool, NSAttributedString?) {
var titleString: NSAttributedString? var titleString: NSAttributedString?
var descriptionString: NSAttributedString? var descriptionString: NSAttributedString?
var hasArtist = false var hasArtist = false
var captionString: NSAttributedString?
if let data = data { if let data = data {
let titleText: String let titleText: String
let subtitleText: String let subtitleText: String
switch data { switch data {
case let .music(title, performer, _, _): case let .music(title, performer, _, _, caption):
titleText = title ?? presentationData.strings.MediaPlayer_UnknownTrack titleText = title ?? presentationData.strings.MediaPlayer_UnknownTrack
subtitleText = performer ?? presentationData.strings.MediaPlayer_UnknownArtist subtitleText = performer ?? presentationData.strings.MediaPlayer_UnknownArtist
hasArtist = performer != nil hasArtist = performer != nil
captionString = caption
case .voice, .instantVideo: case .voice, .instantVideo:
titleText = "" titleText = ""
subtitleText = "" subtitleText = ""
@ -83,7 +85,7 @@ private func stringsForDisplayData(_ data: SharedMediaPlaybackDisplayData?, pres
descriptionString = NSAttributedString(string: subtitleText, font: descriptionFont, textColor: hasArtist ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor) descriptionString = NSAttributedString(string: subtitleText, font: descriptionFont, textColor: hasArtist ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor)
} }
return (titleString, descriptionString, hasArtist) return (titleString, descriptionString, hasArtist, captionString)
} }
final class OverlayPlayerControlsNode: ASDisplayNode { final class OverlayPlayerControlsNode: ASDisplayNode {
@ -146,6 +148,13 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
private var currentAlbumArt: SharedMediaPlaybackAlbumArt? private var currentAlbumArt: SharedMediaPlaybackAlbumArt?
private var currentFileReference: FileMediaReference? private var currentFileReference: FileMediaReference?
private var statusDisposable: Disposable? private var statusDisposable: Disposable?
private var chapterDisposable: Disposable?
private var previousCaption: NSAttributedString?
private var chaptersPromise = ValuePromise<[MediaPlayerScrubbingChapter]>([])
private var currentChapter: MediaPlayerScrubbingChapter?
private let hapticFeedback = HapticFeedback()
private var scrubbingDisposable: Disposable? private var scrubbingDisposable: Disposable?
private var leftDurationLabelPushed = false private var leftDurationLabelPushed = false
@ -376,7 +385,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
strongSelf.updateRateButton(baseRate) strongSelf.updateRateButton(baseRate)
} }
if let displayData = displayData, case let .music(_, _, _, long) = displayData, long { if let displayData = displayData, case let .music(_, _, _, long, _) = displayData, long {
strongSelf.scrubberNode.enableFineScrubbing = true strongSelf.scrubberNode.enableFineScrubbing = true
rateButtonIsHidden = false rateButtonIsHidden = false
} else { } else {
@ -430,6 +439,58 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
} }
}) })
self.chapterDisposable = combineLatest(queue: Queue.mainQueue(), mappedStatus, self.chaptersPromise.get())
.start(next: { [weak self] status, chapters in
if let strongSelf = self, status.duration > 1.0, chapters.count > 0 {
let previousChapter = strongSelf.currentChapter
var currentChapter: MediaPlayerScrubbingChapter?
for chapter in chapters {
if chapter.start > status.timestamp {
break
} else {
currentChapter = chapter
}
}
if let chapter = currentChapter, chapter != previousChapter {
strongSelf.currentChapter = chapter
if strongSelf.scrubberNode.isScrubbing {
strongSelf.hapticFeedback.impact(.light)
}
if let previousChapter = previousChapter, !strongSelf.infoNode.alpha.isZero {
if let snapshotView = strongSelf.infoNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = strongSelf.infoNode.frame
strongSelf.infoNode.view.superview?.addSubview(snapshotView)
let offset: CGFloat = 30.0
let snapshotTargetPosition: CGPoint
let nodeStartPosition: CGPoint
if previousChapter.start < chapter.start {
snapshotTargetPosition = CGPoint(x: -offset, y: 0.0)
nodeStartPosition = CGPoint(x: offset, y: 0.0)
} else {
snapshotTargetPosition = CGPoint(x: offset, y: 0.0)
nodeStartPosition = CGPoint(x: -offset, y: 0.0)
}
snapshotView.layer.animatePosition(from: CGPoint(), to: snapshotTargetPosition, duration: 0.2, removeOnCompletion: false, additive: true)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
strongSelf.infoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
strongSelf.infoNode.layer.animatePosition(from: nodeStartPosition, to: CGPoint(), duration: 0.2, additive: true)
}
}
strongSelf.infoNode.attributedText = NSAttributedString(string: chapter.title, font: Font.regular(13.0), textColor: strongSelf.presentationData.theme.list.itemSecondaryTextColor)
if let layout = strongSelf.validLayout {
let _ = strongSelf.updateLayout(width: layout.0, leftInset: layout.1, rightInset: layout.2, maxHeight: layout.3, transition: .immediate)
}
}
}
})
self.scrubberNode.seek = { [weak self] value in self.scrubberNode.seek = { [weak self] value in
self?.control?(.seek(value)) self?.control?(.seek(value))
} }
@ -463,6 +524,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
deinit { deinit {
self.statusDisposable?.dispose() self.statusDisposable?.dispose()
self.chapterDisposable?.dispose()
self.scrubbingDisposable?.dispose() self.scrubbingDisposable?.dispose()
} }
@ -600,7 +662,15 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
let infoVerticalOrigin: CGFloat = panelHeight - OverlayPlayerControlsNode.basePanelHeight + 36.0 let infoVerticalOrigin: CGFloat = panelHeight - OverlayPlayerControlsNode.basePanelHeight + 36.0
let (titleString, descriptionString, hasArtist) = stringsForDisplayData(self.displayData, presentationData: self.presentationData) let (titleString, descriptionString, hasArtist, caption) = stringsForDisplayData(self.displayData, presentationData: self.presentationData)
if self.previousCaption?.string != caption?.string {
self.previousCaption = caption
let chapters = caption.flatMap { parseMediaPlayerChapters($0) } ?? []
self.chaptersPromise.set(chapters)
self.scrubberNode.updateContent(.standard(lineHeight: 3.0, lineCap: .round, scrubberHandle: .circle, backgroundColor: self.presentationData.theme.list.controlSecondaryColor, foregroundColor: self.presentationData.theme.list.itemAccentColor, bufferingColor: self.presentationData.theme.list.itemAccentColor.withAlphaComponent(0.4), chapters: chapters))
}
self.artistButton.isUserInteractionEnabled = hasArtist self.artistButton.isUserInteractionEnabled = hasArtist
let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - sideInset * 2.0 - leftInset - rightInset - infoLabelsLeftInset - infoLabelsRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - sideInset * 2.0 - leftInset - rightInset - infoLabelsLeftInset - infoLabelsRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets()))
@ -619,7 +689,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
var albumArt: SharedMediaPlaybackAlbumArt? var albumArt: SharedMediaPlaybackAlbumArt?
if let displayData = self.displayData { if let displayData = self.displayData {
switch displayData { switch displayData {
case let .music(_, _, value, _): case let .music(_, _, value, _, _):
albumArt = value albumArt = value
default: default:
break break
@ -913,7 +983,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
} }
@objc func artistPressed() { @objc func artistPressed() {
let (_, descriptionString, _) = stringsForDisplayData(self.displayData, presentationData: self.presentationData) let (_, descriptionString, _, _) = stringsForDisplayData(self.displayData, presentationData: self.presentationData)
if let artist = descriptionString?.string { if let artist = descriptionString?.string {
self.requestSearchByArtist?(artist) self.requestSearchByArtist?(artist)
} }

View File

@ -402,7 +402,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
let entities = generateTextEntities(additionalText, enabledTypes: [.mention]) let entities = generateTextEntities(additionalText, enabledTypes: [.mention])
let attributedAdditionalText = stringWithAppliedEntities(additionalText, entities: entities, baseColor: presentationData.theme.list.itemPrimaryTextColor, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont, underlineLinks: false, message: nil) let attributedAdditionalText = stringWithAppliedEntities(additionalText, entities: entities, baseColor: presentationData.theme.list.itemPrimaryTextColor, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont, underlineLinks: false, message: nil)
self.additionalTextNode.maximumNumberOfLines = 3 self.additionalTextNode.maximumNumberOfLines = 10
self.additionalTextNode.attributedText = attributedAdditionalText self.additionalTextNode.attributedText = attributedAdditionalText
} else { } else {
self.additionalTextNode.attributedText = nil self.additionalTextNode.attributedText = nil

View File

@ -1,11 +1,13 @@
import Foundation import Foundation
import UIKit import UIKit
import Display
import SwiftSignalKit import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import TelegramUIPreferences import TelegramUIPreferences
import AccountContext import AccountContext
import MusicAlbumArtResources import MusicAlbumArtResources
import TextFormat
private enum PeerMessagesMediaPlaylistLoadAnchor { private enum PeerMessagesMediaPlaylistLoadAnchor {
case messageId(MessageId) case messageId(MessageId)
@ -95,6 +97,15 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem {
var displayData: SharedMediaPlaybackDisplayData? { var displayData: SharedMediaPlaybackDisplayData? {
if let file = extractFileMedia(self.message) { if let file = extractFileMedia(self.message) {
let text = self.message.text
var entities: [MessageTextEntity] = []
if let result = addLocallyGeneratedEntities(text, enabledTypes: [.timecode], entities: [], mediaDuration: file.duration.flatMap(Double.init)) {
entities = result
}
let textFont = Font.regular(14.0)
let caption = stringWithAppliedEntities(text, entities: entities, baseColor: .white, linkColor: .white, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: self.message)
for attribute in file.attributes { for attribute in file.attributes {
switch attribute { switch attribute {
case let .Audio(isVoice, duration, title, performer, _): case let .Audio(isVoice, duration, title, performer, _):
@ -114,7 +125,7 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem {
albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)) albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false))
} }
return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: CGFloat(duration) > 10.0 * 60.0) return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: CGFloat(duration) > 10.0 * 60.0, caption: caption)
} }
case let .Video(_, _, flags): case let .Video(_, _, flags):
if flags.contains(.instantRoundVideo) { if flags.contains(.instantRoundVideo) {
@ -127,7 +138,7 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem {
} }
} }
return SharedMediaPlaybackDisplayData.music(title: file.fileName ?? "", performer: self.message.effectiveAuthor?.debugDisplayTitle ?? "", albumArt: nil, long: false) return SharedMediaPlaybackDisplayData.music(title: file.fileName ?? "", performer: self.message.effectiveAuthor?.debugDisplayTitle ?? "", albumArt: nil, long: false, caption: caption)
} }
return nil return nil
} }