Various Fixes

This commit is contained in:
Ilya Laktyushin 2021-08-03 20:30:56 +03:00
parent 80e00293b6
commit c187f16728
24 changed files with 626 additions and 198 deletions

View File

@ -40,8 +40,9 @@ public final class PeerSelectionControllerParams {
public let createNewGroup: (() -> Void)?
public let pretendPresentedInModal: Bool
public let multipleSelection: Bool
public let forwardedMessagesCount: Int
public init(context: AccountContext, filter: ChatListNodePeersFilter = [.onlyWriteable], hasChatListSelector: Bool = true, hasContactSelector: Bool = true, hasGlobalSearch: Bool = true, title: String? = nil, attemptSelection: ((Peer) -> Void)? = nil, createNewGroup: (() -> Void)? = nil, pretendPresentedInModal: Bool = false, multipleSelection: Bool = false) {
public init(context: AccountContext, filter: ChatListNodePeersFilter = [.onlyWriteable], hasChatListSelector: Bool = true, hasContactSelector: Bool = true, hasGlobalSearch: Bool = true, title: String? = nil, attemptSelection: ((Peer) -> Void)? = nil, createNewGroup: (() -> Void)? = nil, pretendPresentedInModal: Bool = false, multipleSelection: Bool = false, forwardedMessagesCount: Int = 0) {
self.context = context
self.filter = filter
self.hasChatListSelector = hasChatListSelector
@ -52,6 +53,7 @@ public final class PeerSelectionControllerParams {
self.createNewGroup = createNewGroup
self.pretendPresentedInModal = pretendPresentedInModal
self.multipleSelection = multipleSelection
self.forwardedMessagesCount = forwardedMessagesCount
}
}

View File

@ -1727,32 +1727,28 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context, displayBackground: true)
mediaAccessoryPanel.containerNode.headerNode.displayScrubber = item.playbackData?.type != .instantVideo
mediaAccessoryPanel.getController = { [weak self] in
return self?.navigationController?.topViewController as? ViewController
}
mediaAccessoryPanel.presentInGlobalOverlay = { [weak self] c in
(self?.navigationController?.topViewController as? ViewController)?.presentInGlobalOverlay(c)
}
mediaAccessoryPanel.close = { [weak self] in
if let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
}
}
mediaAccessoryPanel.toggleRate = {
[weak self] in
mediaAccessoryPanel.setRate = { [weak self] rate in
guard let strongSelf = self else {
return
}
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings
let nextRate: AudioPlaybackRate
switch settings.voicePlaybackRate {
case .x1:
nextRate = .x2
case .x2:
nextRate = .x1
default:
nextRate = .x1
}
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in
return settings.withUpdatedVoicePlaybackRate(nextRate)
return settings.withUpdatedVoicePlaybackRate(rate)
})
return nextRate
return rate
}
|> deliverOnMainQueue).start(next: { baseRate in
guard let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType else {
@ -1771,22 +1767,31 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
})
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let slowdown = baseRate == .x1
controller.present(
UndoOverlayController(
presentationData: presentationData,
content: .audioRate(
slowdown: slowdown,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
let slowdown: Bool?
if baseRate == .x1 {
slowdown = true
} else if baseRate == .x2 {
slowdown = false
} else {
slowdown = nil
}
if let slowdown = slowdown {
controller.present(
UndoOverlayController(
presentationData: presentationData,
content: .audioRate(
slowdown: slowdown,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
),
elevatedLayout: false,
animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
elevatedLayout: false,
animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
in: .current
)
in: .current
)
}
}
})
}

View File

