Merge commit '354be3e42499a871ecd808c334a9370f6e1d4279'

This commit is contained in:
Peter 2019-10-04 14:03:14 +04:00
commit 5cd85de807
10 changed files with 316 additions and 134 deletions

View File

@ -597,7 +597,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
let scrubberFrame = CGRect(origin: CGPoint(x: leftInset, y: scrubberY), size: CGSize(width: width - leftInset - rightInset, height: 34.0))
scrubberView.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
scrubberView.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
transition.updateFrame(layer: scrubberView.layer, frame: scrubberFrame)
}
transition.updateAlpha(node: self.textNode, alpha: displayCaption ? 1.0 : 0.0)

View File

@ -21,6 +21,10 @@ final class ChatVideoGalleryItemScrubberView: UIView {
private var playbackStatus: MediaPlayerStatus?
private var fetchStatusDisposable = MetaDisposable()
private var scrubbingDisposable = MetaDisposable()
private var leftTimestampNodePushed = false
private var rightTimestampNodePushed = false
var hideWhenDurationIsUnknown = false {
didSet {
@ -103,11 +107,16 @@ final class ChatVideoGalleryItemScrubberView: UIView {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.scrubbingDisposable.dispose()
self.fetchStatusDisposable.dispose()
}
func setStatusSignal(_ status: Signal<MediaPlayerStatus, NoError>?) {
let mappedStatus: Signal<MediaPlayerStatus, NoError>?
if let status = status {
mappedStatus = combineLatest(status, self.scrubberNode.scrubbingTimestamp) |> map { status, scrubbingTimestamp -> MediaPlayerStatus in
return MediaPlayerStatus(generationTimestamp: status.generationTimestamp, duration: status.duration, dimensions: status.dimensions, timestamp: scrubbingTimestamp ?? status.timestamp, baseRate: status.baseRate, seekId: status.seekId, status: status.status, soundEnabled: status.soundEnabled)
return MediaPlayerStatus(generationTimestamp: scrubbingTimestamp != nil ? 0 : status.generationTimestamp, duration: status.duration, dimensions: status.dimensions, timestamp: scrubbingTimestamp ?? status.timestamp, baseRate: status.baseRate, seekId: status.seekId, status: status.status, soundEnabled: status.soundEnabled)
}
} else {
mappedStatus = nil
@ -115,6 +124,30 @@ final class ChatVideoGalleryItemScrubberView: UIView {
self.scrubberNode.status = mappedStatus
self.leftTimestampNode.status = mappedStatus
self.rightTimestampNode.status = mappedStatus
self.scrubbingDisposable.set((self.scrubberNode.scrubbingPosition
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
}
let leftTimestampNodePushed: Bool
let rightTimestampNodePushed: Bool
if let value = value {
leftTimestampNodePushed = value < 0.16
rightTimestampNodePushed = value > 0.84
} else {
leftTimestampNodePushed = false
rightTimestampNodePushed = false
}
if leftTimestampNodePushed != strongSelf.leftTimestampNodePushed || rightTimestampNodePushed != strongSelf.rightTimestampNodePushed {
strongSelf.leftTimestampNodePushed = leftTimestampNodePushed
strongSelf.rightTimestampNodePushed = rightTimestampNodePushed
if let layout = strongSelf.containerLayout {
strongSelf.updateLayout(size: layout.0, leftInset: layout.1, rightInset: layout.2, transition: .animated(duration: 0.35, curve: .spring))
}
}
}))
}
func setBufferingStatusSignal(_ status: Signal<(IndexSet, Int)?, NoError>?) {
@ -139,7 +172,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
strongSelf.fileSizeNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: .white)
if let (size, leftInset, rightInset) = strongSelf.containerLayout {
strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
}
}
}))
@ -151,22 +184,25 @@ final class ChatVideoGalleryItemScrubberView: UIView {
}
}
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
self.containerLayout = (size, leftInset, rightInset)
let scrubberHeight: CGFloat = 14.0
let scrubberInset: CGFloat
let timestampOffset: CGFloat
let leftTimestampOffset: CGFloat
let rightTimestampOffset: CGFloat
if size.width > size.height {
scrubberInset = 58.0
timestampOffset = 4.0
leftTimestampOffset = 4.0
rightTimestampOffset = 4.0
} else {
scrubberInset = 13.0
timestampOffset = 22.0
leftTimestampOffset = 22.0 + (self.leftTimestampNodePushed ? 8.0 : 0.0)
rightTimestampOffset = 22.0 + (self.rightTimestampNodePushed ? 8.0 : 0.0)
}
self.leftTimestampNode.frame = CGRect(origin: CGPoint(x: 12.0, y: timestampOffset), size: CGSize(width: 60.0, height: 20.0))
self.rightTimestampNode.frame = CGRect(origin: CGPoint(x: size.width - leftInset - rightInset - 60.0 - 12.0, y: timestampOffset), size: CGSize(width: 60.0, height: 20.0))
transition.updateFrame(node: self.leftTimestampNode, frame: CGRect(origin: CGPoint(x: 12.0, y: leftTimestampOffset), size: CGSize(width: 60.0, height: 20.0)))
transition.updateFrame(node: self.rightTimestampNode, frame: CGRect(origin: CGPoint(x: size.width - leftInset - rightInset - 60.0 - 12.0, y: rightTimestampOffset), size: CGSize(width: 60.0, height: 20.0)))
let fileSize = self.fileSizeNode.measure(size)
self.fileSizeNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - fileSize.width) / 2.0), y: 22.0), size: fileSize)

