mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Various improvements
This commit is contained in:
@@ -61,19 +61,21 @@ private func timestampLabelWidthForDuration(_ timestamp: Double) -> CGFloat {
|
||||
private let titleFont = Font.semibold(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 descriptionString: NSAttributedString?
|
||||
var hasArtist = false
|
||||
var captionString: NSAttributedString?
|
||||
|
||||
if let data = data {
|
||||
let titleText: String
|
||||
let subtitleText: String
|
||||
switch data {
|
||||
case let .music(title, performer, _, _):
|
||||
case let .music(title, performer, _, _, caption):
|
||||
titleText = title ?? presentationData.strings.MediaPlayer_UnknownTrack
|
||||
subtitleText = performer ?? presentationData.strings.MediaPlayer_UnknownArtist
|
||||
hasArtist = performer != nil
|
||||
captionString = caption
|
||||
case .voice, .instantVideo:
|
||||
titleText = ""
|
||||
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)
|
||||
}
|
||||
|
||||
return (titleString, descriptionString, hasArtist)
|
||||
return (titleString, descriptionString, hasArtist, captionString)
|
||||
}
|
||||
|
||||
final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
@@ -146,6 +148,13 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
private var currentAlbumArt: SharedMediaPlaybackAlbumArt?
|
||||
private var currentFileReference: FileMediaReference?
|
||||
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 leftDurationLabelPushed = false
|
||||
@@ -376,7 +385,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
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
|
||||
rateButtonIsHidden = false
|
||||
} 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?.control?(.seek(value))
|
||||
}
|
||||
@@ -463,6 +524,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
|
||||
deinit {
|
||||
self.statusDisposable?.dispose()
|
||||
self.chapterDisposable?.dispose()
|
||||
self.scrubbingDisposable?.dispose()
|
||||
}
|
||||
|
||||
@@ -600,7 +662,15 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
|
||||
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
|
||||
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()))
|
||||
@@ -619,7 +689,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
var albumArt: SharedMediaPlaybackAlbumArt?
|
||||
if let displayData = self.displayData {
|
||||
switch displayData {
|
||||
case let .music(_, _, value, _):
|
||||
case let .music(_, _, value, _, _):
|
||||
albumArt = value
|
||||
default:
|
||||
break
|
||||
@@ -913,7 +983,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
@objc func artistPressed() {
|
||||
let (_, descriptionString, _) = stringsForDisplayData(self.displayData, presentationData: self.presentationData)
|
||||
let (_, descriptionString, _, _) = stringsForDisplayData(self.displayData, presentationData: self.presentationData)
|
||||
if let artist = descriptionString?.string {
|
||||
self.requestSearchByArtist?(artist)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user