@ -524,6 +524,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
private let isInteractingPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
private let controlsVisiblePromise = ValuePromise<Bool>(true, ignoreRepeated: true)
private let isShowingContextMenuPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
private let hasExpandedCaptionPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
private var hideControlsDisposable: Disposable?
var playbackCompleted: (() -> Void)?
@ -701,12 +702,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
self.titleContentView = GalleryTitleView(frame: CGRect())
self._titleView.set(.single(self.titleContentView))
let shouldHideControlsSignal: Signal<Void, NoError> = combineLatest(self.isPlayingPromise.get(), self.isInteractingPromise.get(), self.controlsVisiblePromise.get(), self.isShowingContextMenuPromise.get())
|> mapToSignal { isPlaying, isIntracting, controlsVisible, isShowingContextMenu -> Signal<Void, NoError> in
if isShowingContextMenu {
let shouldHideControlsSignal: Signal<Void, NoError> = combineLatest(self.isPlayingPromise.get(), self.isInteractingPromise.get(), self.controlsVisiblePromise.get(), self.isShowingContextMenuPromise.get(), self.hasExpandedCaptionPromise.get())
|> mapToSignal { isPlaying, isInteracting, controlsVisible, isShowingContextMenu, hasExpandedCaptionPromise -> Signal<Void, NoError> in
if isShowingContextMenu || hasExpandedCaptionPromise {
return .complete()
}
if isPlaying && !isIntracting && controlsVisible {
if isPlaying && !isInteracting && controlsVisible {
return .single(Void())
|> delay(4.0, queue: Queue.mainQueue())
} else {

View File

@ -76,6 +76,6 @@ typedef enum {
+ (UIInterfaceOrientation)_interfaceOrientationForDeviceOrientation:(UIDeviceOrientation)orientation;
+ (bool)useLegacyCamera;
+ (UIImage *)startImage;
@end

View File

@ -4,6 +4,7 @@
#import <LegacyComponents/TGMenuSheetView.h>
#import "TGAttachmentMenuCell.h"
#import "TGCameraController.h"
#import <LegacyComponents/PGCamera.h>
#import <LegacyComponents/TGCameraPreviewView.h>
@ -46,6 +47,8 @@
_camera = camera;
_previewView = [[TGCameraPreviewView alloc] initWithFrame:CGRectMake(0, 0, 84.0f, 84.0f)];
[_previewView fadeInAnimated:false];
[_previewView beginTransitionWithSnapshotImage:[TGCameraController startImage] animated:false];
[_wrapperView addSubview:_previewView];
[camera attachPreviewView:_previewView];

View File

@ -2251,6 +2251,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
_dismissing = true;
self.view.userInteractionEnabled = false;
_focusControl.active = false;
_rectangleView.hidden = true;
@ -2267,6 +2268,15 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
referenceFrame = self.beginTransitionOut();
__weak TGCameraController *weakSelf = self;
[_camera captureNextFrameCompletion:^(UIImage *frameImage) {
CGFloat minSize = MIN(frameImage.size.width, frameImage.size.height);
CGFloat maxSize = MAX(frameImage.size.width, frameImage.size.height);
UIImage *image = TGPhotoEditorCrop(frameImage, nil, UIImageOrientationUp, 0.0f, CGRectMake((maxSize - minSize) / 2.0f, 0.0f, minSize, minSize), false, CGSizeMake(240.0f, 240.0f), frameImage.size, true);
UIImage *startImage = TGSecretBlurredAttachmentImage(image, image.size, NULL, false, 0);
[TGCameraController saveStartImage:startImage];
}];
if (_standalone)
{
[self simpleTransitionOutWithVelocity:velocity completion:^
@ -2757,11 +2767,6 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
}
}
+ (bool)useLegacyCamera
{
return false;
}
+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id<TGMediaSelectableItem>)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator
{
NSMutableArray *signals = [[NSMutableArray alloc] init];
@ -3144,4 +3149,24 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
return value;
}
#pragma mark - Start Image
static UIImage *startImage = nil;
+ (UIImage *)startImage
{
if (startImage == nil)
startImage = TGComponentsImageNamed (@"VideoMessagePlaceholder.jpg");
return startImage;
}
+ (void)saveStartImage:(UIImage *)image
{
if (image == nil)
return;
startImage = image;
}
@end

View File

@ -129,10 +129,15 @@
if (strongSelf == nil)
return;
if (resume)
if (resume) {
[strongSelf endResetTransitionAnimated:true];
else
[strongSelf fadeInAnimated:true];
} else {
if (strongSelf->_snapshotView != nil) {
[strongSelf endTransitionAnimated:true];
} else {
[strongSelf fadeInAnimated:true];
}
}
};
camera.captureStopped = ^(bool pause)
@ -262,6 +267,10 @@
}
}
- (bool)hasTransitionSnapshot {
return _snapshotView != nil;
}
- (void)beginResetTransitionAnimated:(bool)animated
{
if (iosMajorVersion() < 7)
@ -319,7 +328,12 @@
if (_snapshotView != nil)
{
CGSize size = TGScaleToFill(_snapshotView.frame.size, _wrapperView.frame.size);
CGSize imageSize = _snapshotView.frame.size;
if ([_snapshotView isKindOfClass:[UIImageView class]]) {
imageSize = ((UIImageView *)_snapshotView).image.size;
}
CGSize size = TGScaleToFill(imageSize, _wrapperView.frame.size);
_snapshotView.frame = CGRectMake(floor((self.frame.size.width - size.width) / 2.0f), floor((self.frame.size.height - size.height) / 2.0f), size.width, size.height);
}
}

View File

@ -53,7 +53,7 @@
_hasSearchButton = hasSearchButton;
_hasDeleteButton = hasDeleteButton;
_hasViewButton = hasViewButton;
_personalPhoto = ![TGCameraController useLegacyCamera] ? personalPhoto : false;
_personalPhoto = personalPhoto;
_isVideo = isVideo;
_signup = signup;
}

View File

@ -27,6 +27,7 @@ swift_library(
"//submodules/AccountContext:AccountContext",
"//submodules/SegmentedControlNode:SegmentedControlNode",
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
"//submodules/ShimmerEffect:ShimmerEffect",
],
visibility = [
"//visibility:public",

View File

@ -10,6 +10,7 @@ import TelegramStringFormatting
import SelectablePeerNode
import PeerPresenceStatusManager
import AccountContext
import ShimmerEffect
final class ShareControllerInteraction {
var foundPeers: [RenderedPeer] = []
@ -89,14 +90,14 @@ final class ShareControllerPeerGridItem: GridItem {
let context: AccountContext
let theme: PresentationTheme
let strings: PresentationStrings
let peer: RenderedPeer
let peer: RenderedPeer?
let presence: PeerPresence?
let controllerInteraction: ShareControllerInteraction
let search: Bool
let section: GridSection?
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, presence: PeerPresence?, controllerInteraction: ShareControllerInteraction, sectionTitle: String? = nil, search: Bool = false) {
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer?, presence: PeerPresence?, controllerInteraction: ShareControllerInteraction, sectionTitle: String? = nil, search: Bool = false) {
self.context = context
self.theme = theme
self.strings = strings
@ -130,12 +131,15 @@ final class ShareControllerPeerGridItem: GridItem {
}
final class ShareControllerPeerGridItemNode: GridItemNode {
private var currentState: (AccountContext, PresentationTheme, PresentationStrings, RenderedPeer, Bool, PeerPresence?)?
private var currentState: (AccountContext, PresentationTheme, PresentationStrings, RenderedPeer?, Bool, PeerPresence?)?
private let peerNode: SelectablePeerNode
private var presenceManager: PeerPresenceStatusManager?
var controllerInteraction: ShareControllerInteraction?
private var placeholderNode: ShimmerEffectNode?
private var absoluteLocation: (CGRect, CGSize)?
override init() {
self.peerNode = SelectablePeerNode()
@ -143,7 +147,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
self.peerNode.toggleSelection = { [weak self] in
if let strongSelf = self {
if let (_, _, _, peer, search, _) = strongSelf.currentState {
if let (_, _, _, maybePeer, search, _) = strongSelf.currentState, let peer = maybePeer {
if let _ = peer.peers[peer.peerId] {
strongSelf.controllerInteraction?.togglePeer(peer, search)
}
@ -159,13 +163,21 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
})
}
func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, presence: PeerPresence?, search: Bool, synchronousLoad: Bool, force: Bool) {
override func updateAbsoluteRect(_ absoluteRect: CGRect, within containerSize: CGSize) {
var rect = absoluteRect
self.absoluteLocation = (rect, containerSize)
if let shimmerNode = self.placeholderNode {
shimmerNode.updateAbsoluteRect(rect, within: containerSize)
}
}
func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer?, presence: PeerPresence?, search: Bool, synchronousLoad: Bool, force: Bool) {
if force || self.currentState == nil || self.currentState!.0 !== context || self.currentState!.3 != peer || !arePeerPresencesEqual(self.currentState!.5, presence) {
let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor)
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
var online = false
if let peer = peer.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != context.account.peerId {
if let peer = peer?.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != context.account.peerId {
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: timestamp)
if case .online = relativeStatus {
online = true
@ -173,7 +185,39 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
}
self.peerNode.theme = itemTheme
self.peerNode.setup(context: context, theme: theme, strings: strings, peer: EngineRenderedPeer(peer), online: online, synchronousLoad: synchronousLoad)
if let peer = peer {
self.peerNode.setup(context: context, theme: theme, strings: strings, peer: EngineRenderedPeer(peer), online: online, synchronousLoad: synchronousLoad)
if let shimmerNode = self.placeholderNode {
self.placeholderNode = nil
shimmerNode.removeFromSupernode()
}
} else {
let shimmerNode: ShimmerEffectNode
if let current = self.placeholderNode {
shimmerNode = current
} else {
shimmerNode = ShimmerEffectNode()
self.placeholderNode = shimmerNode
self.addSubnode(shimmerNode)
}
shimmerNode.frame = self.bounds
if let (rect, size) = self.absoluteLocation {
shimmerNode.updateAbsoluteRect(rect, within: size)
}
var shapes: [ShimmerEffectNode.Shape] = []
let titleLineWidth: CGFloat = 56.0
let lineDiameter: CGFloat = 10.0
let iconFrame = CGRect(x: 13.0, y: 4.0, width: 60.0, height: 60.0)
shapes.append(.circle(iconFrame))
let titleFrame = CGRect(x: 15.0, y: 70.0, width: 56.0, height: 10.0)
shapes.append(.roundedRectLine(startPoint: CGPoint(x: titleFrame.minX, y: titleFrame.minY + floor((titleFrame.height - lineDiameter) / 2.0)), width: titleLineWidth, diameter: lineDiameter))
shimmerNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, horizontal: true, size: self.bounds.size)
}
self.currentState = (context, theme, strings, peer, search, presence)
self.setNeedsLayout()
if let presence = presence as? TelegramUserPresence {
@ -185,7 +229,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
func updateSelection(animated: Bool) {
var selected = false
if let controllerInteraction = self.controllerInteraction, let (_, _, _, peer, _, _) = self.currentState {
if let controllerInteraction = self.controllerInteraction, let (_, _, _, maybePeer, _, _) = self.currentState, let peer = maybePeer {
selected = controllerInteraction.selectedPeerIds.contains(peer.peerId)
}
@ -197,5 +241,21 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
let bounds = self.bounds
self.peerNode.frame = bounds
self.placeholderNode?.frame = bounds
if let (_, theme, _, _, _, _) = self.currentState, let shimmerNode = self.placeholderNode {
var shapes: [ShimmerEffectNode.Shape] = []
let titleLineWidth: CGFloat = 56.0
let lineDiameter: CGFloat = 10.0
let iconFrame = CGRect(x: (bounds.width - 60.0) / 2.0, y: 4.0, width: 60.0, height: 60.0)
shapes.append(.circle(iconFrame))
let titleFrame = CGRect(x: (bounds.width - titleLineWidth) / 2.0, y: 70.0, width: titleLineWidth, height: 10.0)
shapes.append(.roundedRectLine(startPoint: CGPoint(x: titleFrame.minX, y: titleFrame.minY + floor((titleFrame.height - lineDiameter) / 2.0)), width: titleLineWidth, diameter: lineDiameter))
shimmerNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, horizontal: true, size: self.bounds.size)
}
}
}

View File

@ -110,13 +110,17 @@ private enum ShareSearchRecentEntry: Comparable, Identifiable {
private struct ShareSearchPeerEntry: Comparable, Identifiable {
let index: Int32
let peer: RenderedPeer
let peer: RenderedPeer?
let presence: PeerPresence?
let theme: PresentationTheme
let strings: PresentationStrings
var stableId: Int64 {
return self.peer.peerId.toInt64()
if let peer = self.peer {
return peer.peerId.toInt64()
} else {
return Int64(index)
}
}
static func ==(lhs: ShareSearchPeerEntry, rhs: ShareSearchPeerEntry) -> Bool {
@ -134,7 +138,7 @@ private struct ShareSearchPeerEntry: Comparable, Identifiable {
}
func item(context: AccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareControllerPeerGridItem(context: context, theme: self.theme, strings: self.strings, peer: peer, presence: self.presence, controllerInteraction: interfaceInteraction, search: true)
return ShareControllerPeerGridItem(context: context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, controllerInteraction: interfaceInteraction, search: true)
}
}
@ -246,10 +250,13 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
if !query.isEmpty {
let accountPeer = context.account.postbox.loadedPeerWithId(context.account.peerId) |> take(1)
let foundLocalPeers = context.account.postbox.searchPeers(query: query.lowercased())
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer]), NoError> = .single(([], []))
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError> = .single(([], [], true))
|> then(
context.engine.peers.searchPeers(query: query)
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|> map { a, b -> ([FoundPeer], [FoundPeer], Bool) in
return (a, b, false)
}
)
return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers)
@ -278,21 +285,28 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
}
}
for foundPeer in foundRemotePeers.0 {
let peer = foundPeer.peer
if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) {
existingPeerIds.insert(peer.id)
entries.append(ShareSearchPeerEntry(index: index, peer: RenderedPeer(peer: foundPeer.peer), presence: nil, theme: theme, strings: strings))
if foundRemotePeers.2 {
for _ in 0 ..< 4 {
entries.append(ShareSearchPeerEntry(index: index, peer: nil, presence: nil, theme: theme, strings: strings))
index += 1
}
}
for foundPeer in foundRemotePeers.1 {
let peer = foundPeer.peer
if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) {
existingPeerIds.insert(peer.id)
entries.append(ShareSearchPeerEntry(index: index, peer: RenderedPeer(peer: peer), presence: nil, theme: theme, strings: strings))
index += 1
} else {
for foundPeer in foundRemotePeers.0 {
let peer = foundPeer.peer
if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) {
existingPeerIds.insert(peer.id)
entries.append(ShareSearchPeerEntry(index: index, peer: RenderedPeer(peer: foundPeer.peer), presence: nil, theme: theme, strings: strings))
index += 1
}
}
for foundPeer in foundRemotePeers.1 {
let peer = foundPeer.peer
if !existingPeerIds.contains(peer.id) && canSendMessagesToPeer(peer) {
existingPeerIds.insert(peer.id)
entries.append(ShareSearchPeerEntry(index: index, peer: RenderedPeer(peer: peer), presence: nil, theme: theme, strings: strings))
index += 1
}
}
}
@ -436,7 +450,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
var scrollToItem: GridNodeScrollToItem?
if !self.contentGridNode.isHidden, let ensurePeerVisibleOnLayout = self.ensurePeerVisibleOnLayout {
self.ensurePeerVisibleOnLayout = nil
if let index = self.entries.firstIndex(where: { $0.peer.peerId == ensurePeerVisibleOnLayout }) {
if let index = self.entries.firstIndex(where: { $0.peer?.peerId == ensurePeerVisibleOnLayout }) {
scrollToItem = GridNodeScrollToItem(index: index, position: .visible, transition: transition, directionHint: .up, adjustForSection: false)
}
}

View File

@ -24,7 +24,7 @@ public final class MediaNavigationAccessoryContainerNode: ASDisplayNode, UIGestu
self.backgroundNode = ASDisplayNode()
self.separatorNode = ASDisplayNode()
self.headerNode = MediaNavigationAccessoryHeaderNode(presentationData: self.presentationData)
self.headerNode = MediaNavigationAccessoryHeaderNode(context: context)
super.init()

View File

@ -10,6 +10,7 @@ import UniversalMediaPlayer
import AccountContext
import TelegramStringFormatting
import ManagedAnimationNode
import ContextUI
private let titleFont = Font.regular(12.0)
private let subtitleFont = Font.regular(10.0)
@ -130,6 +131,7 @@ private func generateMaskImage(color: UIColor) -> UIImage? {
public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollViewDelegate {
public static let minimizedHeight: CGFloat = 37.0
private let context: AccountContext
private var theme: PresentationTheme
private var strings: PresentationStrings
private var dateTimeFormat: PresentationDateTimeFormat
@ -148,7 +150,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
private let closeButton: HighlightableButtonNode
private let actionButton: HighlightTrackingButtonNode
private let playPauseIconNode: PlayPauseIconNode
private let rateButton: HighlightableButtonNode
private let rateButton: RateButton
private let accessibilityAreaNode: AccessibilityAreaNode
private let scrubbingNode: MediaPlayerScrubbingNode
@ -167,24 +169,31 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
public var tapAction: (() -> Void)?
public var close: (() -> Void)?
public var toggleRate: (() -> Void)?
public var setRate: ((AudioPlaybackRate) -> Void)?
public var togglePlayPause: (() -> Void)?
public var playPrevious: (() -> Void)?
public var playNext: (() -> Void)?
public var getController: (() -> ViewController?)?
public var presentInGlobalOverlay: ((ViewController) -> Void)?
public var playbackBaseRate: AudioPlaybackRate? = nil {
didSet {
guard self.playbackBaseRate != oldValue, let playbackBaseRate = self.playbackBaseRate else {
return
}
switch playbackBaseRate {
case .x0_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "0.5x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
case .x1:
self.rateButton.setImage(PresentationResourcesRootController.navigationPlayerRateInactiveIcon(self.theme), for: [])
self.rateButton.setContent(.image(optionsRateImage(rate: "1x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
self.rateButton.accessibilityLabel = self.strings.VoiceOver_Media_PlaybackRate
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRateNormal
self.rateButton.accessibilityHint = self.strings.VoiceOver_Media_PlaybackRateChange
case .x1_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.5x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
case .x2:
self.rateButton.setImage(PresentationResourcesRootController.navigationPlayerRateActiveIcon(self.theme), for: [])
self.rateButton.setContent(.image(optionsRateImage(rate: "2x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
self.rateButton.accessibilityLabel = self.strings.VoiceOver_Media_PlaybackRate
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRateFast
self.rateButton.accessibilityHint = self.strings.VoiceOver_Media_PlaybackRateChange
@ -208,7 +217,9 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
}
}
public init(presentationData: PresentationData) {
public init(context: AccountContext) {
self.context = context
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.theme = presentationData.theme
self.strings = presentationData.strings
self.dateTimeFormat = presentationData.dateTimeFormat
@ -236,7 +247,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
self.closeButton.contentEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 2.0)
self.closeButton.displaysAsynchronously = false
self.rateButton = HighlightableButtonNode()
self.rateButton = RateButton()
self.rateButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -4.0, bottom: -8.0, right: -4.0)
self.rateButton.displaysAsynchronously = false
@ -265,9 +276,6 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
self.scrollNode.addSubnode(self.previousItemNode)
self.scrollNode.addSubnode(self.nextItemNode)
//self.addSubnode(self.leftMaskNode)
//self.addSubnode(self.rightMaskNode)
self.addSubnode(self.closeButton)
self.addSubnode(self.rateButton)
self.addSubnode(self.accessibilityAreaNode)
@ -276,9 +284,13 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
self.addSubnode(self.actionButton)
self.closeButton.addTarget(self, action: #selector(self.closeButtonPressed), forControlEvents: .touchUpInside)
self.rateButton.addTarget(self, action: #selector(self.rateButtonPressed), forControlEvents: .touchUpInside)
self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: .touchUpInside)
self.rateButton.addTarget(self, action: #selector(self.rateButtonPressed), forControlEvents: .touchUpInside)
self.rateButton.contextAction = { [weak self] sourceNode, gesture in
self?.openRateMenu(sourceNode: sourceNode, gesture: gesture)
}
self.addSubnode(self.scrubbingNode)
self.addSubnode(self.separatorNode)
@ -300,13 +312,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
return
}
if let status = status {
let baseRate: AudioPlaybackRate
if status.baseRate.isEqual(to: 1.0) {
baseRate = .x1
} else {
baseRate = .x2
}
strongSelf.playbackBaseRate = baseRate
strongSelf.playbackBaseRate = AudioPlaybackRate(status.baseRate)
} else {
strongSelf.playbackBaseRate = .x1
}
@ -365,10 +371,14 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
if let playbackBaseRate = self.playbackBaseRate {
switch playbackBaseRate {
case .x0_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "0.5x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
case .x1:
self.rateButton.setImage(PresentationResourcesRootController.navigationPlayerRateInactiveIcon(self.theme), for: [])
self.rateButton.setContent(.image(optionsRateImage(rate: "1x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
case .x1_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.5x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
case .x2:
self.rateButton.setImage(PresentationResourcesRootController.navigationPlayerRateActiveIcon(self.theme), for: [])
self.rateButton.setContent(.image(optionsRateImage(rate: "2x", isLarge: false, color: self.theme.rootController.navigationBar.controlColor)))
default:
break
}
@ -475,8 +485,8 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
let bounds = CGRect(origin: CGPoint(), size: size)
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 44.0 - rightInset, y: 0.0), size: CGSize(width: 44.0, height: minHeight)))
let rateButtonSize = CGSize(width: 24.0, height: minHeight)
transition.updateFrame(node: self.rateButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 18.0 - closeButtonSize.width - 17.0 - rateButtonSize.width - rightInset, y: 0.0), size: rateButtonSize))
let rateButtonSize = CGSize(width: 30.0, height: minHeight)
transition.updateFrame(node: self.rateButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 20.0 - closeButtonSize.width - rateButtonSize.width - rightInset, y: -4.0), size: rateButtonSize))
transition.updateFrame(node: self.playPauseIconNode, frame: CGRect(origin: CGPoint(x: 6.0, y: 4.0 + UIScreenPixel), size: CGSize(width: 28.0, height: 28.0)))
transition.updateFrame(node: self.actionButton, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 40.0, height: 37.0)))
transition.updateFrame(node: self.scrubbingNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 37.0 - 2.0), size: CGSize(width: size.width, height: 2.0)))
@ -491,7 +501,48 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
}
@objc public func rateButtonPressed() {
self.toggleRate?()
self.rateButton.contextAction?(self.rateButton.containerNode, nil)
}
private func speedList(strings: PresentationStrings) -> [(String, String, AudioPlaybackRate)] {
let speedList: [(String, String, AudioPlaybackRate)] = [
("0.5x", "0.5x", .x0_5),
(strings.PlaybackSpeed_Normal, "1x", .x1),
("1.5x", "1.5x", .x1_5),
("2x", "2x", .x2)
]
return speedList
}
private func contextMenuSpeedItems() -> Signal<[ContextMenuItem], NoError> {
var items: [ContextMenuItem] = []
for (text, _, rate) in self.speedList(strings: self.strings) {
let isSelected = self.playbackBaseRate == rate
items.append(.action(ContextMenuActionItem(text: text, icon: { theme in
if isSelected {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { [weak self] _, f in
f(.default)
self?.setRate?(rate)
})))
}
return .single(items)
}
private func openRateMenu(sourceNode: ASDisplayNode, gesture: ContextGesture?) {
guard let controller = self.getController?() else {
return
}
let items: Signal<[ContextMenuItem], NoError> = self.contextMenuSpeedItems()
let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode)), items: items, reactionItems: [], gesture: gesture)
self.presentInGlobalOverlay?(contextController)
// controller.presentInGlobalOverlay(contextController)
}
@objc public func actionButtonPressed() {
@ -554,3 +605,159 @@ private final class PlayPauseIconNode: ManagedAnimationNode {
}
}
}
private func optionsRateImage(rate: String, isLarge: Bool, color: UIColor = .white) -> UIImage? {
return generateImage(isLarge ? CGSize(width: 30.0, height: 30.0) : CGSize(width: 24.0, height: 24.0), rotatedContext: { size, context in
UIGraphicsPushContext(context)
context.clear(CGRect(origin: CGPoint(), size: size))
if let image = generateTintedImage(image: UIImage(bundleImageName: isLarge ? "Chat/Context Menu/Playspeed30" : "Chat/Context Menu/Playspeed24"), color: color) {
image.draw(at: CGPoint(x: 0.0, y: 0.0))
}
let string = NSMutableAttributedString(string: rate, font: Font.with(size: 11.0, design: .round, weight: .semibold), textColor: color)
var offset = CGPoint(x: 1.0, y: 0.0)
if rate.count >= 3 {
if rate == "0.5x" {
string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string))
offset.x += -0.5
} else {
string.addAttribute(.kern, value: -0.5 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string))
offset.x += -0.3
}
} else {
offset.x += -0.3
}
if !isLarge {
offset.x *= 0.5
offset.y *= 0.5
}
let boundingRect = string.boundingRect(with: size, options: [], context: nil)
string.draw(at: CGPoint(x: offset.x + floor((size.width - boundingRect.width) / 2.0), y: offset.y + floor((size.height - boundingRect.height) / 2.0)))
UIGraphicsPopContext()
})
}
private final class RateButton: HighlightableButtonNode {
enum Content {
case image(UIImage?)
}
let referenceNode: ContextReferenceContentNode
let containerNode: ContextControllerSourceNode
private let iconNode: ASImageNode
var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
private let wide: Bool
init(wide: Bool = false) {
self.wide = wide
self.referenceNode = ContextReferenceContentNode()
self.containerNode = ContextControllerSourceNode()
self.containerNode.animateScale = false
self.iconNode = ASImageNode()
self.iconNode.displaysAsynchronously = false
self.iconNode.displayWithoutProcessing = true
self.iconNode.contentMode = .scaleToFill
super.init()
self.containerNode.addSubnode(self.referenceNode)
self.referenceNode.addSubnode(self.iconNode)
self.addSubnode(self.containerNode)
self.containerNode.shouldBegin = { [weak self] location in
guard let strongSelf = self, let _ = strongSelf.contextAction else {
return false
}
return true
}
self.containerNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self else {
return
}
strongSelf.contextAction?(strongSelf.containerNode, gesture)
}
self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 26.0, height: 44.0))
self.referenceNode.frame = self.containerNode.bounds
if let image = self.iconNode.image {
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
}
self.hitTestSlop = UIEdgeInsets(top: 0.0, left: -4.0, bottom: 0.0, right: -4.0)
}
private var content: Content?
func setContent(_ content: Content, animated: Bool = false) {
if animated {
if let snapshotView = self.referenceNode.view.snapshotContentTree() {
snapshotView.frame = self.referenceNode.frame
self.view.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
snapshotView.layer.animateScale(from: 1.0, to: 0.1, duration: 0.3, removeOnCompletion: false)
self.iconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.iconNode.layer.animateScale(from: 0.1, to: 1.0, duration: 0.3)
}
switch content {
case let .image(image):
if let image = image {
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
}
self.iconNode.image = image
self.iconNode.isHidden = false
}
} else {
self.content = content
switch content {
case let .image(image):
if let image = image {
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
}
self.iconNode.image = image
self.iconNode.isHidden = false
}
}
}
override func didLoad() {
super.didLoad()
self.view.isOpaque = false
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: wide ? 32.0 : 22.0, height: 44.0)
}
func onLayout() {
}
}
private final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController
private let sourceNode: ContextReferenceContentNode
init(controller: ViewController, sourceNode: ContextReferenceContentNode) {
self.controller = controller
self.sourceNode = sourceNode
}
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(referenceNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
}
}

