diff --git a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift index 76d7f5a7cb..c2445f658e 100644 --- a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift +++ b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift @@ -905,6 +905,9 @@ public final class AnimatedStickerNode: ASDisplayNode { private var isSetUpForPlayback = false public func play(firstFrame: Bool = false) { + if case .once = self.playbackMode { + self.isPlaying = true + } if self.isSetUpForPlayback { let directData = self.directData let cachedData = self.cachedData diff --git a/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift b/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift index 30b7e823eb..209bae920e 100644 --- a/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift +++ b/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift @@ -60,7 +60,7 @@ public func messageFileMediaResourceStatus(context: AccountContext, file: Telegr mediaStatus = .playbackStatus(.playing) case .paused: mediaStatus = .playbackStatus(.paused) - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): if whilePlaying { mediaStatus = .playbackStatus(.playing) } else { @@ -84,7 +84,7 @@ public func messageFileMediaResourceStatus(context: AccountContext, file: Telegr mediaStatus = .playbackStatus(.playing) case .paused: mediaStatus = .playbackStatus(.paused) - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): if whilePlaying { mediaStatus = .playbackStatus(.playing) } else { diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 36f09bb9c2..347d5a45f4 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -634,6 +634,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { var isPaused = true var seekable = false var hasStarted = false + var displayProgress = true if let value = value { hasStarted = value.timestamp > 0 @@ -648,7 +649,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { case .playing: isPaused = false playing = true - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, display): + displayProgress = display initialBuffering = true isPaused = !whilePlaying var isStreaming = false @@ -700,7 +702,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { var fetching = false if initialBuffering { - strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false), animated: false, completion: {}) + if displayProgress { + strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false), animated: false, completion: {}) + } else { + strongSelf.statusNode.transitionToState(.none, animated: false, completion: {}) + } } else { var state: RadialStatusNodeState = .play(.white) diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m index 022b8cc8e0..2a52ae7986 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m @@ -1290,6 +1290,9 @@ - (void)_seekToPosition:(NSTimeInterval)position manual:(bool)__unused manual { + if (self.player == nil) { + return; + } CMTime targetTime = CMTimeMakeWithSeconds(position, NSEC_PER_SEC); if (CMTIME_COMPARE_INLINE(targetTime, !=, _chaseTime)) diff --git a/submodules/LocationUI/Sources/LocationDistancePickerScreen.swift b/submodules/LocationUI/Sources/LocationDistancePickerScreen.swift index f95b8e9ead..189589879d 100644 --- a/submodules/LocationUI/Sources/LocationDistancePickerScreen.swift +++ b/submodules/LocationUI/Sources/LocationDistancePickerScreen.swift @@ -465,8 +465,8 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD func animateIn() { self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) - let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY - self.wrappingScrollNode.layer.animateBoundsOriginYAdditive(from: -offset, to: 0.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring) + let offset = self.contentContainerNode.frame.height + self.wrappingScrollNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true) } func animateOut(completion: (() -> Void)? = nil) { @@ -485,8 +485,8 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD internalCompletion() }) - let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY - self.wrappingScrollNode.layer.animateBoundsOriginYAdditive(from: 0.0, to: -offset, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in + let offset = self.contentContainerNode.frame.height + self.wrappingScrollNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: { _ in offsetCompleted = true internalCompletion() }) diff --git a/submodules/LocationUI/Sources/LocationMapNode.swift b/submodules/LocationUI/Sources/LocationMapNode.swift index 114df8d0b7..ffaca3d40a 100644 --- a/submodules/LocationUI/Sources/LocationMapNode.swift +++ b/submodules/LocationUI/Sources/LocationMapNode.swift @@ -83,6 +83,11 @@ private class LocationMapView: MKMapView, UIGestureRecognizerDelegate { return pointInside } + + public override func layoutSubviews() { + super.layoutSubviews() + + } } private let arrowImageSize = CGSize(width: 90.0, height: 90.0) @@ -110,14 +115,16 @@ func generateHeadingArrowImage() -> UIImage? { }) } -private func generateProximityDim(size: CGSize, rect: CGRect) -> UIImage { +private func generateProximityDim(size: CGSize) -> UIImage { return generateImage(size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.4).cgColor) context.fill(CGRect(origin: CGPoint(), size: size)) context.setBlendMode(.clear) - context.fillEllipse(in: rect) + + let ellipseSize = CGSize(width: 260.0, height: 260.0) + context.fillEllipse(in: CGRect(origin: CGPoint(x: (size.width - ellipseSize.width) / 2.0, y: (size.height - ellipseSize.height) / 2.0), size: ellipseSize)) })! } @@ -144,64 +151,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { context.restoreGState() } } - - class InvertedProximityCircle: NSObject, MKOverlay { - var coordinate: CLLocationCoordinate2D - var radius: Double - var alpha: CGFloat { - didSet { - self.alphaTransition = (oldValue, CACurrentMediaTime(), 0.3) - } - } - var alphaTransition: (from: CGFloat, startTimestamp: Double, duration: Double)? - var boundingMapRect: MKMapRect { - return MKMapRect.world - } - - init(center coord: CLLocationCoordinate2D, radius: Double, alpha: CGFloat = 0.0) { - self.coordinate = coord - self.radius = radius - self.alpha = alpha - } - } - - class InvertedProximityCircleRenderer: MKOverlayRenderer { - var radius: Double = 0.0 - var fillColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.5) - - override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) { - guard let overlay = self.overlay as? InvertedProximityCircle else { - return - } - - var alpha: CGFloat = overlay.alpha - if let transition = overlay.alphaTransition { - var t = (CACurrentMediaTime() - transition.startTimestamp) / transition.duration - t = min(1.0, max(0.0, t)) - alpha = transition.from + (alpha - transition.from) * CGFloat(t) - } - - context.setAlpha(alpha) - - let path = UIBezierPath(rect: CGRect(x: mapRect.origin.x, y: mapRect.origin.y, width: mapRect.size.width, height: mapRect.size.height)) - let radiusInMap = overlay.radius * MKMapPointsPerMeterAtLatitude(overlay.coordinate.latitude) * 2.0 - let mapSize: MKMapSize = MKMapSize(width: radiusInMap, height: radiusInMap) - let regionOrigin = MKMapPoint(overlay.coordinate) - var regionRect: MKMapRect = MKMapRect(origin: regionOrigin, size: mapSize) - regionRect = regionRect.offsetBy(dx: -radiusInMap / 2.0, dy: -radiusInMap / 2.0); - regionRect = regionRect.intersection(MKMapRect.world); - - let excludePath: UIBezierPath = UIBezierPath(roundedRect: CGRect(x: regionRect.origin.x, y: regionRect.origin.y, width: regionRect.size.width, height: regionRect.size.height), cornerRadius: CGFloat(regionRect.size.width) / 2.0) - path.append(excludePath) - - context.setFillColor(fillColor.cgColor); - context.addPath(path.cgPath); - context.fillPath(using: .evenOdd) - } - } - private weak var currentInvertedCircleRenderer: InvertedProximityCircleRenderer? - private let locationPromise = Promise(nil) private let pickerAnnotationContainerView: PickerAnnotationContainerView @@ -222,74 +172,34 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { var annotationSelected: ((LocationPinAnnotation?) -> Void)? var userLocationAnnotationSelected: (() -> Void)? - - var indicatorOverlay: InvertedProximityCircle? + + var proximityDimView = UIImageView() var proximityIndicatorRadius: Double? { didSet { - if let activeProximityRadius = self.proximityIndicatorRadius { - if let location = self.currentUserLocation, activeProximityRadius != oldValue { - let indicatorOverlay: InvertedProximityCircle - if let current = self.indicatorOverlay { - indicatorOverlay = current - indicatorOverlay.radius = activeProximityRadius - self.mapView?.removeOverlay(indicatorOverlay) - self.mapView?.addOverlay(indicatorOverlay) - } else { - indicatorOverlay = InvertedProximityCircle(center: location.coordinate, radius: activeProximityRadius) - self.mapView?.addOverlay(indicatorOverlay) - self.indicatorOverlay = indicatorOverlay - indicatorOverlay.alpha = 1.0 - self.updateAnimations() + if let radius = self.proximityIndicatorRadius, let mapView = self.mapView { + if self.proximityDimView.image == nil { + proximityDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + + if oldValue == 0 { + UIView.transition(with: proximityDimView, duration: 0.3, options: .transitionCrossDissolve) { + self.proximityDimView.image = generateProximityDim(size: mapView.bounds.size) + } completion: { _ in + } } } else { - if let indicatorOverlay = self.indicatorOverlay { - indicatorOverlay.alpha = 0.0 - self.updateAnimations() + if self.proximityDimView.image != nil { + UIView.transition(with: proximityDimView, duration: 0.3, options: .transitionCrossDissolve) { + self.proximityDimView.image = nil + } completion: { _ in + + } } } } } - - private var animator: ConstantDisplayLinkAnimator? - private func updateAnimations() { - guard let mapView = self.mapView else { - return - } - var animate = false - let timestamp = CACurrentMediaTime() - - if let indicatorOverlay = self.indicatorOverlay, let transition = indicatorOverlay.alphaTransition { - if transition.startTimestamp + transition.duration < timestamp { - indicatorOverlay.alphaTransition = nil - if indicatorOverlay.alpha.isZero { - self.indicatorOverlay = nil - mapView.removeOverlay(indicatorOverlay) - } - } else { - animate = true - } - } - - if animate { - let animator: ConstantDisplayLinkAnimator - if let current = self.animator { - animator = current - } else { - animator = ConstantDisplayLinkAnimator(update: { [weak self] in - self?.updateAnimations() - }) - self.animator = animator - } - animator.isPaused = false - } else { - self.animator?.isPaused = true - } - - self.currentInvertedCircleRenderer?.setNeedsDisplay(MKMapRect.world) - } - private var circleOverlay: MKCircle? var activeProximityRadius: Double? { didSet { @@ -380,6 +290,18 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { } } + var mapOffset: CGFloat = 0.0 + func setMapCenter(coordinate: CLLocationCoordinate2D, radius: Double, insets: UIEdgeInsets, offset: CGFloat, animated: Bool = false) { + self.mapOffset = offset + self.ignoreRegionChanges = true + + let mapRect = MKMapRect(region: MKCoordinateRegion(center: coordinate, latitudinalMeters: radius * 2.0, longitudinalMeters: radius * 2.0)) + self.mapView?.setVisibleMapRect(mapRect, edgePadding: insets, animated: animated) + self.ignoreRegionChanges = false + + self.proximityDimView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY + offset) + } + func setMapCenter(coordinate: CLLocationCoordinate2D, span: MKCoordinateSpan = defaultMapSpan, offset: CGPoint = CGPoint(), isUserLocation: Bool = false, hidePicker: Bool = false, animated: Bool = false) { let region = MKCoordinateRegion(center: coordinate, span: span) self.ignoreRegionChanges = true @@ -479,6 +401,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { } else if let view = view as? LocationPinAnnotationView { view.setZPosition(view.defaultZPosition) } + + if let container = view.superview { + container.insertSubview(self.proximityDimView, at: 0) + } } } @@ -518,11 +444,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { } func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { - if let invertedCircle = overlay as? InvertedProximityCircle { - let renderer = InvertedProximityCircleRenderer(overlay: invertedCircle) - self.currentInvertedCircleRenderer = renderer - return renderer - } else if let circle = overlay as? MKCircle { + if let circle = overlay as? MKCircle { let renderer = ProximityCircleRenderer(circle: circle) renderer.fillColor = .clear renderer.strokeColor = UIColor(rgb: 0xc3baaf) @@ -533,18 +455,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { return MKOverlayRenderer() } } - - func mapView(_ mapView: MKMapView, didAdd renderers: [MKOverlayRenderer]) { - for renderer in renderers { - if let renderer = renderer as? InvertedProximityCircleRenderer { - renderer.alpha = 0.0 - UIView.animate(withDuration: 0.3) { - renderer.alpha = 1.0 - } - } - } - } - + var distancesToAllAnnotations: Signal<[Double], NoError> { let poll = Signal<[LocationPinAnnotation], NoError> { [weak self] subscriber in if let strongSelf = self { @@ -806,6 +717,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate { } func updateLayout(size: CGSize) { + self.proximityDimView.frame = CGRect(origin: CGPoint(x: 0.0, y: self.mapOffset), size: size) self.pickerAnnotationContainerView.frame = CGRect(x: 0.0, y: floorToScreenPixels((size.height - size.width) / 2.0), width: size.width, height: size.width) if let pickerAnnotationView = self.pickerAnnotationView { pickerAnnotationView.center = CGPoint(x: self.pickerAnnotationContainerView.frame.width / 2.0, y: self.pickerAnnotationContainerView.frame.height / 2.0) diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index 6c063fccc9..fa7d18e75c 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -599,17 +599,28 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan } func setProximityIndicator(radius: Int32?) { + guard let (layout, navigationBarHeight) = self.validLayout else { + return + } if let radius = radius { self.headerNode.forceIsHidden = true - if var coordinate = self.headerNode.mapNode.currentUserLocation?.coordinate, let span = self.headerNode.mapNode.mapSpan { - coordinate.latitude -= span.latitudeDelta * 0.11 + if let coordinate = self.headerNode.mapNode.currentUserLocation?.coordinate { self.updateState { state in var state = state - state.selectedLocation = .coordinate(coordinate, true) + state.selectedLocation = .custom state.trackingMode = .none return state } + + let panelHeight: CGFloat = 349.0 + layout.intrinsicInsets.bottom + let inset = (layout.size.width - 260.0) / 2.0 + let offset = panelHeight / 2.0 + 60.0 + inset + navigationBarHeight / 2.0 + + let point = CGPoint(x: layout.size.width / 2.0, y: navigationBarHeight + (layout.size.height - navigationBarHeight - panelHeight) / 2.0) + let convertedPoint = self.view.convert(point, to: self.headerNode.mapNode.view) + + self.headerNode.mapNode.setMapCenter(coordinate: coordinate, radius: Double(radius), insets: UIEdgeInsets(top: navigationBarHeight, left: inset, bottom: offset, right: inset), offset: convertedPoint.y - self.headerNode.mapNode.frame.height / 2.0, animated: true) } self.headerNode.mapNode.proximityIndicatorRadius = Double(radius) diff --git a/submodules/MediaPlayer/Sources/MediaPlayer.swift b/submodules/MediaPlayer/Sources/MediaPlayer.swift index 759466aba7..1ac1ab6327 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayer.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayer.swift @@ -294,12 +294,12 @@ private final class MediaPlayerContext { duration = max(duration, CMTimeGetSeconds(audioTrackFrameBuffer.duration)) } loadedDuration = duration - let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: duration, dimensions: CGSize(), timestamp: min(max(timestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play, progress: 0.0), soundEnabled: self.enableSound) + let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: duration, dimensions: CGSize(), timestamp: min(max(timestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play, progress: 0.0, display: true), soundEnabled: self.enableSound) self.playerStatus.set(.single(status)) let _ = self.playerStatusValue.swap(status) } else { let duration = seekState?.duration ?? 0.0 - let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: duration, dimensions: CGSize(), timestamp: min(max(timestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play, progress: 0.0), soundEnabled: self.enableSound) + let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: duration, dimensions: CGSize(), timestamp: min(max(timestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play, progress: 0.0, display: true), soundEnabled: self.enableSound) self.playerStatus.set(.single(status)) let _ = self.playerStatusValue.swap(status) } @@ -875,7 +875,7 @@ private final class MediaPlayerContext { if case .playing = self.state { whilePlaying = true } - playbackStatus = .buffering(initial: false, whilePlaying: whilePlaying, progress: Float(bufferingProgress)) + playbackStatus = .buffering(initial: false, whilePlaying: whilePlaying, progress: Float(bufferingProgress), display: true) } else if !rate.isZero { if reportRate.isZero { //playbackStatus = .buffering(initial: false, whilePlaying: true) @@ -926,7 +926,7 @@ private final class MediaPlayerContext { public enum MediaPlayerPlaybackStatus: Equatable { case playing case paused - case buffering(initial: Bool, whilePlaying: Bool, progress: Float) + case buffering(initial: Bool, whilePlaying: Bool, progress: Float, display: Bool) public static func ==(lhs: MediaPlayerPlaybackStatus, rhs: MediaPlayerPlaybackStatus) -> Bool { switch lhs { @@ -942,8 +942,8 @@ public enum MediaPlayerPlaybackStatus: Equatable { } else { return false } - case let .buffering(initial, whilePlaying, progress): - if case .buffering(initial, whilePlaying, progress) = rhs { + case let .buffering(initial, whilePlaying, progress, display): + if case .buffering(initial, whilePlaying, progress, display) = rhs { return true } else { return false diff --git a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift index bd3a68be34..0e7941cf0a 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift @@ -781,7 +781,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { default: break } - if case .buffering(true, _, _) = statusValue.status { + if case .buffering(true, _, _, _) = statusValue.status { //initialBuffering = true } else if Double(0.0).isLess(than: statusValue.duration) { if let scrubbingTimestampValue = self.scrubbingTimestampValue { diff --git a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift index f4f5316a8c..7bf5843296 100644 --- a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift +++ b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift @@ -331,7 +331,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi switch status { case .paused: paused = true - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): paused = !whilePlaying case .playing: paused = false diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index a68301a3a3..34e64ead2d 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -111,6 +111,9 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo } else if let _ = media as? TelegramMediaPoll { hasUneditableAttributes = true break + } else if let _ = media as? TelegramMediaDice { + hasUneditableAttributes = true + break } } diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 19b3198017..331b4b2b54 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1274,7 +1274,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { return .optionalAction({ if shouldPlay { let _ = (appConfiguration - |> deliverOnMainQueue).start(next: { [weak self] appConfiguration in + |> deliverOnMainQueue).start(next: { [weak self, weak animationNode] appConfiguration in guard let strongSelf = self else { return } @@ -1315,9 +1315,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } })) - break + return } } + animationNode?.play() }) } }) diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 562f70d5cc..02b79c940c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -832,7 +832,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { if isAudio && !isVoice { state = .play } else { - if adjustedProgress.isEqual(to: 1.0), (message.flags.contains(.Unsent) || wasCheck) { + if message.groupingKey != nil, adjustedProgress.isEqual(to: 1.0), (message.flags.contains(.Unsent) || wasCheck) { state = .check(appearance: nil) } else { state = .progress(value: CGFloat(adjustedProgress), cancelEnabled: true, appearance: nil) diff --git a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift index e3d815934e..b4c5fd7b3a 100644 --- a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift @@ -176,7 +176,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode { |> deliverOnMainQueue).start(next: { [weak self] status in if let strongSelf = self { switch status.status { - case .playing, .buffering(_, true, _): + case .playing, .buffering(_, true, _, _): strongSelf.playButton.isHidden = true default: strongSelf.playButton.isHidden = false diff --git a/submodules/TelegramUI/Sources/MediaManager.swift b/submodules/TelegramUI/Sources/MediaManager.swift index 988498fede..eddeac9ad9 100644 --- a/submodules/TelegramUI/Sources/MediaManager.swift +++ b/submodules/TelegramUI/Sources/MediaManager.swift @@ -150,7 +150,7 @@ public final class MediaManagerImpl: NSObject, MediaManager { switch value.status.status { case .playing: isPlaying = true - case .buffering(_, true, _): + case .buffering(_, true, _, _): isPlaying = true default: break @@ -230,7 +230,7 @@ public final class MediaManagerImpl: NSObject, MediaManager { updatedGlobalControlOptions.insert(.next) updatedGlobalControlOptions.insert(.seek) switch state.status.status { - case .playing, .buffering(_, true, _): + case .playing, .buffering(_, true, _, _): updatedGlobalControlOptions.insert(.pause) default: updatedGlobalControlOptions.insert(.play) @@ -384,7 +384,7 @@ public final class MediaManagerImpl: NSObject, MediaManager { switch state.status.status { case .playing: isPlaying = true - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): isPlaying = whilePlaying default: break diff --git a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift index f513a740b7..a6147e20ff 100644 --- a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift +++ b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift @@ -304,7 +304,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode { isPaused = false case .paused: isPaused = true - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): isPaused = !whilePlaying } if strongSelf.currentIsPaused != isPaused { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index cd6d5b2961..f96aa5d52f 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -311,7 +311,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode { var bufferingProgress: Float? if isMediaStreamable(resource: videoContent.fileReference.media.resource) { if let playerStatus = self.playerStatus { - if case let .buffering(_, _, progress) = playerStatus.status { + if case let .buffering(_, _, progress, _) = playerStatus.status { bufferingProgress = progress } else if case .playing = playerStatus.status { bufferingProgress = nil diff --git a/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift index 65dae43824..ce2f67df30 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift @@ -14,7 +14,7 @@ final class GenericEmbedImplementation: WebEmbedImplementation { init(url: String) { self.url = url - self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0), soundEnabled: true) + self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0, display: true), soundEnabled: true) } func setup(_ webView: WKWebView, userContentController: WKUserContentController, evaluateJavaScript: @escaping (String, ((Any?) -> Void)?) -> Void, updateStatus: @escaping (MediaPlayerStatus) -> Void, onPlaybackStarted: @escaping () -> Void) { diff --git a/submodules/TelegramUniversalVideoContent/Sources/PictureInPictureVideoControlsNode.swift b/submodules/TelegramUniversalVideoContent/Sources/PictureInPictureVideoControlsNode.swift index fd483dae68..e3be01867d 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/PictureInPictureVideoControlsNode.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/PictureInPictureVideoControlsNode.swift @@ -37,7 +37,7 @@ final class PictureInPictureVideoControlsNode: ASDisplayNode { case .playing: self.playButton.isHidden = true self.pauseButton.isHidden = false - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): if whilePlaying { self.playButton.isHidden = true self.pauseButton.isHidden = false diff --git a/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift index 517a7fef05..ddcea50be2 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift @@ -315,7 +315,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte self.isBuffering = false } if self.isBuffering { - status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0) + status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0, display: true) } else { status = isPlaying ? .playing : .paused } @@ -326,7 +326,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte let status: MediaPlayerPlaybackStatus self.isBuffering = true if self.isBuffering { - status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0) + status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0, display: true) } else { status = isPlaying ? .playing : .paused } @@ -337,7 +337,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte let status: MediaPlayerPlaybackStatus self.isBuffering = false if self.isBuffering { - status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0) + status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0, display: true) } else { status = isPlaying ? .playing : .paused } @@ -381,7 +381,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte func play() { assert(Queue.mainQueue().isCurrent()) if !self.initializedStatus { - self._status.set(MediaPlayerStatus(generationTimestamp: 0.0, duration: Double(self.approximateDuration), dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0), soundEnabled: true)) + self._status.set(MediaPlayerStatus(generationTimestamp: 0.0, duration: Double(self.approximateDuration), dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0, display: true), soundEnabled: true)) } if !self.hasAudioSession { self.audioSessionDisposable.set(self.audioSessionManager.push(audioSessionType: .play, activate: { [weak self] _ in diff --git a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift index 629adfe05a..238549cb2c 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift @@ -44,7 +44,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent private let playbackCompletedListeners = Bag<() -> Void>() private var initializedStatus = false - private var statusValue = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: false, progress: 0.0), soundEnabled: true) + private var statusValue = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: false, progress: 0.0, display: true), soundEnabled: true) private var isBuffering = true private let _status = ValuePromise() var status: Signal { @@ -169,7 +169,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent let isPlaying = !self.player.rate.isZero let status: MediaPlayerPlaybackStatus if self.isBuffering { - status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0) + status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0, display: true) } else { status = isPlaying ? .playing : .paused } @@ -180,7 +180,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent let status: MediaPlayerPlaybackStatus self.isBuffering = true if self.isBuffering { - status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0) + status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0, display: true) } else { status = isPlaying ? .playing : .paused } @@ -191,7 +191,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent let status: MediaPlayerPlaybackStatus self.isBuffering = false if self.isBuffering { - status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0) + status = .buffering(initial: false, whilePlaying: isPlaying, progress: 0.0, display: true) } else { status = isPlaying ? .playing : .paused } @@ -219,7 +219,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent func play() { assert(Queue.mainQueue().isCurrent()) if !self.initializedStatus { - self._status.set(MediaPlayerStatus(generationTimestamp: 0.0, duration: Double(self.approximateDuration), dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: self.seekId, status: .buffering(initial: true, whilePlaying: true, progress: 0.0), soundEnabled: true)) + self._status.set(MediaPlayerStatus(generationTimestamp: 0.0, duration: Double(self.approximateDuration), dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: self.seekId, status: .buffering(initial: true, whilePlaying: true, progress: 0.0, display: true), soundEnabled: true)) } if !self.hasAudioSession { self.audioSessionDisposable.set(self.audioSessionManager.push(audioSessionType: .play, activate: { [weak self] _ in diff --git a/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift index 4c4041c36e..85fb56e6ba 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift @@ -20,7 +20,7 @@ final class TwitchEmbedImplementation: WebEmbedImplementation { init(url: String) { self.url = url - self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0), soundEnabled: true) + self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0, display: true), soundEnabled: true) } func setup(_ webView: WKWebView, userContentController: WKUserContentController, evaluateJavaScript: @escaping (String, ((Any?) -> Void)?) -> Void, updateStatus: @escaping (MediaPlayerStatus) -> Void, onPlaybackStarted: @escaping () -> Void) { diff --git a/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift index a1af6625ff..bd0db6638f 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift @@ -97,7 +97,7 @@ final class VimeoEmbedImplementation: WebEmbedImplementation { init(videoId: String, timestamp: Int = 0) { self.videoId = videoId self.timestamp = timestamp - self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: Double(timestamp), baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0), soundEnabled: true) + self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: Double(timestamp), baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0, display: true), soundEnabled: true) } func setup(_ webView: WKWebView, userContentController: WKUserContentController, evaluateJavaScript: @escaping (String, ((Any?) -> Void)?) -> Void, updateStatus: @escaping (MediaPlayerStatus) -> Void, onPlaybackStarted: @escaping () -> Void) { @@ -221,7 +221,7 @@ final class VimeoEmbedImplementation: WebEmbedImplementation { playbackStatus = .paused newTimestamp = 0.0 default: - playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0) + playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0, display: true) } self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: 1.0, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true) diff --git a/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift index 7bb56feac0..c9140d8af9 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift @@ -101,7 +101,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { private var timestamp: Int private var ignoreEarlierTimestamps = false - private var status : MediaPlayerStatus + private var status: MediaPlayerStatus private var ready = false private var started = false @@ -117,11 +117,11 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { init(videoId: String, timestamp: Int = 0) { self.videoId = videoId - self.timestamp = 0 + self.timestamp = timestamp if self.timestamp > 0 { self.ignoreEarlierTimestamps = true } - self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: Double(timestamp), baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0), soundEnabled: true) + self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: Double(timestamp), baseRate: 1.0, seekId: 0, status: .buffering(initial: true, whilePlaying: true, progress: 0.0, display: true), soundEnabled: true) self.benchmarkStartTime = CFAbsoluteTimeGetCurrent() } @@ -286,16 +286,16 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation { playbackStatus = .paused newTimestamp = 0.0 } else { - playbackStatus = .buffering(initial: false, whilePlaying: true, progress: 0.0) + playbackStatus = .buffering(initial: false, whilePlaying: true, progress: 0.0, display: false) } case 1: playbackStatus = .playing case 2: playbackStatus = .paused case 3: - playbackStatus = .buffering(initial: false, whilePlaying: true, progress: 0.0) + playbackStatus = .buffering(initial: false, whilePlaying: true, progress: 0.0, display: false) default: - playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0) + playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0, display: false) } if case .playing = playbackStatus, !self.started { diff --git a/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift b/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift index 4ce6a36057..739053cb79 100644 --- a/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift +++ b/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift @@ -198,7 +198,7 @@ final class WebSearchVideoGalleryItemNode: ZoomableContentGalleryItemNode { switch value.status { case .playing: isPaused = false - case let .buffering(_, whilePlaying, _): + case let .buffering(_, whilePlaying, _, _): initialBuffering = true isPaused = !whilePlaying var isStreaming = false