View File

@ -23,6 +23,8 @@ private final class MediaPlayerScrubbingNodeButton: ASDisplayNode {
var endScrubbing: ((Bool) -> Void)?
var updateScrubbing: ((CGFloat) -> Void)?
var highlighted: ((Bool) -> Void)?
private var scrubbingStartLocation: CGPoint?
override func didLoad() {
@ -32,6 +34,28 @@ private final class MediaPlayerScrubbingNodeButton: ASDisplayNode {
self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
self.highlighted?(true)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
if self.scrubbingStartLocation == nil {
self.highlighted?(false)
}
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
if self.scrubbingStartLocation == nil {
self.highlighted?(false)
}
}
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
var location = recognizer.location(in: self.view)
location.x -= self.bounds.minX
@ -50,6 +74,7 @@ private final class MediaPlayerScrubbingNodeButton: ASDisplayNode {
let delta = location.x - scrubbingStartLocation.x
self.updateScrubbing?(delta / self.bounds.size.width)
self.endScrubbing?(recognizer.state == .ended)
self.highlighted?(false)
}
default:
break
@ -94,9 +119,10 @@ private final class StandardMediaPlayerScrubbingNodeContentNode {
let foregroundNode: MediaPlayerScrubbingForegroundNode
let handle: MediaPlayerScrubbingNodeHandle
let handleNode: ASDisplayNode?
let highlightedHandleNode: ASDisplayNode?
let handleNodeContainer: MediaPlayerScrubbingNodeButton?
init(lineHeight: CGFloat, lineCap: MediaPlayerScrubbingNodeCap, backgroundNode: ASImageNode, bufferingNode: MediaPlayerScrubbingBufferingNode, foregroundContentNode: ASImageNode, foregroundNode: MediaPlayerScrubbingForegroundNode, handle: MediaPlayerScrubbingNodeHandle, handleNode: ASDisplayNode?, handleNodeContainer: MediaPlayerScrubbingNodeButton?) {
init(lineHeight: CGFloat, lineCap: MediaPlayerScrubbingNodeCap, backgroundNode: ASImageNode, bufferingNode: MediaPlayerScrubbingBufferingNode, foregroundContentNode: ASImageNode, foregroundNode: MediaPlayerScrubbingForegroundNode, handle: MediaPlayerScrubbingNodeHandle, handleNode: ASDisplayNode?, highlightedHandleNode: ASDisplayNode?, handleNodeContainer: MediaPlayerScrubbingNodeButton?) {
self.lineHeight = lineHeight
self.lineCap = lineCap
self.backgroundNode = backgroundNode
@ -105,6 +131,7 @@ private final class StandardMediaPlayerScrubbingNodeContentNode {
self.foregroundNode = foregroundNode
self.handle = handle
self.handleNode = handleNode
self.highlightedHandleNode = highlightedHandleNode
self.handleNodeContainer = handleNodeContainer
}
}
@ -195,6 +222,11 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
return self._scrubbingTimestamp.get()
}
private let _scrubbingPosition = Promise<Double?>(nil)
public var scrubbingPosition: Signal<Double?, NoError> {
return self._scrubbingPosition.get()
}
public var ignoreSeekId: Int?
public var enableScrubbing: Bool = true {
@ -288,6 +320,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
foregroundNode.clipsToBounds = true
var handleNodeImpl: ASImageNode?
var highlightedHandleNodeImpl: ASImageNode?
var handleNodeContainerImpl: MediaPlayerScrubbingNodeButton?
switch scrubberHandle {
@ -304,18 +337,27 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
handleNodeContainerImpl = handleNodeContainer
case .circle:
let handleNode = ASImageNode()
handleNode.image = generateFilledCircleImage(diameter: lineHeight + 4.0, color: foregroundColor)
handleNode.image = generateFilledCircleImage(diameter: lineHeight + 3.0, color: foregroundColor)
handleNode.isLayerBacked = true
handleNodeImpl = handleNode
let highlightedHandleNode = ASImageNode()
let highlightedHandleImage = generateFilledCircleImage(diameter: lineHeight + 3.0 + 20.0, color: foregroundColor)!
highlightedHandleNode.image = highlightedHandleImage
highlightedHandleNode.bounds = CGRect(origin: CGPoint(), size: highlightedHandleImage.size)
highlightedHandleNode.isLayerBacked = true
highlightedHandleNode.transform = CATransform3DMakeScale(0.1875, 0.1875, 1.0)
highlightedHandleNodeImpl = highlightedHandleNode
let handleNodeContainer = MediaPlayerScrubbingNodeButton()
handleNodeContainer.addSubnode(handleNode)
handleNodeContainer.addSubnode(highlightedHandleNode)
handleNodeContainerImpl = handleNodeContainer
}
handleNodeContainerImpl?.isUserInteractionEnabled = enableScrubbing
return .standard(StandardMediaPlayerScrubbingNodeContentNode(lineHeight: lineHeight, lineCap: lineCap, backgroundNode: backgroundNode, bufferingNode: bufferingNode, foregroundContentNode: foregroundContentNode, foregroundNode: foregroundNode, handle: scrubberHandle, handleNode: handleNodeImpl, handleNodeContainer: handleNodeContainerImpl))
return .standard(StandardMediaPlayerScrubbingNodeContentNode(lineHeight: lineHeight, lineCap: lineCap, backgroundNode: backgroundNode, bufferingNode: bufferingNode, foregroundContentNode: foregroundContentNode, foregroundNode: foregroundNode, handle: scrubberHandle, handleNode: handleNodeImpl, highlightedHandleNode: highlightedHandleNodeImpl, handleNodeContainer: handleNodeContainerImpl))
case let .custom(backgroundNode, foregroundContentNode):
let foregroundNode = MediaPlayerScrubbingForegroundNode()
foregroundNode.isLayerBacked = true
@ -373,12 +415,39 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
if let handleNodeContainer = node.handleNodeContainer {
self.addSubnode(handleNodeContainer)
handleNodeContainer.highlighted = { [weak self] highlighted in
if let strongSelf = self, let highlightedHandleNode = node.highlightedHandleNode, let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
if highlighted {
strongSelf.displayLink?.isPaused = true
var timestamp = statusValue.timestamp
if statusValue.generationTimestamp > 0 {
let currentTimestamp = CACurrentMediaTime()
timestamp = timestamp + (currentTimestamp - statusValue.generationTimestamp) * statusValue.baseRate
}
strongSelf.scrubbingTimestampValue = timestamp
strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue))
strongSelf._scrubbingPosition.set(.single(strongSelf.scrubbingTimestampValue.flatMap { $0 / statusValue.duration }))
highlightedHandleNode.layer.animateSpring(from: 0.1875 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.65, initialVelocity: 0.0, damping: 80.0, removeOnCompletion: false)
} else {
strongSelf.scrubbingTimestampValue = nil
strongSelf._scrubbingTimestamp.set(.single(nil))
strongSelf._scrubbingPosition.set(.single(nil))
strongSelf.updateProgressAnimations()
highlightedHandleNode.layer.animateSpring(from: 1.0 as NSNumber, to: 0.1875 as NSNumber, keyPath: "transform.scale", duration: 0.65, initialVelocity: 0.0, damping: 120.0, removeOnCompletion: false)
}
}
}
handleNodeContainer.beginScrubbing = { [weak self] in
if let strongSelf = self {
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
strongSelf.scrubbingTimestampValue = statusValue.timestamp
strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue))
strongSelf._scrubbingPosition.set(.single(strongSelf.scrubbingTimestampValue.flatMap { $0 / statusValue.duration }))
strongSelf.update?(strongSelf.scrubbingTimestampValue, CGFloat(statusValue.timestamp / statusValue.duration))
strongSelf.updateProgressAnimations()
}
@ -390,6 +459,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
let timestampValue = max(0.0, min(statusValue.duration, scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction)))
strongSelf.scrubbingTimestampValue = timestampValue
strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue))
strongSelf._scrubbingPosition.set(.single(strongSelf.scrubbingTimestampValue.flatMap { $0 / statusValue.duration }))
strongSelf.update?(timestampValue, CGFloat(timestampValue / statusValue.duration))
strongSelf.updateProgressAnimations()
}
@ -401,6 +471,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
let scrubbingTimestampValue = strongSelf.scrubbingTimestampValue
strongSelf.scrubbingTimestampValue = nil
strongSelf._scrubbingTimestamp.set(.single(nil))
strongSelf._scrubbingPosition.set(.single(nil))
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
if let statusValue = strongSelf.statusValue {
switch statusValue.status {
@ -508,7 +579,14 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
node.foregroundContentNode.backgroundColor = foregroundColor
}
if let handleNode = node.handleNode as? ASImageNode {
handleNode.image = generateHandleBackground(color: foregroundColor)
switch node.handle {
case .line:
handleNode.image = generateHandleBackground(color: foregroundColor)
case .circle:
handleNode.image = generateFilledCircleImage(diameter: node.lineHeight + 3.0, color: foregroundColor)
case .none:
break
}
}
case .custom:
break
@ -522,7 +600,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
if !self.isInHierarchyValue {
needsAnimation = false
} else if let _ = scrubbingTimestampValue {
} else if let _ = self.scrubbingTimestampValue {
needsAnimation = false
} else if let statusValue = self.statusValue {
if case .buffering(true, _) = statusValue.status {
@ -594,10 +672,16 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
if let handleNode = node.handleNode {
var handleSize: CGSize = CGSize(width: 2.0, height: bounds.size.height)
var handleOffset: CGFloat = 0.0
if case .circle = node.handle, let handleNode = handleNode as? ASImageNode, let image = handleNode.image {
handleSize = image.size
handleOffset = -1.0 + UIScreenPixel
}
handleNode.frame = CGRect(origin: CGPoint(x: -handleSize.width / 2.0, y: floor((bounds.size.height - handleSize.height) / 2.0) + handleOffset), size: handleSize)
if let highlightedHandleNode = node.highlightedHandleNode {
highlightedHandleNode.position = handleNode.position
}
handleNode.frame = CGRect(origin: CGPoint(x: -handleSize.width / 2.0, y: floor((bounds.size.height - handleSize.height) / 2.0)), size: handleSize)
}
if let handleNodeContainer = node.handleNodeContainer {
@ -605,7 +689,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
}
if let (timestamp, duration) = timestampAndDuration {
if let scrubbingTimestampValue = scrubbingTimestampValue {
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
var progress = CGFloat(scrubbingTimestampValue / duration)
if progress.isNaN || !progress.isFinite {
progress = 0.0

View File

@ -586,13 +586,13 @@ public final class ShareController: ViewController {
url = "https://t.me/\(addressName)/\(message.id.id)"
}
}
var peer: Peer?
var peerId: PeerId?
if let authorPeerId = message.author?.id {
peer = message.peers[authorPeerId]
peerId = authorPeerId
} else if let mainPeer = messageMainPeer(message) {
peer = mainPeer
peerId = mainPeer.id
}
collectableItems.append(CollectableExternalShareItem(url: url, text: message.text, author: peer?.displayTitle, timestamp: message.timestamp, mediaReference: selectedMedia.flatMap({ AnyMediaReference.message(message: MessageReference(message), media: $0) })))
collectableItems.append(CollectableExternalShareItem(url: url, text: message.text, author: nil, timestamp: message.timestamp, mediaReference: selectedMedia.flatMap({ AnyMediaReference.message(message: MessageReference(message), media: $0) })))
}
case .fromExternal:
break

View File

@ -145,13 +145,21 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
}
if forwardInfo == nil {
for media in media {
inner: for media in message.media {
if let file = media as? TelegramMediaFile {
if file.isSticker {
sentStickers.append(file)
} else if file.isVideo && file.isAnimated {
sentGifs.append(file)
for attribute in file.attributes {
switch attribute {
case let .Sticker(_, packReference, _):
if packReference != nil {
sentStickers.append(file)
}
case .Animated:
sentGifs.append(file)
default:
break
}
}
break inner
}
}
}
@ -296,13 +304,21 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage
}
if storeForwardInfo == nil {
for media in media {
inner: for media in message.media {
if let file = media as? TelegramMediaFile {
if file.isSticker {
sentStickers.append(file)
} else if file.isVideo && file.isAnimated {
sentGifs.append(file)
for attribute in file.attributes {
switch attribute {
case let .Sticker(_, packReference, _):
if packReference != nil {
sentStickers.append(file)
}
case .Animated:
sentGifs.append(file)
default:
break
}
}
break inner
}
}
}

View File

@ -5326,7 +5326,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
legacyController.bind(controller: controller)
legacyController.deferScreenEdgeGestures = [.top]
configureLegacyAssetPicker(controller, context: strongSelf.context, peer: peer, initialCaption: inputText.string, hasSchedule: !strongSelf.presentationInterfaceState.isScheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, presentWebSearch: { [weak self, weak legacyController] in
configureLegacyAssetPicker(controller, context: strongSelf.context, peer: peer, initialCaption: inputText.string, hasSchedule: !strongSelf.presentationInterfaceState.isScheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, presentWebSearch: editingMedia ? nil : { [weak self, weak legacyController] in
if let strongSelf = self {
let controller = WebSearchController(context: strongSelf.context, peer: peer, configuration: searchBotsConfiguration, mode: .media(completion: { results, selectionState, editingState, silentPosting in
if let legacyController = legacyController {

View File

@ -1616,7 +1616,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let aspectRatio = min(image.size.width, image.size.height) / maxSide
if isMemoji || (imageHasTransparency(cgImage) && aspectRatio > 0.85) {
self.paste(.sticker(image, isMemoji))
return false
return true
}
}

View File

@ -31,8 +31,8 @@ private func generateShareIcon(theme: PresentationTheme) -> UIImage? {
})
}
private let titleFont = Font.medium(16.0)
private let descriptionFont = Font.regular(12.0)
private let titleFont = Font.semibold(17.0)
private let descriptionFont = Font.regular(17.0)
private func stringsForDisplayData(_ data: SharedMediaPlaybackDisplayData?, theme: PresentationTheme) -> (NSAttributedString?, NSAttributedString?) {
var titleString: NSAttributedString?
@ -109,6 +109,10 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
private var currentFileReference: FileMediaReference?
private var statusDisposable: Disposable?
private var scrubbingDisposable: Disposable?
private var leftDurationLabelPushed = false
private var rightDurationLabelPushed = false
private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, maxHeight: CGFloat)?
init(account: Account, accountManager: AccountManager, theme: PresentationTheme, status: Signal<(Account, SharedMediaPlayerItemPlaybackStateOrLoading)?, NoError>) {
@ -223,96 +227,121 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
self.leftDurationLabel.status = mappedStatus
self.rightDurationLabel.status = mappedStatus
self.scrubbingDisposable = (self.scrubberNode.scrubbingPosition
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
}
let leftDurationLabelPushed: Bool
let rightDurationLabelPushed: Bool
if let value = value {
leftDurationLabelPushed = value < 0.16
rightDurationLabelPushed = value > (strongSelf.rateButton.isHidden ? 0.84 : 0.74)
} else {
leftDurationLabelPushed = false
rightDurationLabelPushed = false
}
if leftDurationLabelPushed != strongSelf.leftDurationLabelPushed || rightDurationLabelPushed != strongSelf.rightDurationLabelPushed {
strongSelf.leftDurationLabelPushed = leftDurationLabelPushed
strongSelf.rightDurationLabelPushed = rightDurationLabelPushed
if let layout = strongSelf.validLayout {
strongSelf.updateLayout(width: layout.0, leftInset: layout.1, rightInset: layout.2, maxHeight: layout.3, transition: .animated(duration: 0.35, curve: .spring))
}
}
})
self.statusDisposable = (delayedStatus
|> deliverOnMainQueue).start(next: { [weak self] value in
if let strongSelf = self {
var valueItemId: SharedMediaPlaylistItemId?
if let (_, value) = value, case let .state(state) = value {
valueItemId = state.item.id
guard let strongSelf = self else {
return
}
var valueItemId: SharedMediaPlaylistItemId?
if let (_, value) = value, case let .state(state) = value {
valueItemId = state.item.id
}
if !areSharedMediaPlaylistItemIdsEqual(valueItemId, strongSelf.currentItemId) {
strongSelf.currentItemId = valueItemId
strongSelf.scrubberNode.ignoreSeekId = nil
}
strongSelf.shareNode.isHidden = false
var displayData: SharedMediaPlaybackDisplayData?
if let (_, valueOrLoading) = value, case let .state(value) = valueOrLoading {
let isPaused: Bool
switch value.status.status {
case .playing:
isPaused = false
case .paused:
isPaused = true
case let .buffering(_, whilePlaying):
isPaused = !whilePlaying
}
if !areSharedMediaPlaylistItemIdsEqual(valueItemId, strongSelf.currentItemId) {
strongSelf.currentItemId = valueItemId
strongSelf.scrubberNode.ignoreSeekId = nil
}
strongSelf.shareNode.isHidden = false
var displayData: SharedMediaPlaybackDisplayData?
if let (_, valueOrLoading) = value, case let .state(value) = valueOrLoading {
let isPaused: Bool
switch value.status.status {
case .playing:
isPaused = false
case .paused:
isPaused = true
case let .buffering(_, whilePlaying):
isPaused = !whilePlaying
}
if strongSelf.currentIsPaused != isPaused {
strongSelf.currentIsPaused = isPaused
strongSelf.updatePlayPauseButton(paused: isPaused)
}
if strongSelf.currentIsPaused != isPaused {
strongSelf.currentIsPaused = isPaused
strongSelf.playPauseButton.isEnabled = true
strongSelf.backwardButton.isEnabled = true
strongSelf.forwardButton.isEnabled = true
displayData = value.item.displayData
if value.order != strongSelf.currentOrder {
strongSelf.updateOrder?(value.order)
strongSelf.currentOrder = value.order
strongSelf.updateOrderButton(value.order)
}
if value.looping != strongSelf.currentLooping {
strongSelf.currentLooping = value.looping
strongSelf.updateLoopButton(value.looping)
}
let baseRate: AudioPlaybackRate
if !value.status.baseRate.isEqual(to: 1.0) {
baseRate = .x2
} else {
baseRate = .x1
}
if baseRate != strongSelf.currentRate {
strongSelf.currentRate = baseRate
strongSelf.updateRateButton(baseRate)
}
if let displayData = displayData, case let .music(_, _, _, long) = displayData, long {
strongSelf.rateButton.isHidden = false
} else {
strongSelf.rateButton.isHidden = true
}
} else {
strongSelf.playPauseButton.isEnabled = false
strongSelf.backwardButton.isEnabled = false
strongSelf.forwardButton.isEnabled = false
strongSelf.rateButton.isHidden = true
displayData = nil
strongSelf.updatePlayPauseButton(paused: isPaused)
}
if strongSelf.displayData != displayData {
strongSelf.displayData = displayData
if let (_, valueOrLoading) = value, case let .state(value) = valueOrLoading, let source = value.item.playbackData?.source {
switch source {
case let .telegramFile(fileReference):
strongSelf.currentFileReference = fileReference
if let size = fileReference.media.size {
strongSelf.scrubberNode.bufferingStatus = strongSelf.postbox.mediaBox.resourceRangesStatus(fileReference.media.resource)
|> map { ranges -> (IndexSet, Int) in
return (ranges, size)
}
} else {
strongSelf.scrubberNode.bufferingStatus = nil
}
}
} else {
strongSelf.scrubberNode.bufferingStatus = nil
}
strongSelf.updateLabels(transition: .immediate)
strongSelf.playPauseButton.isEnabled = true
strongSelf.backwardButton.isEnabled = true
strongSelf.forwardButton.isEnabled = true
displayData = value.item.displayData
if value.order != strongSelf.currentOrder {
strongSelf.updateOrder?(value.order)
strongSelf.currentOrder = value.order
strongSelf.updateOrderButton(value.order)
}
if value.looping != strongSelf.currentLooping {
strongSelf.currentLooping = value.looping
strongSelf.updateLoopButton(value.looping)
}
let baseRate: AudioPlaybackRate
if !value.status.baseRate.isEqual(to: 1.0) {
baseRate = .x2
} else {
baseRate = .x1
}
if baseRate != strongSelf.currentRate {
strongSelf.currentRate = baseRate
strongSelf.updateRateButton(baseRate)
}
if let displayData = displayData, case let .music(_, _, _, long) = displayData, long {
strongSelf.rateButton.isHidden = false
} else {
strongSelf.rateButton.isHidden = true
}
} else {
strongSelf.playPauseButton.isEnabled = false
strongSelf.backwardButton.isEnabled = false
strongSelf.forwardButton.isEnabled = false
strongSelf.rateButton.isHidden = true
displayData = nil
}
if strongSelf.displayData != displayData {
strongSelf.displayData = displayData
if let (_, valueOrLoading) = value, case let .state(value) = valueOrLoading, let source = value.item.playbackData?.source {
switch source {
case let .telegramFile(fileReference):
strongSelf.currentFileReference = fileReference
if let size = fileReference.media.size {
strongSelf.scrubberNode.bufferingStatus = strongSelf.postbox.mediaBox.resourceRangesStatus(fileReference.media.resource)
|> map { ranges -> (IndexSet, Int) in
return (ranges, size)
}
} else {
strongSelf.scrubberNode.bufferingStatus = nil
}
}
} else {
strongSelf.scrubberNode.bufferingStatus = nil
}
strongSelf.updateLabels(transition: .immediate)
}
})
@ -332,6 +361,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
deinit {
self.statusDisposable?.dispose()
self.scrubbingDisposable?.dispose()
}
override func didLoad() {
@ -378,7 +408,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
let sideInset: CGFloat = 20.0
let infoLabelsLeftInset: CGFloat = 64.0
let infoLabelsLeftInset: CGFloat = 60.0
let infoLabelsRightInset: CGFloat = 32.0
let infoVerticalOrigin: CGFloat = panelHeight - OverlayPlayerControlsNode.basePanelHeight + 36.0
@ -392,7 +422,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: self.isExpanded ? floor((width - titleLayout.size.width) / 2.0) : (leftInset + sideInset + infoLabelsLeftInset), y: infoVerticalOrigin + 1.0), size: titleLayout.size))
let _ = titleApply()
transition.updateFrame(node: self.descriptionNode, frame: CGRect(origin: CGPoint(x: self.isExpanded ? floor((width - descriptionLayout.size.width) / 2.0) : (leftInset + sideInset + infoLabelsLeftInset), y: infoVerticalOrigin + 27.0), size: descriptionLayout.size))
transition.updateFrame(node: self.descriptionNode, frame: CGRect(origin: CGPoint(x: self.isExpanded ? floor((width - descriptionLayout.size.width) / 2.0) : (leftInset + sideInset + infoLabelsLeftInset), y: infoVerticalOrigin + 26.0), size: descriptionLayout.size))
let _ = descriptionApply()
var albumArt: SharedMediaPlaybackAlbumArt?
@ -469,7 +499,6 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, maxHeight: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
self.validLayout = (width, leftInset, rightInset, maxHeight)
let panelHeight = OverlayPlayerControlsNode.heightForLayout(width: width, leftInset: leftInset, rightInset: rightInset, maxHeight: maxHeight, isExpanded: self.isExpanded)
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight), size: CGSize(width: width, height: UIScreenPixel)))
@ -562,10 +591,14 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
let scrubberVerticalOrigin: CGFloat = infoVerticalOrigin + 64.0
transition.updateFrame(node: self.scrubberNode, frame: CGRect(origin: CGPoint(x: leftInset + sideInset, y: scrubberVerticalOrigin - 8.0), size: CGSize(width: width - sideInset * 2.0 - leftInset - rightInset, height: 10.0 + 8.0 * 2.0)))
transition.updateFrame(node: self.leftDurationLabel, frame: CGRect(origin: CGPoint(x: leftInset + sideInset, y: scrubberVerticalOrigin + 14.0), size: CGSize(width: 100.0, height: 20.0)))
transition.updateFrame(node: self.rightDurationLabel, frame: CGRect(origin: CGPoint(x: width - sideInset - rightInset - 100.0, y: scrubberVerticalOrigin + 14.0), size: CGSize(width: 100.0, height: 20.0)))
transition.updateFrame(node: self.rateButton, frame: CGRect(origin: CGPoint(x: width - sideInset - rightInset - 100.0 + 24.0, y: scrubberVerticalOrigin + 10.0), size: CGSize(width: 24.0, height: 24.0)))
var leftLabelVerticalOffset: CGFloat = self.leftDurationLabelPushed ? 6.0 : 0.0
transition.updateFrame(node: self.leftDurationLabel, frame: CGRect(origin: CGPoint(x: leftInset + sideInset, y: scrubberVerticalOrigin + 14.0 + leftLabelVerticalOffset), size: CGSize(width: 100.0, height: 20.0)))
var rightLabelVerticalOffset: CGFloat = self.rightDurationLabelPushed ? 6.0 : 0.0
transition.updateFrame(node: self.rightDurationLabel, frame: CGRect(origin: CGPoint(x: width - sideInset - rightInset - 100.0, y: scrubberVerticalOrigin + 14.0 + rightLabelVerticalOffset), size: CGSize(width: 100.0, height: 20.0)))
transition.updateFrame(node: self.rateButton, frame: CGRect(origin: CGPoint(x: width - sideInset - rightInset - 100.0 + 24.0, y: scrubberVerticalOrigin + 10.0 + rightLabelVerticalOffset), size: CGSize(width: 24.0, height: 24.0)))
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -8.0), size: CGSize(width: width, height: panelHeight + 8.0)))

View File

@ -293,9 +293,21 @@ private final class WalletQrScanScreenNode: ViewControllerTracingNode, UIScrollV
let sideInset: CGFloat = 66.0
let titleSpacing: CGFloat = 48.0
let bounds = CGRect(origin: CGPoint(), size: layout.size)
if case .tablet = layout.deviceMetrics.type {
if case .landscape = layout.orientation {
let rotation: CGFloat
if UIDevice.current.orientation == .landscapeLeft {
rotation = CGFloat.pi / 2.0
} else {
rotation = -CGFloat.pi / 2.0
}
self.previewNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
} else {
self.previewNode.transform = CATransform3DIdentity
}
}
transition.updateFrame(node: self.previewNode, frame: bounds)
transition.updateFrame(node: self.fadeNode, frame: bounds)
@ -307,27 +319,26 @@ private final class WalletQrScanScreenNode: ViewControllerTracingNode, UIScrollV
let dimRect: CGRect
let controlsAlpha: CGFloat
if let focusedRect = self.focusedRect {
dimAlpha = 1.0
controlsAlpha = 0.0
dimAlpha = 1.0
let side = max(bounds.width * focusedRect.width, bounds.height * focusedRect.height) * 0.6
let center = CGPoint(x: (1.0 - focusedRect.center.y) * bounds.width, y: focusedRect.center.x * bounds.height)
dimRect = CGRect(x: center.x - side / 2.0, y: center.y - side / 2.0, width: side, height: side)
} else {
dimAlpha = 0.625
controlsAlpha = 1.0
dimAlpha = 0.625
dimRect = CGRect(x: dimInset, y: dimHeight, width: layout.size.width - dimInset * 2.0, height: layout.size.height - dimHeight * 2.0)
}
transition.updateFrame(node: self.topDimNode, frame: CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: dimRect.minY))
transition.updateFrame(node: self.bottomDimNode, frame: CGRect(x: 0.0, y: dimRect.maxY, width: layout.size.width, height: max(0.0, layout.size.height - dimRect.maxY)))
transition.updateFrame(node: self.leftDimNode, frame: CGRect(x: 0.0, y: dimRect.minY, width: max(0.0, dimRect.minX), height: dimRect.height))
transition.updateFrame(node: self.rightDimNode, frame: CGRect(x: dimRect.maxX, y: dimRect.minY, width: max(0.0, layout.size.width - dimRect.maxX), height: dimRect.height))
transition.updateAlpha(node: self.topDimNode, alpha: dimAlpha)
transition.updateAlpha(node: self.bottomDimNode, alpha: dimAlpha)
transition.updateAlpha(node: self.leftDimNode, alpha: dimAlpha)
transition.updateAlpha(node: self.rightDimNode, alpha: dimAlpha)
transition.updateFrame(node: self.topDimNode, frame: CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: dimRect.minY))
transition.updateFrame(node: self.bottomDimNode, frame: CGRect(x: 0.0, y: dimRect.maxY, width: layout.size.width, height: max(0.0, layout.size.height - dimRect.maxY)))
transition.updateFrame(node: self.leftDimNode, frame: CGRect(x: 0.0, y: dimRect.minY, width: max(0.0, dimRect.minX), height: dimRect.height))
transition.updateFrame(node: self.rightDimNode, frame: CGRect(x: dimRect.maxX, y: dimRect.minY, width: max(0.0, layout.size.width - dimRect.maxX), height: dimRect.height))
transition.updateFrame(node: self.frameNode, frame: dimRect.insetBy(dx: -2.0, dy: -2.0))
let buttonSize = CGSize(width: 72.0, height: 72.0)

View File

@ -155,8 +155,10 @@ private final class WalletQrViewScreenNode: ViewControllerTracingNode {
let imageFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: floor((layout.size.height - imageSize.height - layout.intrinsicInsets.bottom) / 2.0)), size: imageSize)
transition.updateFrame(node: self.imageNode, frame: imageFrame)
let iconFrame = imageFrame.insetBy(dx: 106.0, dy: 106.0).offsetBy(dx: 0.0, dy: -2.0)
self.iconNode.updateLayout(size: iconFrame.size)
transition.updateFrameAsPositionAndBounds(node: self.iconNode, frame: iconFrame)
let iconSide = floor(imageSide * 0.24)
let iconSize = CGSize(width: iconSide, height: iconSide)
self.iconNode.updateLayout(size: iconSize)
transition.updateBounds(node: self.iconNode, bounds: CGRect(origin: CGPoint(), size: iconSize))
transition.updatePosition(node: self.iconNode, position: imageFrame.center.offsetBy(dx: 0.0, dy: -1.0))
}
}