View File

@ -4,17 +4,21 @@ import Display
import AsyncDisplayKit
import TelegramCore
import AccountContext
import TelegramUIPreferences
public final class MediaNavigationAccessoryPanel: ASDisplayNode {
public let containerNode: MediaNavigationAccessoryContainerNode
public var close: (() -> Void)?
public var toggleRate: (() -> Void)?
public var setRate: ((AudioPlaybackRate) -> Void)?
public var togglePlayPause: (() -> Void)?
public var tapAction: (() -> Void)?
public var playPrevious: (() -> Void)?
public var playNext: (() -> Void)?
public var getController: (() -> ViewController?)?
public var presentInGlobalOverlay: ((ViewController) -> Void)?
public init(context: AccountContext, displayBackground: Bool = false) {
self.containerNode = MediaNavigationAccessoryContainerNode(context: context, displayBackground: displayBackground)
@ -27,8 +31,8 @@ public final class MediaNavigationAccessoryPanel: ASDisplayNode {
close()
}
}
self.containerNode.headerNode.toggleRate = { [weak self] in
self?.toggleRate?()
self.containerNode.headerNode.setRate = { [weak self] rate in
self?.setRate?(rate)
}
self.containerNode.headerNode.togglePlayPause = { [weak self] in
if let strongSelf = self, let togglePlayPause = strongSelf.togglePlayPause {
@ -50,6 +54,20 @@ public final class MediaNavigationAccessoryPanel: ASDisplayNode {
playNext()
}
}
self.containerNode.headerNode.getController = { [weak self] in
if let strongSelf = self, let getController = strongSelf.getController {
return getController()
} else {
return nil
}
}
self.containerNode.headerNode.presentInGlobalOverlay = { [weak self] c in
if let strongSelf = self, let presentInGlobalOverlay = strongSelf.presentInGlobalOverlay {
presentInGlobalOverlay(c)
}
}
}
public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {

View File

@ -645,32 +645,28 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context)
mediaAccessoryPanel.containerNode.headerNode.displayScrubber = item.playbackData?.type != .instantVideo
mediaAccessoryPanel.getController = { [weak self] in
return self
}
mediaAccessoryPanel.presentInGlobalOverlay = { [weak self] c in
self?.presentInGlobalOverlay(c)
}
mediaAccessoryPanel.close = { [weak self] in
if let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
}
}
mediaAccessoryPanel.toggleRate = {
[weak self] in
mediaAccessoryPanel.setRate = { [weak self] rate in
guard let strongSelf = self else {
return
}
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings
let nextRate: AudioPlaybackRate
switch settings.voicePlaybackRate {
case .x1:
nextRate = .x2
case .x2:
nextRate = .x1
default:
nextRate = .x1
}
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in
return settings.withUpdatedVoicePlaybackRate(nextRate)
return settings.withUpdatedVoicePlaybackRate(rate)
})
return nextRate
return rate
}
|> deliverOnMainQueue).start(next: { baseRate in
guard let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType else {
@ -688,22 +684,31 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
})
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let slowdown = baseRate == .x1
strongSelf.present(
UndoOverlayController(
presentationData: presentationData,
content: .audioRate(
slowdown: slowdown,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
let slowdown: Bool?
if baseRate == .x1 {
slowdown = true
} else if baseRate == .x2 {
slowdown = false
} else {
slowdown = nil
}
if let slowdown = slowdown {
strongSelf.present(
UndoOverlayController(
presentationData: presentationData,
content: .audioRate(
slowdown: slowdown,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
),
elevatedLayout: false,
animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
elevatedLayout: false,
animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
in: .current
)
in: .current
)
}
})
}
mediaAccessoryPanel.togglePlayPause = { [weak self] in

View File

@ -4776,7 +4776,6 @@ public final class VoiceChatController: ViewController {
let speakingPeersUpdated = self.currentSpeakingPeers != speakingPeers
self.currentCallMembers = callMembers
self.currentSpeakingPeers = speakingPeers
self.currentInvitedPeers = invitedPeers
var entries: [ListEntry] = []
@ -5081,9 +5080,10 @@ public final class VoiceChatController: ViewController {
self.updateMainVideo(waitForFullSize: true, entries: fullscreenEntries, force: true)
return
}
self.updateRequestedVideoChannels()
self.currentSpeakingPeers = speakingPeers
self.peerIdToEndpointId = peerIdToEndpointId
var updateLayout = false

View File

@ -10978,7 +10978,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var attemptSelectionImpl: ((Peer) -> Void)?
let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: filter, attemptSelection: { peer in
attemptSelectionImpl?(peer)
}, multipleSelection: true))
}, multipleSelection: true, forwardedMessagesCount: messages.count))
let context = self.context
attemptSelectionImpl = { [weak controller] peer in
guard let controller = controller else {

View File

@ -1080,7 +1080,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let viaBotNode = viaBotApply()
if strongSelf.viaBotNode == nil {
strongSelf.viaBotNode = viaBotNode
strongSelf.addSubnode(viaBotNode)
strongSelf.contextSourceNode.contentNode.addSubnode(viaBotNode)
}
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 15.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 14.0)), y: 8.0), size: viaBotLayout.size)
viaBotNode.frame = viaBotFrame
@ -1161,7 +1161,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} else {
let forwardBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
strongSelf.forwardBackgroundNode = forwardBackgroundNode
strongSelf.addSubnode(forwardBackgroundNode)
strongSelf.contextSourceNode.contentNode.addSubnode(forwardBackgroundNode)
}
}
@ -1169,7 +1169,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
if strongSelf.forwardInfoNode == nil {
strongSelf.forwardInfoNode = forwardInfoNode
strongSelf.addSubnode(forwardInfoNode)
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
}
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
forwardInfoNode.frame = forwardInfoFrame

