mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' into experiments/video-chat
This commit is contained in:
commit
0c046a4af6
@ -302,7 +302,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState))
|
||||
if stateAndFilterId.state.editing {
|
||||
if strongSelf.groupId == .root {
|
||||
strongSelf.navigationItem.rightBarButtonItem = nil
|
||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
||||
}
|
||||
let title = !stateAndFilterId.state.selectedPeerIds.isEmpty ? strongSelf.presentationData.strings.ChatList_SelectedChats(Int32(stateAndFilterId.state.selectedPeerIds.count)) : defaultTitle
|
||||
|
||||
@ -315,10 +315,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
strongSelf.titleView.setTitle(NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false), animated: animated)
|
||||
} else if isReorderingTabs {
|
||||
if strongSelf.groupId == .root {
|
||||
strongSelf.navigationItem.rightBarButtonItem = nil
|
||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
||||
}
|
||||
let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed))
|
||||
strongSelf.navigationItem.leftBarButtonItem = leftBarButtonItem
|
||||
strongSelf.navigationItem.setLeftBarButton(leftBarButtonItem, animated: true)
|
||||
|
||||
let (_, connectsViaProxy) = proxy
|
||||
switch networkState {
|
||||
@ -341,16 +341,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
isRoot = true
|
||||
|
||||
if isReorderingTabs {
|
||||
strongSelf.navigationItem.rightBarButtonItem = nil
|
||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
||||
} else {
|
||||
let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(strongSelf.presentationData.theme), style: .plain, target: strongSelf, action: #selector(strongSelf.composePressed))
|
||||
rightBarButtonItem.accessibilityLabel = strongSelf.presentationData.strings.VoiceOver_Navigation_Compose
|
||||
strongSelf.navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||
if strongSelf.navigationItem.rightBarButtonItem?.accessibilityLabel != rightBarButtonItem.accessibilityLabel {
|
||||
strongSelf.navigationItem.setRightBarButton(rightBarButtonItem, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
if isReorderingTabs {
|
||||
let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed))
|
||||
strongSelf.navigationItem.leftBarButtonItem = leftBarButtonItem
|
||||
leftBarButtonItem.accessibilityLabel = strongSelf.presentationData.strings.Common_Done
|
||||
if strongSelf.navigationItem.leftBarButtonItem?.accessibilityLabel != leftBarButtonItem.accessibilityLabel {
|
||||
strongSelf.navigationItem.setLeftBarButton(leftBarButtonItem, animated: true)
|
||||
}
|
||||
} else {
|
||||
let editItem: UIBarButtonItem
|
||||
if stateAndFilterId.state.editing {
|
||||
@ -360,7 +365,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
editItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(strongSelf.editPressed))
|
||||
editItem.accessibilityLabel = strongSelf.presentationData.strings.Common_Edit
|
||||
}
|
||||
strongSelf.navigationItem.leftBarButtonItem = editItem
|
||||
if strongSelf.navigationItem.leftBarButtonItem?.accessibilityLabel != editItem.accessibilityLabel {
|
||||
strongSelf.navigationItem.setLeftBarButton(editItem, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -904,6 +911,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
}
|
||||
|
||||
let previousToolbarValue = Atomic<Toolbar?>(value: nil)
|
||||
self.stateDisposable.set(combineLatest(queue: .mainQueue(),
|
||||
self.presentationDataValue.get(),
|
||||
peerIdsAndOptions
|
||||
@ -954,7 +962,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
toolbar = Toolbar(leftAction: leftAction, rightAction: ToolbarAction(title: presentationData.strings.Common_Delete, isEnabled: options.delete), middleAction: middleAction)
|
||||
}
|
||||
}
|
||||
strongSelf.setToolbar(toolbar, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
var transition: ContainedViewLayoutTransition = .immediate
|
||||
let previousToolbar = previousToolbarValue.swap(toolbar)
|
||||
if (previousToolbar == nil) != (toolbar == nil) {
|
||||
transition = .animated(duration: 0.3, curve: .easeInOut)
|
||||
}
|
||||
strongSelf.setToolbar(toolbar, transition: transition)
|
||||
}))
|
||||
|
||||
self.tabContainerNode.tabSelected = { [weak self] id in
|
||||
@ -1445,13 +1458,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
@objc private func donePressed() {
|
||||
self.reorderingDonePressed()
|
||||
|
||||
let editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||
editItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
||||
if case .root = self.groupId, self.filter == nil {
|
||||
self.navigationItem.setLeftBarButton(editItem, animated: true)
|
||||
} else {
|
||||
self.navigationItem.setRightBarButton(editItem, animated: true)
|
||||
}
|
||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring))
|
||||
self.searchContentNode?.setIsEnabled(true, animated: true)
|
||||
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
||||
|
@ -1,6 +1,8 @@
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
|
||||
private let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers])
|
||||
|
||||
private var backArrowImageCache: [Int32: UIImage] = [:]
|
||||
|
||||
class SparseNode: ASDisplayNode {
|
||||
@ -269,7 +271,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
private var title: String? {
|
||||
didSet {
|
||||
if let title = self.title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor)
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor)
|
||||
self.titleNode.accessibilityLabel = title
|
||||
if self.titleNode.supernode == nil {
|
||||
self.buttonsContainerNode.addSubnode(self.titleNode)
|
||||
@ -744,7 +746,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
|
||||
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
|
||||
if let title = self.title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor)
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor)
|
||||
self.titleNode.accessibilityLabel = title
|
||||
}
|
||||
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
|
||||
@ -820,7 +822,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
|
||||
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
|
||||
if let title = self.title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor)
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor)
|
||||
self.titleNode.accessibilityLabel = title
|
||||
}
|
||||
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
|
||||
@ -1079,7 +1081,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
}
|
||||
} else if let title = self.title {
|
||||
let node = ImmediateTextNode()
|
||||
node.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: foregroundColor)
|
||||
node.attributedText = NSAttributedString(string: title, font: titleFont, textColor: foregroundColor)
|
||||
return node
|
||||
} else {
|
||||
return nil
|
||||
|
@ -154,6 +154,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
var setPlayRate: ((Double) -> Void)?
|
||||
var fetchControl: (() -> Void)?
|
||||
|
||||
var interacting: ((Bool) -> Void)?
|
||||
|
||||
private var seekTimer: SwiftSignalKit.Timer?
|
||||
private var currentIsPaused: Bool = true
|
||||
private var seekRate: Double = 1.0
|
||||
@ -892,6 +894,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
if messages.count == 1 {
|
||||
strongSelf.commitDeleteMessages(messages, ask: true)
|
||||
} else {
|
||||
strongSelf.interacting?(true)
|
||||
|
||||
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
if !presentationData.theme.overallDarkAppearance {
|
||||
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
@ -930,8 +934,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
actionSheet.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
let items: [ActionSheetItem] = [
|
||||
ActionSheetButtonItem(title: singleText, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
@ -1012,6 +1018,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: messages.map { $0.id }, type: .forEveryone).start()
|
||||
strongSelf.controllerInteraction?.dismissController()
|
||||
} else if !items.isEmpty {
|
||||
strongSelf.interacting?(true)
|
||||
actionSheet.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
@ -1024,13 +1034,17 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
|
||||
@objc func actionButtonPressed() {
|
||||
self.interacting?(true)
|
||||
|
||||
if let currentMessage = self.currentMessage {
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> [Message] in
|
||||
return transaction.getMessageGroup(currentMessage.id) ?? []
|
||||
} |> deliverOnMainQueue).start(next: { [weak self] messages in
|
||||
if let strongSelf = self, !messages.isEmpty {
|
||||
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
var forceTheme: PresentationTheme?
|
||||
if !presentationData.theme.overallDarkAppearance {
|
||||
forceTheme = defaultDarkColorPresentationTheme
|
||||
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
}
|
||||
var generalMessageContentKind: MessageContentKind?
|
||||
@ -1109,7 +1123,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
}
|
||||
}
|
||||
let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: preferredAction, forcedTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme)
|
||||
let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: preferredAction, forceTheme: forceTheme)
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
@ -1170,7 +1187,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
|
||||
let shareAction: ([Message]) -> Void = { messages in
|
||||
if let strongSelf = self {
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), preferredAction: preferredAction, forcedTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme)
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), preferredAction: preferredAction, forceTheme: forceTheme)
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
@ -1240,7 +1260,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
})
|
||||
} else if let (webPage, media) = self.currentWebPageAndMedia {
|
||||
var presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
var forceTheme: PresentationTheme?
|
||||
if !presentationData.theme.overallDarkAppearance {
|
||||
forceTheme = defaultDarkColorPresentationTheme
|
||||
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
}
|
||||
|
||||
@ -1265,7 +1287,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
if availableOpenInOptions(context: self.context, item: item).count > 1 {
|
||||
preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Conversation_FileOpenIn, action: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let openInController = OpenInActionSheetController(context: strongSelf.context, forceTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme, item: item, additionalAction: nil, openUrl: { [weak self] url in
|
||||
let openInController = OpenInActionSheetController(context: strongSelf.context, forceTheme: forceTheme, item: item, additionalAction: nil, openUrl: { [weak self] url in
|
||||
if let strongSelf = self {
|
||||
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||
}
|
||||
@ -1290,7 +1312,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
}
|
||||
}
|
||||
let shareController = ShareController(context: self.context, subject: subject, preferredAction: preferredAction, forcedTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme)
|
||||
let shareController = ShareController(context: self.context, subject: subject, preferredAction: preferredAction, forceTheme: forceTheme)
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
|
@ -120,7 +120,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
||||
self.fetchStatusDisposable.dispose()
|
||||
}
|
||||
|
||||
var collapsed: Bool = false
|
||||
var collapsed: Bool?
|
||||
func setCollapsed(_ collapsed: Bool, animated: Bool) {
|
||||
guard self.collapsed != collapsed else {
|
||||
return
|
||||
@ -128,15 +128,14 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
||||
|
||||
self.collapsed = collapsed
|
||||
|
||||
guard let (size, _, _) = self.containerLayout else {
|
||||
return
|
||||
}
|
||||
|
||||
let alpha: CGFloat = collapsed ? 0.0 : 1.0
|
||||
self.leftTimestampNode.alpha = alpha
|
||||
self.rightTimestampNode.alpha = alpha
|
||||
self.infoNode.alpha = size.width < size.height && !self.collapsed ? 1.0 : 0.0
|
||||
self.updateScrubberVisibility(animated: animated)
|
||||
|
||||
if let (size, _, _) = self.containerLayout {
|
||||
self.infoNode.alpha = size.width < size.height && !collapsed ? 1.0 : 0.0
|
||||
}
|
||||
}
|
||||
|
||||
private func updateScrubberVisibility(animated: Bool) {
|
||||
@ -144,10 +143,10 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
||||
var alpha: CGFloat = 1.0
|
||||
if let playbackStatus = self.playbackStatus, playbackStatus.duration <= 30.0 {
|
||||
} else {
|
||||
alpha = self.collapsed ? 0.0 : 1.0
|
||||
alpha = self.collapsed == true ? 0.0 : 1.0
|
||||
collapsed = false
|
||||
}
|
||||
self.scrubberNode.setCollapsed(collapsed, animated: animated)
|
||||
self.scrubberNode.setCollapsed(collapsed == true, animated: animated)
|
||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .linear) : .immediate
|
||||
transition.updateAlpha(node: self.scrubberNode, alpha: alpha)
|
||||
}
|
||||
@ -285,7 +284,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
||||
let infoSize = self.infoNode.measure(infoConstrainedSize)
|
||||
self.infoNode.bounds = CGRect(origin: CGPoint(), size: infoSize)
|
||||
transition.updatePosition(node: self.infoNode, position: CGPoint(x: size.width / 2.0, y: infoOffset + infoSize.height / 2.0))
|
||||
self.infoNode.alpha = size.width < size.height && !self.collapsed ? 1.0 : 0.0
|
||||
self.infoNode.alpha = size.width < size.height && self.collapsed == false ? 1.0 : 0.0
|
||||
|
||||
self.scrubberNode.frame = CGRect(origin: CGPoint(x: scrubberInset, y: 6.0), size: CGSize(width: size.width - leftInset - rightInset - scrubberInset * 2.0, height: scrubberHeight))
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import Display
|
||||
public final class GalleryFooterNode: ASDisplayNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
|
||||
private var currentThumbnailPanelHeight: CGFloat?
|
||||
private var currentFooterContentNode: GalleryFooterContentNode?
|
||||
private var currentOverlayContentNode: GalleryOverlayContentNode?
|
||||
private var currentLayout: (ContainerViewLayout, CGFloat, Bool)?
|
||||
@ -36,11 +37,16 @@ public final class GalleryFooterNode: ASDisplayNode {
|
||||
let cleanInsets = layout.insets(options: [])
|
||||
|
||||
var dismissedCurrentFooterContentNode: GalleryFooterContentNode?
|
||||
var dismissedThumbnailPanelHeight: CGFloat?
|
||||
if self.currentFooterContentNode !== footerContentNode {
|
||||
if let currentFooterContentNode = self.currentFooterContentNode {
|
||||
currentFooterContentNode.requestLayout = nil
|
||||
dismissedCurrentFooterContentNode = currentFooterContentNode
|
||||
}
|
||||
if let currentThumbnailPanelHeight = self.currentThumbnailPanelHeight {
|
||||
dismissedThumbnailPanelHeight = currentThumbnailPanelHeight
|
||||
}
|
||||
self.currentThumbnailPanelHeight = thumbnailPanelHeight
|
||||
self.currentFooterContentNode = footerContentNode
|
||||
if let footerContentNode = footerContentNode {
|
||||
footerContentNode.setVisibilityAlpha(self.visibilityAlpha, animated: transition.isAnimated)
|
||||
@ -68,10 +74,11 @@ public final class GalleryFooterNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
let effectiveThumbnailPanelHeight = self.currentThumbnailPanelHeight ?? thumbnailPanelHeight
|
||||
var backgroundHeight: CGFloat = 0.0
|
||||
let verticalOffset: CGFloat = isHidden ? (layout.size.width > layout.size.height ? 44.0 : (thumbnailPanelHeight > 0.0 ? 106.0 : 54.0)) : 0.0
|
||||
let verticalOffset: CGFloat = isHidden ? (layout.size.width > layout.size.height ? 44.0 : (effectiveThumbnailPanelHeight > 0.0 ? 106.0 : 54.0)) : 0.0
|
||||
if let footerContentNode = self.currentFooterContentNode {
|
||||
backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: thumbnailPanelHeight, transition: transition)
|
||||
backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: effectiveThumbnailPanelHeight, transition: transition)
|
||||
transition.updateFrame(node: footerContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundHeight)))
|
||||
if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode {
|
||||
let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||
|
@ -205,7 +205,9 @@ private final class UniversalVideoGalleryItemOverlayNode: GalleryOverlayContentN
|
||||
}
|
||||
|
||||
override func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateAlpha(node: self.wrapperNode, alpha: 1.0)
|
||||
if !self.visibilityAlpha.isZero {
|
||||
transition.updateAlpha(node: self.wrapperNode, alpha: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
override func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
||||
@ -271,12 +273,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private let statusNode: RadialStatusNode
|
||||
private var statusNodeShouldBeHidden = true
|
||||
|
||||
private var isCentral = false
|
||||
private var isCentral: Bool?
|
||||
private var _isVisible: Bool?
|
||||
private var initiallyActivated = false
|
||||
private var hideStatusNodeUntilCentrality = false
|
||||
private var playOnContentOwnership = false
|
||||
private var skipInitialPause = false
|
||||
private var ignorePauseStatus = false
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
private var didPause = false
|
||||
private var isPaused = true
|
||||
@ -299,6 +302,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private var scrubbingFrames = false
|
||||
private var scrubbingFrameDisposable: Disposable?
|
||||
|
||||
private let isPlayingPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
private let isInteractingPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
private let controlsVisiblePromise = ValuePromise<Bool>(true, ignoreRepeated: true)
|
||||
private var hideControlsDisposable: Disposable?
|
||||
|
||||
var playbackCompleted: (() -> Void)?
|
||||
|
||||
private var customUnembedWhenPortrait: ((OverlayMediaItemNode) -> Bool)?
|
||||
@ -323,6 +331,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.footerContentNode.interacting = { [weak self] value in
|
||||
self?.isInteractingPromise.set(value)
|
||||
}
|
||||
|
||||
self.overlayContentNode.action = { [weak self] toLandscape in
|
||||
self?.updateControlsVisibility(!toLandscape)
|
||||
context.sharedContext.applicationBindings.forceOrientation(toLandscape ? .landscapeRight : .portrait)
|
||||
@ -436,12 +448,30 @@ 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())
|
||||
|> mapToSignal { isPlaying, isIntracting, controlsVisible -> Signal<Void, NoError> in
|
||||
if isPlaying && !isIntracting && controlsVisible {
|
||||
return .single(Void())
|
||||
|> delay(4.0, queue: Queue.mainQueue())
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
self.hideControlsDisposable = (shouldHideControlsSignal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateControlsVisibility(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.statusDisposable.dispose()
|
||||
self.mediaPlaybackStateDisposable.dispose()
|
||||
self.scrubbingFrameDisposable?.dispose()
|
||||
self.hideControlsDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func ready() -> Signal<Void, NoError> {
|
||||
@ -484,21 +514,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
private var controlsTimer: SwiftSignalKit.Timer?
|
||||
private var previousPlaying: Bool?
|
||||
|
||||
private func setupControlsTimer() {
|
||||
let timer = SwiftSignalKit.Timer(timeout: 3.0, repeat: false, completion: { [weak self] in
|
||||
self?.updateControlsVisibility(false)
|
||||
self?.controlsTimer = nil
|
||||
}, queue: Queue.mainQueue())
|
||||
timer.start()
|
||||
self.controlsTimer = timer
|
||||
}
|
||||
|
||||
func setupItem(_ item: UniversalVideoGalleryItem) {
|
||||
if self.item?.content.id != item.content.id {
|
||||
self.previousPlaying = nil
|
||||
self.isPlayingPromise.set(false)
|
||||
|
||||
if item.hideControls {
|
||||
self.statusButtonNode.isHidden = true
|
||||
@ -665,7 +683,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value, fetchStatus in
|
||||
if let strongSelf = self {
|
||||
var initialBuffering = false
|
||||
var playing = false
|
||||
var isPlaying = false
|
||||
var isPaused = true
|
||||
var seekable = hintSeekable
|
||||
var hasStarted = false
|
||||
@ -683,7 +701,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
switch value.status {
|
||||
case .playing:
|
||||
isPaused = false
|
||||
playing = true
|
||||
isPlaying = true
|
||||
strongSelf.ignorePauseStatus = false
|
||||
case let .buffering(_, whilePlaying, _, display):
|
||||
displayProgress = display
|
||||
initialBuffering = !whilePlaying
|
||||
@ -716,9 +735,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
isPaused = false
|
||||
}
|
||||
} else if strongSelf.actionAtEnd == .stop {
|
||||
strongSelf.updateControlsVisibility(true)
|
||||
strongSelf.controlsTimer?.invalidate()
|
||||
strongSelf.controlsTimer = nil
|
||||
strongSelf.isPlayingPromise.set(false)
|
||||
if strongSelf.isCentral == true {
|
||||
strongSelf.updateControlsVisibility(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !value.duration.isZero {
|
||||
@ -726,14 +746,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
if strongSelf.isCentral && playing && strongSelf.previousPlaying != true && !disablePlayerControls {
|
||||
strongSelf.controlsTimer?.invalidate()
|
||||
strongSelf.setupControlsTimer()
|
||||
} else if !playing {
|
||||
strongSelf.controlsTimer?.invalidate()
|
||||
strongSelf.controlsTimer = nil
|
||||
if !disablePlayerControls && strongSelf.isCentral == true && isPlaying {
|
||||
strongSelf.isPlayingPromise.set(true)
|
||||
} else if !isPlaying {
|
||||
strongSelf.isPlayingPromise.set(false)
|
||||
}
|
||||
strongSelf.previousPlaying = playing
|
||||
|
||||
var fetching = false
|
||||
if initialBuffering {
|
||||
@ -751,7 +768,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
case .Remote:
|
||||
state = .download(.white)
|
||||
case let .Fetching(_, progress):
|
||||
if !playing {
|
||||
if !isPlaying {
|
||||
fetching = true
|
||||
isPaused = true
|
||||
}
|
||||
@ -768,13 +785,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
strongSelf.fetchStatus = fetchStatus
|
||||
|
||||
if !item.hideControls {
|
||||
strongSelf.statusNodeShouldBeHidden = (!initialBuffering && (strongSelf.didPause || !isPaused) && !fetching)
|
||||
strongSelf.statusNodeShouldBeHidden = strongSelf.ignorePauseStatus || (!initialBuffering && (strongSelf.didPause || !isPaused) && !fetching)
|
||||
strongSelf.statusButtonNode.isHidden = strongSelf.hideStatusNodeUntilCentrality || strongSelf.statusNodeShouldBeHidden
|
||||
}
|
||||
|
||||
if isAnimated || disablePlayerControls {
|
||||
strongSelf.footerContentNode.content = .info
|
||||
} else if isPaused {
|
||||
} else if isPaused && !strongSelf.ignorePauseStatus {
|
||||
if hasStarted || strongSelf.didPause {
|
||||
strongSelf.footerContentNode.content = .playback(paused: true, seekable: seekable)
|
||||
} else if let fetchStatus = fetchStatus, !strongSelf.requiresDownload {
|
||||
@ -808,10 +825,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
if let strongSelf = self, !isAnimated {
|
||||
videoNode?.seek(0.0)
|
||||
|
||||
if strongSelf.actionAtEnd == .stop && strongSelf.isCentral {
|
||||
if strongSelf.actionAtEnd == .stop && strongSelf.isCentral == true {
|
||||
strongSelf.isPlayingPromise.set(false)
|
||||
strongSelf.updateControlsVisibility(true)
|
||||
strongSelf.controlsTimer?.invalidate()
|
||||
strongSelf.controlsTimer = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -834,8 +850,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
|
||||
override func controlsVisibilityUpdated(isVisible: Bool) {
|
||||
self.controlsTimer?.invalidate()
|
||||
self.controlsTimer = nil
|
||||
self.controlsVisiblePromise.set(isVisible)
|
||||
|
||||
self.videoNode?.isUserInteractionEnabled = isVisible ? self.videoNodeUserInteractionEnabled : false
|
||||
self.videoNode?.notifyPlaybackControlsHidden(!isVisible)
|
||||
@ -915,8 +930,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.controlsTimer?.invalidate()
|
||||
self.controlsTimer = nil
|
||||
self.isPlayingPromise.set(false)
|
||||
|
||||
self.dismissOnOrientationChange = false
|
||||
if videoNode.ownsContentNode {
|
||||
@ -941,6 +955,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
if self.skipInitialPause {
|
||||
self.skipInitialPause = false
|
||||
} else {
|
||||
self.ignorePauseStatus = true
|
||||
videoNode.pause()
|
||||
videoNode.seek(0.0)
|
||||
}
|
||||
@ -973,7 +988,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
|
||||
override func activateAsInitial() {
|
||||
if let videoNode = self.videoNode, self.isCentral {
|
||||
if let videoNode = self.videoNode, self.isCentral == true {
|
||||
self.initiallyActivated = true
|
||||
|
||||
var isAnimated = false
|
||||
@ -1614,6 +1629,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
self.isInteractingPromise.set(true)
|
||||
|
||||
let signal = stickerPacksAttachedToMedia(account: self.context.account, media: media)
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
@ -1627,7 +1644,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
let baseNavigationController = strongSelf.baseNavigationController()
|
||||
baseNavigationController?.view.endEditing(true)
|
||||
let controller = StickerPackScreen(context: strongSelf.context, mainStickerPack: packs[0], stickerPacks: packs, sendSticker: nil)
|
||||
let controller = StickerPackScreen(context: strongSelf.context, mainStickerPack: packs[0], stickerPacks: packs, sendSticker: nil, dismissed: { [weak self] in
|
||||
self?.isInteractingPromise.set(false)
|
||||
})
|
||||
(baseNavigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root), with: nil)
|
||||
})
|
||||
}
|
||||
|
@ -575,6 +575,13 @@ public final class ListMessageFileItemNode: ListMessageNode {
|
||||
|
||||
if statusUpdated {
|
||||
updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult)
|
||||
|> mapToSignal { value -> Signal<FileMediaResourceStatus, NoError> in
|
||||
if case .Fetching = value.fetchStatus {
|
||||
return .single(value) |> delay(0.25, queue: Queue.concurrentDefaultQueue())
|
||||
} else {
|
||||
return .single(value)
|
||||
}
|
||||
}
|
||||
|
||||
if isAudio || isInstantVideo {
|
||||
if let currentUpdatedStatusSignal = updatedStatusSignal {
|
||||
|
@ -231,6 +231,9 @@ public final class SearchDisplayController {
|
||||
self.searchBar.activate()
|
||||
if let placeholder = placeholder {
|
||||
self.searchBar.animateIn(from: placeholder, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
if self.contentNode.hasDim {
|
||||
self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
}
|
||||
} else {
|
||||
self.searchBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
@ -255,17 +258,6 @@ public final class SearchDisplayController {
|
||||
let backgroundNode = self.backgroundNode
|
||||
let contentNode = self.contentNode
|
||||
if animated {
|
||||
if let placeholder = placeholder, let (layout, navigationBarHeight) = self.containerLayout {
|
||||
let contentNodePosition = self.backgroundNode.layer.position
|
||||
let targetTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil)
|
||||
|
||||
var contentNavigationBarHeight = navigationBarHeight
|
||||
if layout.statusBarHeight == nil {
|
||||
contentNavigationBarHeight += 28.0
|
||||
}
|
||||
|
||||
self.backgroundNode.layer.animatePosition(from: contentNodePosition, to: CGPoint(x: contentNodePosition.x, y: contentNodePosition.y + (targetTextBackgroundFrame.maxY + 8.0 - contentNavigationBarHeight)), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
}
|
||||
backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak backgroundNode] _ in
|
||||
backgroundNode?.removeFromSupernode()
|
||||
})
|
||||
|
@ -93,7 +93,11 @@ final class ThemeGridSearchColorsNode: ASDisplayNode {
|
||||
return CGSize(width: constrainedSize.width, height: 100.0)
|
||||
}
|
||||
|
||||
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
let hadLayout = self.validLayout != nil
|
||||
self.validLayout = (size, leftInset, rightInset)
|
||||
|
||||
self.sectionHeaderNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 29.0))
|
||||
self.sectionHeaderNode.updateLayout(size: CGSize(width: size.width, height: 29.0), leftInset: leftInset, rightInset: rightInset)
|
||||
|
||||
@ -103,6 +107,9 @@ final class ThemeGridSearchColorsNode: ASDisplayNode {
|
||||
|
||||
self.scrollNode.frame = CGRect(x: 0.0, y: 29.0, width: size.width, height: size.height - 29.0)
|
||||
self.scrollNode.view.contentInset = insets
|
||||
if !hadLayout {
|
||||
self.scrollNode.view.contentOffset = CGPoint(x: -leftInset, y: 0.0)
|
||||
}
|
||||
|
||||
var offset: CGFloat = inset
|
||||
if let subnodes = self.scrollNode.subnodes {
|
||||
|
@ -299,7 +299,7 @@ public final class ShareController: ViewController {
|
||||
private var currentAccount: Account
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
private let forcedTheme: PresentationTheme?
|
||||
private let forceTheme: PresentationTheme?
|
||||
|
||||
private let externalShare: Bool
|
||||
private let immediateExternalShare: Bool
|
||||
@ -327,11 +327,11 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forcedTheme: forcedTheme, forcedActionTitle: forcedActionTitle)
|
||||
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forceTheme: forceTheme, forcedActionTitle: forcedActionTitle)
|
||||
}
|
||||
|
||||
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.sharedContext = sharedContext
|
||||
self.currentContext = currentContext
|
||||
self.currentAccount = currentContext.account
|
||||
@ -343,11 +343,11 @@ public final class ShareController: ViewController {
|
||||
self.immediatePeerId = immediatePeerId
|
||||
self.fromForeignApp = fromForeignApp
|
||||
self.segmentedValues = segmentedValues
|
||||
self.forcedTheme = forcedTheme
|
||||
self.forceTheme = forceTheme
|
||||
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
if let forcedTheme = self.forcedTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forcedTheme)
|
||||
if let forceTheme = self.forceTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
@ -487,17 +487,17 @@ public final class ShareController: ViewController {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, fromForeignApp: self.fromForeignApp, forcedTheme: self.forcedTheme, segmentedValues: self.segmentedValues)
|
||||
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, fromForeignApp: self.fromForeignApp, forceTheme: self.forceTheme, segmentedValues: self.segmentedValues)
|
||||
self.controllerNode.completed = self.completed
|
||||
self.controllerNode.dismiss = { [weak self] shared in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
self?.dismissed?(shared)
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
self.controllerNode.cancel = { [weak self] in
|
||||
self?.controllerNode.view.endEditing(true)
|
||||
self?.controllerNode.animateOut(shared: false, completion: {
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
self?.dismissed?(false)
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
})
|
||||
}
|
||||
self.controllerNode.share = { [weak self] text, peerIds in
|
||||
|
@ -25,7 +25,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
private let sharedContext: SharedAccountContext
|
||||
private var context: AccountContext?
|
||||
private var presentationData: PresentationData
|
||||
private let forcedTheme: PresentationTheme?
|
||||
private let forceTheme: PresentationTheme?
|
||||
private let externalShare: Bool
|
||||
private let immediateExternalShare: Bool
|
||||
private var immediatePeerId: PeerId?
|
||||
@ -80,10 +80,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
private let presetText: String?
|
||||
|
||||
init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forcedTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forceTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
self.sharedContext = sharedContext
|
||||
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
self.forcedTheme = forcedTheme
|
||||
self.forceTheme = forceTheme
|
||||
self.externalShare = externalShare
|
||||
self.immediateExternalShare = immediateExternalShare
|
||||
self.immediatePeerId = immediatePeerId
|
||||
@ -96,8 +96,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.defaultAction = defaultAction
|
||||
self.requestLayout = requestLayout
|
||||
|
||||
if let forcedTheme = self.forcedTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forcedTheme)
|
||||
if let forceTheme = self.forceTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
|
||||
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
@ -272,8 +272,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
self.presentationData = presentationData
|
||||
if let forcedTheme = self.forcedTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forcedTheme)
|
||||
if let forceTheme = self.forceTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
|
||||
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
|
@ -25,7 +25,9 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
||||
}
|
||||
|
||||
private var animatedIn = false
|
||||
private var dismissed = false
|
||||
private var isDismissed = false
|
||||
|
||||
public var dismissed: (() -> Void)?
|
||||
|
||||
private let context: AccountContext
|
||||
private let mode: StickerPackPreviewControllerMode
|
||||
@ -150,6 +152,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
||||
}))
|
||||
}, actionPerformed: self.actionPerformed)
|
||||
self.controllerNode.dismiss = { [weak self] in
|
||||
self?.dismissed?()
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
self.controllerNode.cancel = { [weak self] in
|
||||
@ -264,8 +267,8 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
||||
}
|
||||
|
||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||
if !self.dismissed {
|
||||
self.dismissed = true
|
||||
if !self.isDismissed {
|
||||
self.isDismissed = true
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
@ -988,6 +988,8 @@ public final class StickerPackScreenImpl: ViewController {
|
||||
return self.displayNode as! StickerPackScreenNode
|
||||
}
|
||||
|
||||
public var dismissed: (() -> Void)?
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override public var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
@ -1020,6 +1022,7 @@ public final class StickerPackScreenImpl: ViewController {
|
||||
strongSelf.updateModalStyleOverlayTransitionFactor(value, transition: transition)
|
||||
}
|
||||
}, dismissed: { [weak self] in
|
||||
self?.dismissed?()
|
||||
self?.dismiss()
|
||||
}, presentInGlobalOverlay: { [weak self] c, a in
|
||||
self?.presentInGlobalOverlay(c, with: a)
|
||||
@ -1060,10 +1063,11 @@ public enum StickerPackScreenPerformedAction {
|
||||
case remove(positionInList: Int)
|
||||
}
|
||||
|
||||
public func StickerPackScreen(context: AccountContext, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil) -> ViewController {
|
||||
public func StickerPackScreen(context: AccountContext, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil, dismissed: (() -> Void)? = nil) -> ViewController {
|
||||
//return StickerPackScreenImpl(context: context, stickerPacks: stickerPacks, selectedStickerPackIndex: stickerPacks.firstIndex(of: mainStickerPack) ?? 0, parentNavigationController: parentNavigationController, sendSticker: sendSticker)
|
||||
|
||||
let controller = StickerPackPreviewController(context: context, stickerPack: mainStickerPack, mode: mode, parentNavigationController: parentNavigationController, actionPerformed: actionPerformed)
|
||||
controller.dismissed = dismissed
|
||||
controller.sendSticker = sendSticker
|
||||
return controller
|
||||
}
|
||||
|
@ -565,7 +565,12 @@ public final class VoiceChatController: ViewController {
|
||||
var text: VoiceChatParticipantItem.ParticipantText
|
||||
var expandedText: VoiceChatParticipantItem.ParticipantText?
|
||||
let icon: VoiceChatParticipantItem.Icon
|
||||
switch peerEntry.state {
|
||||
|
||||
var state = peerEntry.state
|
||||
if let muteState = peerEntry.muteState, case .speaking = state, muteState.mutedByYou || !muteState.canUnmute {
|
||||
state = .listening
|
||||
}
|
||||
switch state {
|
||||
case .listening:
|
||||
if let muteState = peerEntry.muteState, muteState.mutedByYou {
|
||||
text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive)
|
||||
@ -1266,7 +1271,7 @@ public final class VoiceChatController: ViewController {
|
||||
openIcon = UIImage(bundleImageName: "Chat/Context Menu/Channels")
|
||||
} else {
|
||||
openTitle = strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile
|
||||
openIcon = UIImage(bundleImageName: "Chat/Context Menu/Info")
|
||||
openIcon = UIImage(bundleImageName: "Chat/Context Menu/User")
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: openTitle, icon: { theme in
|
||||
return generateTintedImage(image: openIcon, color: theme.actionSheet.primaryTextColor)
|
||||
@ -2234,7 +2239,7 @@ public final class VoiceChatController: ViewController {
|
||||
return formatSendTitle(presentationData.strings.VoiceChat_InviteLink_InviteListeners(Int32(count)))
|
||||
})]
|
||||
}
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forcedTheme: strongSelf.darkTheme, forcedActionTitle: presentationData.strings.VoiceChat_CopyInviteLink)
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forceTheme: strongSelf.darkTheme, forcedActionTitle: presentationData.strings.VoiceChat_CopyInviteLink)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
|
@ -179,6 +179,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
private var peerPresenceManager: PeerPresenceStatusManager?
|
||||
private var layoutParams: (VoiceChatParticipantItem, ListViewItemLayoutParams, Bool, Bool)?
|
||||
private var isExtracted = false
|
||||
private var wavesColor: UIColor?
|
||||
|
||||
private var videoNode: GroupVideoNode?
|
||||
@ -279,6 +280,8 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.isExtracted = isExtracted
|
||||
|
||||
if isExtracted {
|
||||
strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: item.presentationData.theme.list.itemBlocksBackgroundColor)
|
||||
}
|
||||
@ -521,7 +524,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.extractedRect = extractedRect
|
||||
strongSelf.nonExtractedRect = nonExtractedRect
|
||||
|
||||
if strongSelf.contextSourceNode.isExtractedToContextPreview {
|
||||
if strongSelf.isExtracted {
|
||||
strongSelf.extractedBackgroundImageNode.frame = extractedRect
|
||||
} else {
|
||||
strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect
|
||||
|
@ -797,6 +797,12 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
public static func compare(lhs: Participant, rhs: Participant, sortAscending: Bool) -> Bool {
|
||||
let lhsCanUnmute = lhs.muteState?.canUnmute ?? true
|
||||
let rhsCanUnmute = rhs.muteState?.canUnmute ?? true
|
||||
if lhsCanUnmute != rhsCanUnmute {
|
||||
return lhsCanUnmute
|
||||
}
|
||||
|
||||
if let lhsActivityRank = lhs.activityRank, let rhsActivityRank = rhs.activityRank {
|
||||
if lhsActivityRank != rhsActivityRank {
|
||||
return lhsActivityRank < rhsActivityRank
|
||||
@ -1440,6 +1446,11 @@ public final class GroupCallParticipantsContext {
|
||||
activityTimestamp = participantUpdate.activityTimestamp ?? previousActivityTimestamp
|
||||
}
|
||||
|
||||
if let muteState = participantUpdate.muteState, !muteState.canUnmute {
|
||||
previousActivityRank = nil
|
||||
activityTimestamp = nil
|
||||
}
|
||||
|
||||
var volume = participantUpdate.volume
|
||||
var muteState = participantUpdate.muteState
|
||||
if participantUpdate.isMin {
|
||||
|
@ -30,7 +30,9 @@ func updateAppConfigurationOnce(postbox: Postbox, network: Network) -> Signal<Vo
|
||||
|
||||
func managedAppConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = Signal<Void, NoError> { subscriber in
|
||||
return updateAppConfigurationOnce(postbox: postbox, network: network).start()
|
||||
return updateAppConfigurationOnce(postbox: postbox, network: network).start(completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||
}
|
||||
|
@ -14,7 +14,9 @@ func managedAutodownloadSettingsUpdates(accountManager: AccountManager, network:
|
||||
return updateAutodownloadSettingsInteractively(accountManager: accountManager, { _ -> AutodownloadSettings in
|
||||
return AutodownloadSettings(apiAutodownloadSettings: result)
|
||||
})
|
||||
}).start()
|
||||
}).start(completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||
}
|
||||
|
@ -90,7 +90,9 @@ func managedConfigurationUpdates(accountManager: AccountManager, postbox: Postbo
|
||||
}
|
||||
}
|
||||
|> switchToLatest
|
||||
}).start()
|
||||
}).start(completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
|
||||
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||
|
@ -19,7 +19,9 @@ func managedVoipConfigurationUpdates(postbox: Postbox, network: Network) -> Sign
|
||||
})
|
||||
}
|
||||
}
|
||||
}).start()
|
||||
}).start(completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||
}
|
||||
|
@ -763,6 +763,7 @@ final class AuthorizedApplicationContext {
|
||||
self.rootController.setForceInCallStatusBar((self.context.sharedContext as! SharedAccountContextImpl).currentCallStatusBarNode)
|
||||
if let groupCallController = self.context.sharedContext.currentGroupCallController as? VoiceChatController {
|
||||
if let overlayController = groupCallController.currentOverlayController {
|
||||
groupCallController.parentNavigationController = self.rootController
|
||||
self.rootController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false)
|
||||
}
|
||||
}
|
||||
|
@ -1364,6 +1364,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
case .replyThread:
|
||||
postAsReply = true
|
||||
}
|
||||
|
||||
if let messageId = messageId, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
|
||||
if let author = message.author as? TelegramUser, author.botInfo != nil {
|
||||
} else {
|
||||
postAsReply = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
@ -2423,7 +2430,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
var items: [ContextMenuItem] = [
|
||||
.action(ContextMenuActionItem(text: isChannel ? strongSelf.presentationData.strings.Conversation_ContextMenuOpenChannelProfile : strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
self?.openPeer(peerId: peer.id, navigation: .info, fromMessage: nil)
|
||||
@ -7254,19 +7261,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in
|
||||
self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion)
|
||||
})
|
||||
}
|
||||
|
||||
override public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) {
|
||||
guard let layout = self.validLayout, case .compact = layout.metrics.widthClass else {
|
||||
return
|
||||
}
|
||||
let hasOverlayNodes = self.context.sharedContext.mediaManager.overlayMediaManager.controller?.hasNodes ?? false
|
||||
if self.validLayout != nil && orientation.isLandscape && !hasOverlayNodes && self.traceVisibility() && isTopmostChatController(self) {
|
||||
var completed = false
|
||||
self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
|
||||
if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled {
|
||||
let _ = self.controllerInteraction?.openMessage(message, .landscape)
|
||||
completed = true
|
||||
|
||||
if case .compact = layout.metrics.widthClass {
|
||||
let hasOverlayNodes = self.context.sharedContext.mediaManager.overlayMediaManager.controller?.hasNodes ?? false
|
||||
if self.validLayout != nil && layout.size.width > layout.size.height && !hasOverlayNodes && self.traceVisibility() && isTopmostChatController(self) {
|
||||
var completed = false
|
||||
self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
|
||||
if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled {
|
||||
let _ = self.controllerInteraction?.openMessage(message, .landscape)
|
||||
completed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user