View File

@ -43,11 +43,11 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
}
private var forwardInfoNode: ChatMessageForwardInfoNode?
private var forwardBackgroundNode: ASImageNode?
private var forwardBackgroundNode: NavigationBackgroundNode?
private var viaBotNode: TextNode?
private var replyInfoNode: ChatMessageReplyInfoNode?
private var replyBackgroundNode: ASImageNode?
private var replyBackgroundNode: NavigationBackgroundNode?
private var actionButtonsNode: ChatMessageActionButtonsNode?
@ -389,7 +389,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
var viaBotApply: (TextNodeLayout, () -> TextNode)?
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?
var updatedReplyBackgroundNode: ASImageNode?
var updatedReplyBackgroundNode: NavigationBackgroundNode?
var replyBackgroundImage: UIImage?
var replyMarkup: ReplyMarkupMessageAttribute?
@ -432,6 +432,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
let botString = addAttributesToStringWithRanges(item.presentationData.strings.Conversation_MessageViaUser("@\(inlineBotNameString)")._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: botString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
ignoreForward = true
}
}
@ -464,11 +466,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
updatedReplyBackgroundNode = currentReplyBackgroundNode
} else {
updatedReplyBackgroundNode = ASImageNode()
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
}
let graphics = PresentationResourcesChat.additionalGraphics(item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
replyBackgroundImage = graphics.chatFreeformContentAdditionalInfoBackgroundImage
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
}
var updatedShareButtonNode: ChatMessageShareButton?
@ -487,7 +488,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
var forwardAuthorSignature: String?
var forwardInfoSizeApply: (CGSize, (CGFloat) -> ChatMessageForwardInfoNode)?
var updatedForwardBackgroundNode: ASImageNode?
var updatedForwardBackgroundNode: NavigationBackgroundNode?
var forwardBackgroundImage: UIImage?
if !ignoreForward, let forwardInfo = item.message.forwardInfo {
@ -517,11 +518,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
if let currentForwardBackgroundNode = currentForwardBackgroundNode {
updatedForwardBackgroundNode = currentForwardBackgroundNode
} else {
updatedForwardBackgroundNode = ASImageNode()
updatedForwardBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
}
let graphics = PresentationResourcesChat.additionalGraphics(item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
forwardBackgroundImage = graphics.chatServiceBubbleFillImage
updatedForwardBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
}
var maxContentWidth = normalDisplaySize.width
@ -613,10 +613,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
if let updatedReplyBackgroundNode = updatedReplyBackgroundNode {
if strongSelf.replyBackgroundNode == nil {
strongSelf.replyBackgroundNode = updatedReplyBackgroundNode
strongSelf.addSubnode(updatedReplyBackgroundNode)
updatedReplyBackgroundNode.image = replyBackgroundImage
} else {
strongSelf.replyBackgroundNode?.image = replyBackgroundImage
strongSelf.contextSourceNode.contentNode.addSubnode(updatedReplyBackgroundNode)
}
} else if let replyBackgroundNode = strongSelf.replyBackgroundNode {
replyBackgroundNode.removeFromSupernode()
@ -627,11 +624,13 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
let viaBotNode = viaBotApply()
if strongSelf.viaBotNode == nil {
strongSelf.viaBotNode = viaBotNode
strongSelf.addSubnode(viaBotNode)
strongSelf.contextSourceNode.contentNode.addSubnode(viaBotNode)
}
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0), size: viaBotLayout.size)
viaBotNode.frame = viaBotFrame
strongSelf.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0))
let replyBackgroundFrame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0))
strongSelf.replyBackgroundNode?.frame = replyBackgroundFrame
strongSelf.replyBackgroundNode?.update(size: replyBackgroundFrame.size, cornerRadius: 8.0, transition: .immediate)
} else if let viaBotNode = strongSelf.viaBotNode {
viaBotNode.removeFromSupernode()
strongSelf.viaBotNode = nil
@ -641,7 +640,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
let replyInfoNode = replyInfoApply()
if strongSelf.replyInfoNode == nil {
strongSelf.replyInfoNode = replyInfoNode
strongSelf.addSubnode(replyInfoNode)
strongSelf.contextSourceNode.contentNode.addSubnode(replyInfoNode)
}
var viaBotSize = CGSize()
if let viaBotNode = strongSelf.viaBotNode {
@ -654,7 +653,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
}
}
replyInfoNode.frame = replyInfoFrame
strongSelf.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0))
let replyBackgroundFrame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0))
strongSelf.replyBackgroundNode?.frame = replyBackgroundFrame
strongSelf.replyBackgroundNode?.update(size: replyBackgroundFrame.size, cornerRadius: 8.0, transition: .immediate)
} else if let replyInfoNode = strongSelf.replyInfoNode {
replyInfoNode.removeFromSupernode()
strongSelf.replyInfoNode = nil
@ -694,8 +695,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
if let updatedForwardBackgroundNode = updatedForwardBackgroundNode {
if strongSelf.forwardBackgroundNode == nil {
strongSelf.forwardBackgroundNode = updatedForwardBackgroundNode
strongSelf.addSubnode(updatedForwardBackgroundNode)
updatedForwardBackgroundNode.image = forwardBackgroundImage
strongSelf.contextSourceNode.contentNode.addSubnode(updatedForwardBackgroundNode)
}
} else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
forwardBackgroundNode.removeFromSupernode()
@ -706,7 +706,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
if strongSelf.forwardInfoNode == nil {
strongSelf.forwardInfoNode = forwardInfoNode
strongSelf.addSubnode(forwardInfoNode)
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in
guard let strongSelf = strongSelf, let item = strongSelf.item else {
return
@ -716,7 +716,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
}
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
forwardInfoNode.frame = forwardInfoFrame
strongSelf.forwardBackgroundNode?.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0))
let forwardBackgroundFrame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0))
strongSelf.forwardBackgroundNode?.frame = forwardBackgroundFrame
strongSelf.forwardBackgroundNode?.update(size: forwardBackgroundFrame.size, cornerRadius: 8.0, transition: .immediate)
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
forwardInfoNode.removeFromSupernode()
strongSelf.forwardInfoNode = nil

View File

@ -719,7 +719,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
let viaBotNode = viaBotApply()
if strongSelf.viaBotNode == nil {
strongSelf.viaBotNode = viaBotNode
strongSelf.addSubnode(viaBotNode)
strongSelf.contextSourceNode.contentNode.addSubnode(viaBotNode)
}
viaBotNode.frame = viaBotFrame
if let replyBackgroundNode = strongSelf.replyBackgroundNode {

View File

@ -11,13 +11,15 @@ private final class InstantVideoRadialStatusNodeParameters: NSObject {
let progress: CGFloat
let dimProgress: CGFloat
let playProgress: CGFloat
let blinkProgress: CGFloat
let hasSeek: Bool
init(color: UIColor, progress: CGFloat, dimProgress: CGFloat, playProgress: CGFloat, hasSeek: Bool) {
init(color: UIColor, progress: CGFloat, dimProgress: CGFloat, playProgress: CGFloat, blinkProgress: CGFloat, hasSeek: Bool) {
self.color = color
self.progress = progress
self.dimProgress = dimProgress
self.playProgress = playProgress
self.blinkProgress = blinkProgress
self.hasSeek = hasSeek
}
}
@ -64,6 +66,12 @@ final class InstantVideoRadialStatusNode: ASDisplayNode, UIGestureRecognizerDele
}
}
private var effectiveBlinkProgress: CGFloat = 0.0 {
didSet {
self.setNeedsDisplay()
}
}
private var _statusValue: MediaPlayerStatus?
private var statusValue: MediaPlayerStatus? {
get {
@ -196,8 +204,38 @@ final class InstantVideoRadialStatusNode: ASDisplayNode, UIGestureRecognizerDele
if let seekingProgress = self.seekingProgress {
if seekingProgress > 0.98 && fraction > 0.0 && fraction < 0.05 {
self.hapticFeedback.impact(.light)
let blinkAnimation = POPBasicAnimation()
blinkAnimation.property = POPAnimatableProperty.property(withName: "blinkProgress", initializer: { property in
property?.readBlock = { node, values in
values?.pointee = (node as! InstantVideoRadialStatusNode).effectiveBlinkProgress
}
property?.writeBlock = { node, values in
(node as! InstantVideoRadialStatusNode).effectiveBlinkProgress = values!.pointee
}
property?.threshold = 0.01
}) as? POPAnimatableProperty
blinkAnimation.fromValue = 1.0 as NSNumber
blinkAnimation.toValue = 0.0 as NSNumber
blinkAnimation.duration = 0.5
self.pop_add(blinkAnimation, forKey: "blinkProgress")
} else if seekingProgress > 0.0 && seekingProgress < 0.05 && fraction > 0.98 {
self.hapticFeedback.impact(.light)
let blinkAnimation = POPBasicAnimation()
blinkAnimation.property = POPAnimatableProperty.property(withName: "blinkProgress", initializer: { property in
property?.readBlock = { node, values in
values?.pointee = (node as! InstantVideoRadialStatusNode).effectiveBlinkProgress
}
property?.writeBlock = { node, values in
(node as! InstantVideoRadialStatusNode).effectiveBlinkProgress = values!.pointee
}
property?.threshold = 0.01
}) as? POPAnimatableProperty
blinkAnimation.fromValue = -1.0 as NSNumber
blinkAnimation.toValue = 0.0 as NSNumber
blinkAnimation.duration = 0.5
self.pop_add(blinkAnimation, forKey: "blinkProgress")
}
}
let newProgress = min(0.99, fraction)
@ -216,7 +254,7 @@ final class InstantVideoRadialStatusNode: ASDisplayNode, UIGestureRecognizerDele
}
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
return InstantVideoRadialStatusNodeParameters(color: self.color, progress: self.effectiveProgress, dimProgress: self.effectiveDimProgress, playProgress: self.effectivePlayProgress, hasSeek: self.hasSeek)
return InstantVideoRadialStatusNodeParameters(color: self.color, progress: self.effectiveProgress, dimProgress: self.effectiveDimProgress, playProgress: self.effectivePlayProgress, blinkProgress: self.effectiveBlinkProgress, hasSeek: self.hasSeek)
}
@objc override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
@ -231,9 +269,23 @@ final class InstantVideoRadialStatusNode: ASDisplayNode, UIGestureRecognizerDele
if let parameters = parameters as? InstantVideoRadialStatusNodeParameters {
context.setStrokeColor(parameters.color.cgColor)
context.addEllipse(in: bounds)
context.clip()
if !parameters.dimProgress.isZero {
context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.35 * min(1.0, parameters.dimProgress)).cgColor)
context.fillEllipse(in: bounds)
if parameters.playProgress == 1.0 {
context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.35 * min(1.0, parameters.dimProgress)).cgColor)
context.fillEllipse(in: bounds)
} else {
var locations: [CGFloat] = [0.0, 0.8, 1.0]
let alpha: CGFloat = 0.2 + 0.15 * parameters.playProgress
let colors: [CGColor] = [UIColor(rgb: 0x000000, alpha: alpha * min(1.0, parameters.dimProgress * parameters.playProgress)).cgColor, UIColor(rgb: 0x000000, alpha: alpha * min(1.0, parameters.dimProgress * parameters.playProgress)).cgColor, UIColor(rgb: 0x000000, alpha: alpha * min(1.0, parameters.dimProgress)).cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
let center = bounds.center
context.drawRadialGradient(gradient, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: bounds.width / 2.0, options: .drawsAfterEndLocation)
}
}
context.setBlendMode(.normal)
@ -255,9 +307,19 @@ final class InstantVideoRadialStatusNode: ASDisplayNode, UIGestureRecognizerDele
}
if !parameters.dimProgress.isZero {
context.setLineWidth(lineWidth)
if parameters.blinkProgress > 0.0 {
context.setStrokeColor(parameters.color.withAlphaComponent(0.2 * parameters.blinkProgress).cgColor)
context.strokeEllipse(in: CGRect(x: (bounds.size.width - pathDiameter) / 2.0 , y: (bounds.size.height - pathDiameter) / 2.0, width: pathDiameter, height: pathDiameter))
}
if parameters.hasSeek {
context.setStrokeColor(parameters.color.withAlphaComponent(0.2 * parameters.dimProgress).cgColor)
context.setLineWidth(lineWidth)
var progress = parameters.dimProgress
if parameters.blinkProgress < 0.0 {
progress = parameters.dimProgress + parameters.blinkProgress
}
context.setStrokeColor(parameters.color.withAlphaComponent(0.2 * progress).cgColor)
context.strokeEllipse(in: CGRect(x: (bounds.size.width - pathDiameter) / 2.0 , y: (bounds.size.height - pathDiameter) / 2.0, width: pathDiameter, height: pathDiameter))
}

View File

@ -206,32 +206,28 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context, displayBackground: true)
mediaAccessoryPanel.containerNode.headerNode.displayScrubber = item.playbackData?.type != .instantVideo
mediaAccessoryPanel.getController = { [weak self] in
return self?.parentController
}
mediaAccessoryPanel.presentInGlobalOverlay = { [weak self] c in
self?.parentController?.presentInGlobalOverlay(c)
}
mediaAccessoryPanel.close = { [weak self] in
if let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
}
}
mediaAccessoryPanel.toggleRate = {
[weak self] in
mediaAccessoryPanel.setRate = { [weak self] rate in
guard let strongSelf = self else {
return
}
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings
let nextRate: AudioPlaybackRate
switch settings.voicePlaybackRate {
case .x1:
nextRate = .x2
case .x2:
nextRate = .x1
default:
nextRate = .x1
}
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in
return settings.withUpdatedVoicePlaybackRate(nextRate)
return settings.withUpdatedVoicePlaybackRate(rate)
})
return nextRate
return rate
}
|> deliverOnMainQueue).start(next: { baseRate in
guard let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType else {
@ -250,22 +246,31 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
})
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let slowdown = baseRate == .x1
controller.present(
UndoOverlayController(
presentationData: presentationData,
content: .audioRate(
slowdown: slowdown,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
let slowdown: Bool?
if baseRate == .x1 {
slowdown = true
} else if baseRate == .x2 {
slowdown = false
} else {
slowdown = nil
}
if let slowdown = slowdown {
controller.present(
UndoOverlayController(
presentationData: presentationData,
content: .audioRate(
slowdown: slowdown,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
),
elevatedLayout: false,
animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
elevatedLayout: false,
animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
in: .current
)
in: .current
)
}
}
})
}

View File

@ -58,6 +58,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
private let hasContactSelector: Bool
private let hasGlobalSearch: Bool
private let pretendPresentedInModal: Bool
private let forwardedMessagesCount: Int
override public var _presentedInModal: Bool {
get {
@ -85,6 +86,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
self.attemptSelection = params.attemptSelection
self.createNewGroup = params.createNewGroup
self.pretendPresentedInModal = params.pretendPresentedInModal
self.forwardedMessagesCount = params.forwardedMessagesCount
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
@ -148,7 +150,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
}
override public func loadDisplayNode() {
self.displayNode = PeerSelectionControllerNode(context: self.context, filter: self.filter, hasChatListSelector: self.hasChatListSelector, hasContactSelector: self.hasContactSelector, hasGlobalSearch: self.hasGlobalSearch, createNewGroup: self.createNewGroup, present: { [weak self] c, a in
self.displayNode = PeerSelectionControllerNode(context: self.context, filter: self.filter, hasChatListSelector: self.hasChatListSelector, hasContactSelector: self.hasContactSelector, hasGlobalSearch: self.hasGlobalSearch, forwardedMessagesCount: self.forwardedMessagesCount, createNewGroup: self.createNewGroup, present: { [weak self] c, a in
self?.present(c, in: .window(.root), with: a)
}, presentInGlobalOverlay: { [weak self] c, a in
self?.presentInGlobalOverlay(c, with: a)

View File

@ -66,7 +66,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
return self.readyValue.get()
}
init(context: AccountContext, filter: ChatListNodePeersFilter, hasChatListSelector: Bool, hasContactSelector: Bool, hasGlobalSearch: Bool, createNewGroup: (() -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void) {
init(context: AccountContext, filter: ChatListNodePeersFilter, hasChatListSelector: Bool, hasContactSelector: Bool, hasGlobalSearch: Bool, forwardedMessagesCount: Int, createNewGroup: (() -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void) {
self.context = context
self.present = present
self.presentInGlobalOverlay = presentInGlobalOverlay
@ -79,6 +79,16 @@ final class PeerSelectionControllerNode: ASDisplayNode {
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(PeerId(0)), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil)
var mockMessageIds: [MessageId]?
if forwardedMessagesCount > 0 {
var messageIds: [MessageId] = []
for _ in 0 ..< forwardedMessagesCount {
messageIds.append(MessageId(peerId: PeerId(0), namespace: Namespaces.Message.Local, id: Int32.random(in: 0 ..< Int32.max)))
}
mockMessageIds = messageIds
}
self.presentationInterfaceState = self.presentationInterfaceState.updatedInterfaceState { $0.withUpdatedForwardMessageIds(mockMessageIds) }
if hasChatListSelector && hasContactSelector {
self.toolbarBackgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.navigationBar.blurredBackgroundColor)
@ -276,13 +286,6 @@ final class PeerSelectionControllerNode: ASDisplayNode {
guard let textInputNode = textInputPanelNode.textInputNode else {
return
}
// let previousSupportedOrientations = strongSelf.supportedOrientations
// if layout.size.width > layout.size.height {
// strongSelf.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .landscape)
// } else {
// strongSelf.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
// }
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, interfaceState: strongSelf.presentationInterfaceState, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, completion: { [weak self] in
if let strongSelf = self {
// strongSelf.supportedOrientations = previousSupportedOrientations
@ -292,7 +295,6 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}, schedule: { [weak textInputPanelNode] in
textInputPanelNode?.sendMessage(.schedule)
})
// strongSelf.sendMessageActionsController = controller
strongSelf.presentInGlobalOverlay(controller, nil)
}, openScheduledMessages: {
}, openPeersNearby: {