mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '472699a7afb885fd9026772cad0968628c8f71c8'
This commit is contained in:
commit
088fdc247a
@ -302,7 +302,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState))
|
let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState))
|
||||||
if stateAndFilterId.state.editing {
|
if stateAndFilterId.state.editing {
|
||||||
if strongSelf.groupId == .root {
|
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
|
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)
|
strongSelf.titleView.setTitle(NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false), animated: animated)
|
||||||
} else if isReorderingTabs {
|
} else if isReorderingTabs {
|
||||||
if strongSelf.groupId == .root {
|
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))
|
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
|
let (_, connectsViaProxy) = proxy
|
||||||
switch networkState {
|
switch networkState {
|
||||||
@ -341,16 +341,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
isRoot = true
|
isRoot = true
|
||||||
|
|
||||||
if isReorderingTabs {
|
if isReorderingTabs {
|
||||||
strongSelf.navigationItem.rightBarButtonItem = nil
|
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
||||||
} else {
|
} else {
|
||||||
let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(strongSelf.presentationData.theme), style: .plain, target: strongSelf, action: #selector(strongSelf.composePressed))
|
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
|
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 {
|
if isReorderingTabs {
|
||||||
let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed))
|
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 {
|
} else {
|
||||||
let editItem: UIBarButtonItem
|
let editItem: UIBarButtonItem
|
||||||
if stateAndFilterId.state.editing {
|
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 = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(strongSelf.editPressed))
|
||||||
editItem.accessibilityLabel = strongSelf.presentationData.strings.Common_Edit
|
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.stateDisposable.set(combineLatest(queue: .mainQueue(),
|
||||||
self.presentationDataValue.get(),
|
self.presentationDataValue.get(),
|
||||||
peerIdsAndOptions
|
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)
|
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
|
self.tabContainerNode.tabSelected = { [weak self] id in
|
||||||
@ -1445,13 +1458,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
@objc private func donePressed() {
|
@objc private func donePressed() {
|
||||||
self.reorderingDonePressed()
|
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.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
self.searchContentNode?.setIsEnabled(true, animated: true)
|
self.searchContentNode?.setIsEnabled(true, animated: true)
|
||||||
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
|
||||||
|
private let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers])
|
||||||
|
|
||||||
private var backArrowImageCache: [Int32: UIImage] = [:]
|
private var backArrowImageCache: [Int32: UIImage] = [:]
|
||||||
|
|
||||||
class SparseNode: ASDisplayNode {
|
class SparseNode: ASDisplayNode {
|
||||||
@ -269,7 +271,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
private var title: String? {
|
private var title: String? {
|
||||||
didSet {
|
didSet {
|
||||||
if let title = self.title {
|
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.titleNode.accessibilityLabel = title
|
||||||
if self.titleNode.supernode == nil {
|
if self.titleNode.supernode == nil {
|
||||||
self.buttonsContainerNode.addSubnode(self.titleNode)
|
self.buttonsContainerNode.addSubnode(self.titleNode)
|
||||||
@ -744,7 +746,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
|
self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
|
||||||
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
|
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
|
||||||
if let title = self.title {
|
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.titleNode.accessibilityLabel = title
|
||||||
}
|
}
|
||||||
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
|
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.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
|
||||||
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
|
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
|
||||||
if let title = self.title {
|
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.titleNode.accessibilityLabel = title
|
||||||
}
|
}
|
||||||
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
|
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
|
||||||
@ -1079,7 +1081,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
} else if let title = self.title {
|
} else if let title = self.title {
|
||||||
let node = ImmediateTextNode()
|
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
|
return node
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -154,6 +154,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
var setPlayRate: ((Double) -> Void)?
|
var setPlayRate: ((Double) -> Void)?
|
||||||
var fetchControl: (() -> Void)?
|
var fetchControl: (() -> Void)?
|
||||||
|
|
||||||
|
var interacting: ((Bool) -> Void)?
|
||||||
|
|
||||||
private var seekTimer: SwiftSignalKit.Timer?
|
private var seekTimer: SwiftSignalKit.Timer?
|
||||||
private var currentIsPaused: Bool = true
|
private var currentIsPaused: Bool = true
|
||||||
private var seekRate: Double = 1.0
|
private var seekRate: Double = 1.0
|
||||||
@ -892,6 +894,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
if messages.count == 1 {
|
if messages.count == 1 {
|
||||||
strongSelf.commitDeleteMessages(messages, ask: true)
|
strongSelf.commitDeleteMessages(messages, ask: true)
|
||||||
} else {
|
} else {
|
||||||
|
strongSelf.interacting?(true)
|
||||||
|
|
||||||
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
if !presentationData.theme.overallDarkAppearance {
|
if !presentationData.theme.overallDarkAppearance {
|
||||||
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||||
@ -930,8 +934,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||||
|
actionSheet.dismissed = { [weak self] _ in
|
||||||
|
self?.interacting?(false)
|
||||||
|
}
|
||||||
let items: [ActionSheetItem] = [
|
let items: [ActionSheetItem] = [
|
||||||
ActionSheetButtonItem(title: singleText, color: .destructive, action: { [weak actionSheet] in
|
ActionSheetButtonItem(title: singleText, color: .destructive, action: { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
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()
|
let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: messages.map { $0.id }, type: .forEveryone).start()
|
||||||
strongSelf.controllerInteraction?.dismissController()
|
strongSelf.controllerInteraction?.dismissController()
|
||||||
} else if !items.isEmpty {
|
} else if !items.isEmpty {
|
||||||
|
strongSelf.interacting?(true)
|
||||||
|
actionSheet.dismissed = { [weak self] _ in
|
||||||
|
self?.interacting?(false)
|
||||||
|
}
|
||||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||||
ActionSheetButtonItem(title: strongSelf.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
ActionSheetButtonItem(title: strongSelf.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
actionSheet?.dismissAnimated()
|
||||||
@ -1024,13 +1034,17 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func actionButtonPressed() {
|
@objc func actionButtonPressed() {
|
||||||
|
self.interacting?(true)
|
||||||
|
|
||||||
if let currentMessage = self.currentMessage {
|
if let currentMessage = self.currentMessage {
|
||||||
let _ = (self.context.account.postbox.transaction { transaction -> [Message] in
|
let _ = (self.context.account.postbox.transaction { transaction -> [Message] in
|
||||||
return transaction.getMessageGroup(currentMessage.id) ?? []
|
return transaction.getMessageGroup(currentMessage.id) ?? []
|
||||||
} |> deliverOnMainQueue).start(next: { [weak self] messages in
|
} |> deliverOnMainQueue).start(next: { [weak self] messages in
|
||||||
if let strongSelf = self, !messages.isEmpty {
|
if let strongSelf = self, !messages.isEmpty {
|
||||||
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
var forceTheme: PresentationTheme?
|
||||||
if !presentationData.theme.overallDarkAppearance {
|
if !presentationData.theme.overallDarkAppearance {
|
||||||
|
forceTheme = defaultDarkColorPresentationTheme
|
||||||
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||||
}
|
}
|
||||||
var generalMessageContentKind: MessageContentKind?
|
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
|
shareController.completed = { [weak self] peerIds in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||||
@ -1170,7 +1187,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
|
|
||||||
let shareAction: ([Message]) -> Void = { messages in
|
let shareAction: ([Message]) -> Void = { messages in
|
||||||
if let strongSelf = self {
|
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
|
shareController.completed = { [weak self] peerIds in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
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 {
|
} else if let (webPage, media) = self.currentWebPageAndMedia {
|
||||||
var presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
var presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
var forceTheme: PresentationTheme?
|
||||||
if !presentationData.theme.overallDarkAppearance {
|
if !presentationData.theme.overallDarkAppearance {
|
||||||
|
forceTheme = defaultDarkColorPresentationTheme
|
||||||
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,7 +1287,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
if availableOpenInOptions(context: self.context, item: item).count > 1 {
|
if availableOpenInOptions(context: self.context, item: item).count > 1 {
|
||||||
preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Conversation_FileOpenIn, action: { [weak self] in
|
preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Conversation_FileOpenIn, action: { [weak self] in
|
||||||
if let strongSelf = self {
|
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 {
|
if let strongSelf = self {
|
||||||
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
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
|
shareController.completed = { [weak self] peerIds in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||||
|
@ -120,7 +120,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
self.fetchStatusDisposable.dispose()
|
self.fetchStatusDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
var collapsed: Bool = false
|
var collapsed: Bool?
|
||||||
func setCollapsed(_ collapsed: Bool, animated: Bool) {
|
func setCollapsed(_ collapsed: Bool, animated: Bool) {
|
||||||
guard self.collapsed != collapsed else {
|
guard self.collapsed != collapsed else {
|
||||||
return
|
return
|
||||||
@ -128,15 +128,14 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
|
|
||||||
self.collapsed = collapsed
|
self.collapsed = collapsed
|
||||||
|
|
||||||
guard let (size, _, _) = self.containerLayout else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let alpha: CGFloat = collapsed ? 0.0 : 1.0
|
let alpha: CGFloat = collapsed ? 0.0 : 1.0
|
||||||
self.leftTimestampNode.alpha = alpha
|
self.leftTimestampNode.alpha = alpha
|
||||||
self.rightTimestampNode.alpha = alpha
|
self.rightTimestampNode.alpha = alpha
|
||||||
self.infoNode.alpha = size.width < size.height && !self.collapsed ? 1.0 : 0.0
|
|
||||||
self.updateScrubberVisibility(animated: animated)
|
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) {
|
private func updateScrubberVisibility(animated: Bool) {
|
||||||
@ -144,10 +143,10 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
var alpha: CGFloat = 1.0
|
var alpha: CGFloat = 1.0
|
||||||
if let playbackStatus = self.playbackStatus, playbackStatus.duration <= 30.0 {
|
if let playbackStatus = self.playbackStatus, playbackStatus.duration <= 30.0 {
|
||||||
} else {
|
} else {
|
||||||
alpha = self.collapsed ? 0.0 : 1.0
|
alpha = self.collapsed == true ? 0.0 : 1.0
|
||||||
collapsed = false
|
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
|
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .linear) : .immediate
|
||||||
transition.updateAlpha(node: self.scrubberNode, alpha: alpha)
|
transition.updateAlpha(node: self.scrubberNode, alpha: alpha)
|
||||||
}
|
}
|
||||||
@ -285,7 +284,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
let infoSize = self.infoNode.measure(infoConstrainedSize)
|
let infoSize = self.infoNode.measure(infoConstrainedSize)
|
||||||
self.infoNode.bounds = CGRect(origin: CGPoint(), size: infoSize)
|
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))
|
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))
|
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 {
|
public final class GalleryFooterNode: ASDisplayNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
|
|
||||||
|
private var currentThumbnailPanelHeight: CGFloat?
|
||||||
private var currentFooterContentNode: GalleryFooterContentNode?
|
private var currentFooterContentNode: GalleryFooterContentNode?
|
||||||
private var currentOverlayContentNode: GalleryOverlayContentNode?
|
private var currentOverlayContentNode: GalleryOverlayContentNode?
|
||||||
private var currentLayout: (ContainerViewLayout, CGFloat, Bool)?
|
private var currentLayout: (ContainerViewLayout, CGFloat, Bool)?
|
||||||
@ -36,11 +37,16 @@ public final class GalleryFooterNode: ASDisplayNode {
|
|||||||
let cleanInsets = layout.insets(options: [])
|
let cleanInsets = layout.insets(options: [])
|
||||||
|
|
||||||
var dismissedCurrentFooterContentNode: GalleryFooterContentNode?
|
var dismissedCurrentFooterContentNode: GalleryFooterContentNode?
|
||||||
|
var dismissedThumbnailPanelHeight: CGFloat?
|
||||||
if self.currentFooterContentNode !== footerContentNode {
|
if self.currentFooterContentNode !== footerContentNode {
|
||||||
if let currentFooterContentNode = self.currentFooterContentNode {
|
if let currentFooterContentNode = self.currentFooterContentNode {
|
||||||
currentFooterContentNode.requestLayout = nil
|
currentFooterContentNode.requestLayout = nil
|
||||||
dismissedCurrentFooterContentNode = currentFooterContentNode
|
dismissedCurrentFooterContentNode = currentFooterContentNode
|
||||||
}
|
}
|
||||||
|
if let currentThumbnailPanelHeight = self.currentThumbnailPanelHeight {
|
||||||
|
dismissedThumbnailPanelHeight = currentThumbnailPanelHeight
|
||||||
|
}
|
||||||
|
self.currentThumbnailPanelHeight = thumbnailPanelHeight
|
||||||
self.currentFooterContentNode = footerContentNode
|
self.currentFooterContentNode = footerContentNode
|
||||||
if let footerContentNode = footerContentNode {
|
if let footerContentNode = footerContentNode {
|
||||||
footerContentNode.setVisibilityAlpha(self.visibilityAlpha, animated: transition.isAnimated)
|
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
|
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 {
|
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)))
|
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 {
|
if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode {
|
||||||
let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
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) {
|
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) {
|
override func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
||||||
@ -271,12 +273,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
private let statusNode: RadialStatusNode
|
private let statusNode: RadialStatusNode
|
||||||
private var statusNodeShouldBeHidden = true
|
private var statusNodeShouldBeHidden = true
|
||||||
|
|
||||||
private var isCentral = false
|
private var isCentral: Bool?
|
||||||
private var _isVisible: Bool?
|
private var _isVisible: Bool?
|
||||||
private var initiallyActivated = false
|
private var initiallyActivated = false
|
||||||
private var hideStatusNodeUntilCentrality = false
|
private var hideStatusNodeUntilCentrality = false
|
||||||
private var playOnContentOwnership = false
|
private var playOnContentOwnership = false
|
||||||
private var skipInitialPause = false
|
private var skipInitialPause = false
|
||||||
|
private var ignorePauseStatus = false
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
private var didPause = false
|
private var didPause = false
|
||||||
private var isPaused = true
|
private var isPaused = true
|
||||||
@ -299,6 +302,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
private var scrubbingFrames = false
|
private var scrubbingFrames = false
|
||||||
private var scrubbingFrameDisposable: Disposable?
|
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)?
|
var playbackCompleted: (() -> Void)?
|
||||||
|
|
||||||
private var customUnembedWhenPortrait: ((OverlayMediaItemNode) -> Bool)?
|
private var customUnembedWhenPortrait: ((OverlayMediaItemNode) -> Bool)?
|
||||||
@ -323,6 +331,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
self.footerContentNode.interacting = { [weak self] value in
|
||||||
|
self?.isInteractingPromise.set(value)
|
||||||
|
}
|
||||||
|
|
||||||
self.overlayContentNode.action = { [weak self] toLandscape in
|
self.overlayContentNode.action = { [weak self] toLandscape in
|
||||||
self?.updateControlsVisibility(!toLandscape)
|
self?.updateControlsVisibility(!toLandscape)
|
||||||
context.sharedContext.applicationBindings.forceOrientation(toLandscape ? .landscapeRight : .portrait)
|
context.sharedContext.applicationBindings.forceOrientation(toLandscape ? .landscapeRight : .portrait)
|
||||||
@ -436,12 +448,30 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|
|
||||||
self.titleContentView = GalleryTitleView(frame: CGRect())
|
self.titleContentView = GalleryTitleView(frame: CGRect())
|
||||||
self._titleView.set(.single(self.titleContentView))
|
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 {
|
deinit {
|
||||||
self.statusDisposable.dispose()
|
self.statusDisposable.dispose()
|
||||||
self.mediaPlaybackStateDisposable.dispose()
|
self.mediaPlaybackStateDisposable.dispose()
|
||||||
self.scrubbingFrameDisposable?.dispose()
|
self.scrubbingFrameDisposable?.dispose()
|
||||||
|
self.hideControlsDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func ready() -> Signal<Void, NoError> {
|
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) {
|
func setupItem(_ item: UniversalVideoGalleryItem) {
|
||||||
if self.item?.content.id != item.content.id {
|
if self.item?.content.id != item.content.id {
|
||||||
self.previousPlaying = nil
|
self.isPlayingPromise.set(false)
|
||||||
|
|
||||||
if item.hideControls {
|
if item.hideControls {
|
||||||
self.statusButtonNode.isHidden = true
|
self.statusButtonNode.isHidden = true
|
||||||
@ -665,7 +683,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|> deliverOnMainQueue).start(next: { [weak self] value, fetchStatus in
|
|> deliverOnMainQueue).start(next: { [weak self] value, fetchStatus in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var initialBuffering = false
|
var initialBuffering = false
|
||||||
var playing = false
|
var isPlaying = false
|
||||||
var isPaused = true
|
var isPaused = true
|
||||||
var seekable = hintSeekable
|
var seekable = hintSeekable
|
||||||
var hasStarted = false
|
var hasStarted = false
|
||||||
@ -683,7 +701,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
switch value.status {
|
switch value.status {
|
||||||
case .playing:
|
case .playing:
|
||||||
isPaused = false
|
isPaused = false
|
||||||
playing = true
|
isPlaying = true
|
||||||
|
strongSelf.ignorePauseStatus = false
|
||||||
case let .buffering(_, whilePlaying, _, display):
|
case let .buffering(_, whilePlaying, _, display):
|
||||||
displayProgress = display
|
displayProgress = display
|
||||||
initialBuffering = !whilePlaying
|
initialBuffering = !whilePlaying
|
||||||
@ -716,9 +735,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
isPaused = false
|
isPaused = false
|
||||||
}
|
}
|
||||||
} else if strongSelf.actionAtEnd == .stop {
|
} else if strongSelf.actionAtEnd == .stop {
|
||||||
strongSelf.updateControlsVisibility(true)
|
strongSelf.isPlayingPromise.set(false)
|
||||||
strongSelf.controlsTimer?.invalidate()
|
if strongSelf.isCentral == true {
|
||||||
strongSelf.controlsTimer = nil
|
strongSelf.updateControlsVisibility(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !value.duration.isZero {
|
if !value.duration.isZero {
|
||||||
@ -726,14 +746,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strongSelf.isCentral && playing && strongSelf.previousPlaying != true && !disablePlayerControls {
|
if !disablePlayerControls && strongSelf.isCentral == true && isPlaying {
|
||||||
strongSelf.controlsTimer?.invalidate()
|
strongSelf.isPlayingPromise.set(true)
|
||||||
strongSelf.setupControlsTimer()
|
} else if !isPlaying {
|
||||||
} else if !playing {
|
strongSelf.isPlayingPromise.set(false)
|
||||||
strongSelf.controlsTimer?.invalidate()
|
|
||||||
strongSelf.controlsTimer = nil
|
|
||||||
}
|
}
|
||||||
strongSelf.previousPlaying = playing
|
|
||||||
|
|
||||||
var fetching = false
|
var fetching = false
|
||||||
if initialBuffering {
|
if initialBuffering {
|
||||||
@ -751,7 +768,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
case .Remote:
|
case .Remote:
|
||||||
state = .download(.white)
|
state = .download(.white)
|
||||||
case let .Fetching(_, progress):
|
case let .Fetching(_, progress):
|
||||||
if !playing {
|
if !isPlaying {
|
||||||
fetching = true
|
fetching = true
|
||||||
isPaused = true
|
isPaused = true
|
||||||
}
|
}
|
||||||
@ -768,13 +785,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
strongSelf.fetchStatus = fetchStatus
|
strongSelf.fetchStatus = fetchStatus
|
||||||
|
|
||||||
if !item.hideControls {
|
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
|
strongSelf.statusButtonNode.isHidden = strongSelf.hideStatusNodeUntilCentrality || strongSelf.statusNodeShouldBeHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
if isAnimated || disablePlayerControls {
|
if isAnimated || disablePlayerControls {
|
||||||
strongSelf.footerContentNode.content = .info
|
strongSelf.footerContentNode.content = .info
|
||||||
} else if isPaused {
|
} else if isPaused && !strongSelf.ignorePauseStatus {
|
||||||
if hasStarted || strongSelf.didPause {
|
if hasStarted || strongSelf.didPause {
|
||||||
strongSelf.footerContentNode.content = .playback(paused: true, seekable: seekable)
|
strongSelf.footerContentNode.content = .playback(paused: true, seekable: seekable)
|
||||||
} else if let fetchStatus = fetchStatus, !strongSelf.requiresDownload {
|
} else if let fetchStatus = fetchStatus, !strongSelf.requiresDownload {
|
||||||
@ -808,10 +825,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
if let strongSelf = self, !isAnimated {
|
if let strongSelf = self, !isAnimated {
|
||||||
videoNode?.seek(0.0)
|
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.updateControlsVisibility(true)
|
||||||
strongSelf.controlsTimer?.invalidate()
|
|
||||||
strongSelf.controlsTimer = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -834,8 +850,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func controlsVisibilityUpdated(isVisible: Bool) {
|
override func controlsVisibilityUpdated(isVisible: Bool) {
|
||||||
self.controlsTimer?.invalidate()
|
self.controlsVisiblePromise.set(isVisible)
|
||||||
self.controlsTimer = nil
|
|
||||||
|
|
||||||
self.videoNode?.isUserInteractionEnabled = isVisible ? self.videoNodeUserInteractionEnabled : false
|
self.videoNode?.isUserInteractionEnabled = isVisible ? self.videoNodeUserInteractionEnabled : false
|
||||||
self.videoNode?.notifyPlaybackControlsHidden(!isVisible)
|
self.videoNode?.notifyPlaybackControlsHidden(!isVisible)
|
||||||
@ -915,8 +930,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.controlsTimer?.invalidate()
|
self.isPlayingPromise.set(false)
|
||||||
self.controlsTimer = nil
|
|
||||||
|
|
||||||
self.dismissOnOrientationChange = false
|
self.dismissOnOrientationChange = false
|
||||||
if videoNode.ownsContentNode {
|
if videoNode.ownsContentNode {
|
||||||
@ -941,6 +955,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
if self.skipInitialPause {
|
if self.skipInitialPause {
|
||||||
self.skipInitialPause = false
|
self.skipInitialPause = false
|
||||||
} else {
|
} else {
|
||||||
|
self.ignorePauseStatus = true
|
||||||
videoNode.pause()
|
videoNode.pause()
|
||||||
videoNode.seek(0.0)
|
videoNode.seek(0.0)
|
||||||
}
|
}
|
||||||
@ -973,7 +988,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func activateAsInitial() {
|
override func activateAsInitial() {
|
||||||
if let videoNode = self.videoNode, self.isCentral {
|
if let videoNode = self.videoNode, self.isCentral == true {
|
||||||
self.initiallyActivated = true
|
self.initiallyActivated = true
|
||||||
|
|
||||||
var isAnimated = false
|
var isAnimated = false
|
||||||
@ -1614,6 +1629,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|> delay(0.15, queue: Queue.mainQueue())
|
|> delay(0.15, queue: Queue.mainQueue())
|
||||||
let progressDisposable = progressSignal.start()
|
let progressDisposable = progressSignal.start()
|
||||||
|
|
||||||
|
self.isInteractingPromise.set(true)
|
||||||
|
|
||||||
let signal = stickerPacksAttachedToMedia(account: self.context.account, media: media)
|
let signal = stickerPacksAttachedToMedia(account: self.context.account, media: media)
|
||||||
|> afterDisposed {
|
|> afterDisposed {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
@ -1627,7 +1644,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
}
|
}
|
||||||
let baseNavigationController = strongSelf.baseNavigationController()
|
let baseNavigationController = strongSelf.baseNavigationController()
|
||||||
baseNavigationController?.view.endEditing(true)
|
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)
|
(baseNavigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root), with: nil)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -575,6 +575,13 @@ public final class ListMessageFileItemNode: ListMessageNode {
|
|||||||
|
|
||||||
if statusUpdated {
|
if statusUpdated {
|
||||||
updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult)
|
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 isAudio || isInstantVideo {
|
||||||
if let currentUpdatedStatusSignal = updatedStatusSignal {
|
if let currentUpdatedStatusSignal = updatedStatusSignal {
|
||||||
|
@ -231,6 +231,9 @@ public final class SearchDisplayController {
|
|||||||
self.searchBar.activate()
|
self.searchBar.activate()
|
||||||
if let placeholder = placeholder {
|
if let placeholder = placeholder {
|
||||||
self.searchBar.animateIn(from: placeholder, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
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 {
|
} else {
|
||||||
self.searchBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
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)
|
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 backgroundNode = self.backgroundNode
|
||||||
let contentNode = self.contentNode
|
let contentNode = self.contentNode
|
||||||
if animated {
|
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.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak backgroundNode] _ in
|
||||||
backgroundNode?.removeFromSupernode()
|
backgroundNode?.removeFromSupernode()
|
||||||
})
|
})
|
||||||
|
@ -93,7 +93,11 @@ final class ThemeGridSearchColorsNode: ASDisplayNode {
|
|||||||
return CGSize(width: constrainedSize.width, height: 100.0)
|
return CGSize(width: constrainedSize.width, height: 100.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
||||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: 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.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)
|
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.frame = CGRect(x: 0.0, y: 29.0, width: size.width, height: size.height - 29.0)
|
||||||
self.scrollNode.view.contentInset = insets
|
self.scrollNode.view.contentInset = insets
|
||||||
|
if !hadLayout {
|
||||||
|
self.scrollNode.view.contentOffset = CGPoint(x: -leftInset, y: 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
var offset: CGFloat = inset
|
var offset: CGFloat = inset
|
||||||
if let subnodes = self.scrollNode.subnodes {
|
if let subnodes = self.scrollNode.subnodes {
|
||||||
|
@ -299,7 +299,7 @@ public final class ShareController: ViewController {
|
|||||||
private var currentAccount: Account
|
private var currentAccount: Account
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
private let forcedTheme: PresentationTheme?
|
private let forceTheme: PresentationTheme?
|
||||||
|
|
||||||
private let externalShare: Bool
|
private let externalShare: Bool
|
||||||
private let immediateExternalShare: 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) {
|
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, forcedTheme: forcedTheme, forcedActionTitle: forcedActionTitle)
|
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.sharedContext = sharedContext
|
||||||
self.currentContext = currentContext
|
self.currentContext = currentContext
|
||||||
self.currentAccount = currentContext.account
|
self.currentAccount = currentContext.account
|
||||||
@ -343,11 +343,11 @@ public final class ShareController: ViewController {
|
|||||||
self.immediatePeerId = immediatePeerId
|
self.immediatePeerId = immediatePeerId
|
||||||
self.fromForeignApp = fromForeignApp
|
self.fromForeignApp = fromForeignApp
|
||||||
self.segmentedValues = segmentedValues
|
self.segmentedValues = segmentedValues
|
||||||
self.forcedTheme = forcedTheme
|
self.forceTheme = forceTheme
|
||||||
|
|
||||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||||
if let forcedTheme = self.forcedTheme {
|
if let forceTheme = self.forceTheme {
|
||||||
self.presentationData = self.presentationData.withUpdated(theme: forcedTheme)
|
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
@ -487,17 +487,17 @@ public final class ShareController: ViewController {
|
|||||||
return
|
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))
|
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.completed = self.completed
|
||||||
self.controllerNode.dismiss = { [weak self] shared in
|
self.controllerNode.dismiss = { [weak self] shared in
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
self?.dismissed?(shared)
|
self?.dismissed?(shared)
|
||||||
|
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||||
}
|
}
|
||||||
self.controllerNode.cancel = { [weak self] in
|
self.controllerNode.cancel = { [weak self] in
|
||||||
self?.controllerNode.view.endEditing(true)
|
self?.controllerNode.view.endEditing(true)
|
||||||
self?.controllerNode.animateOut(shared: false, completion: {
|
self?.controllerNode.animateOut(shared: false, completion: {
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
self?.dismissed?(false)
|
self?.dismissed?(false)
|
||||||
|
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
self.controllerNode.share = { [weak self] text, peerIds in
|
self.controllerNode.share = { [weak self] text, peerIds in
|
||||||
|
@ -25,7 +25,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
private let sharedContext: SharedAccountContext
|
private let sharedContext: SharedAccountContext
|
||||||
private var context: AccountContext?
|
private var context: AccountContext?
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private let forcedTheme: PresentationTheme?
|
private let forceTheme: PresentationTheme?
|
||||||
private let externalShare: Bool
|
private let externalShare: Bool
|
||||||
private let immediateExternalShare: Bool
|
private let immediateExternalShare: Bool
|
||||||
private var immediatePeerId: PeerId?
|
private var immediatePeerId: PeerId?
|
||||||
@ -80,10 +80,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
|
|
||||||
private let presetText: String?
|
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.sharedContext = sharedContext
|
||||||
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||||
self.forcedTheme = forcedTheme
|
self.forceTheme = forceTheme
|
||||||
self.externalShare = externalShare
|
self.externalShare = externalShare
|
||||||
self.immediateExternalShare = immediateExternalShare
|
self.immediateExternalShare = immediateExternalShare
|
||||||
self.immediatePeerId = immediatePeerId
|
self.immediatePeerId = immediatePeerId
|
||||||
@ -96,8 +96,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
self.defaultAction = defaultAction
|
self.defaultAction = defaultAction
|
||||||
self.requestLayout = requestLayout
|
self.requestLayout = requestLayout
|
||||||
|
|
||||||
if let forcedTheme = self.forcedTheme {
|
if let forceTheme = self.forceTheme {
|
||||||
self.presentationData = self.presentationData.withUpdated(theme: forcedTheme)
|
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||||
@ -272,8 +272,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
if let forcedTheme = self.forcedTheme {
|
if let forceTheme = self.forceTheme {
|
||||||
self.presentationData = self.presentationData.withUpdated(theme: forcedTheme)
|
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
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 animatedIn = false
|
||||||
private var dismissed = false
|
private var isDismissed = false
|
||||||
|
|
||||||
|
public var dismissed: (() -> Void)?
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let mode: StickerPackPreviewControllerMode
|
private let mode: StickerPackPreviewControllerMode
|
||||||
@ -150,6 +152,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
|||||||
}))
|
}))
|
||||||
}, actionPerformed: self.actionPerformed)
|
}, actionPerformed: self.actionPerformed)
|
||||||
self.controllerNode.dismiss = { [weak self] in
|
self.controllerNode.dismiss = { [weak self] in
|
||||||
|
self?.dismissed?()
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||||
}
|
}
|
||||||
self.controllerNode.cancel = { [weak self] in
|
self.controllerNode.cancel = { [weak self] in
|
||||||
@ -264,8 +267,8 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||||
if !self.dismissed {
|
if !self.isDismissed {
|
||||||
self.dismissed = true
|
self.isDismissed = true
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -988,6 +988,8 @@ public final class StickerPackScreenImpl: ViewController {
|
|||||||
return self.displayNode as! StickerPackScreenNode
|
return self.displayNode as! StickerPackScreenNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var dismissed: (() -> Void)?
|
||||||
|
|
||||||
private let _ready = Promise<Bool>()
|
private let _ready = Promise<Bool>()
|
||||||
override public var ready: Promise<Bool> {
|
override public var ready: Promise<Bool> {
|
||||||
return self._ready
|
return self._ready
|
||||||
@ -1020,6 +1022,7 @@ public final class StickerPackScreenImpl: ViewController {
|
|||||||
strongSelf.updateModalStyleOverlayTransitionFactor(value, transition: transition)
|
strongSelf.updateModalStyleOverlayTransitionFactor(value, transition: transition)
|
||||||
}
|
}
|
||||||
}, dismissed: { [weak self] in
|
}, dismissed: { [weak self] in
|
||||||
|
self?.dismissed?()
|
||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
}, presentInGlobalOverlay: { [weak self] c, a in
|
}, presentInGlobalOverlay: { [weak self] c, a in
|
||||||
self?.presentInGlobalOverlay(c, with: a)
|
self?.presentInGlobalOverlay(c, with: a)
|
||||||
@ -1060,10 +1063,11 @@ public enum StickerPackScreenPerformedAction {
|
|||||||
case remove(positionInList: Int)
|
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)
|
//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)
|
let controller = StickerPackPreviewController(context: context, stickerPack: mainStickerPack, mode: mode, parentNavigationController: parentNavigationController, actionPerformed: actionPerformed)
|
||||||
|
controller.dismissed = dismissed
|
||||||
controller.sendSticker = sendSticker
|
controller.sendSticker = sendSticker
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
@ -563,7 +563,12 @@ public final class VoiceChatController: ViewController {
|
|||||||
var text: VoiceChatParticipantItem.ParticipantText
|
var text: VoiceChatParticipantItem.ParticipantText
|
||||||
var expandedText: VoiceChatParticipantItem.ParticipantText?
|
var expandedText: VoiceChatParticipantItem.ParticipantText?
|
||||||
let icon: VoiceChatParticipantItem.Icon
|
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:
|
case .listening:
|
||||||
if let muteState = peerEntry.muteState, muteState.mutedByYou {
|
if let muteState = peerEntry.muteState, muteState.mutedByYou {
|
||||||
text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive)
|
text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive)
|
||||||
@ -1268,7 +1273,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
openIcon = UIImage(bundleImageName: "Chat/Context Menu/Channels")
|
openIcon = UIImage(bundleImageName: "Chat/Context Menu/Channels")
|
||||||
} else {
|
} else {
|
||||||
openTitle = strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile
|
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
|
items.append(.action(ContextMenuActionItem(text: openTitle, icon: { theme in
|
||||||
return generateTintedImage(image: openIcon, color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: openIcon, color: theme.actionSheet.primaryTextColor)
|
||||||
@ -2236,7 +2241,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
return formatSendTitle(presentationData.strings.VoiceChat_InviteLink_InviteListeners(Int32(count)))
|
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
|
shareController.completed = { [weak self] peerIds in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||||
|
@ -179,6 +179,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
private var peerPresenceManager: PeerPresenceStatusManager?
|
private var peerPresenceManager: PeerPresenceStatusManager?
|
||||||
private var layoutParams: (VoiceChatParticipantItem, ListViewItemLayoutParams, Bool, Bool)?
|
private var layoutParams: (VoiceChatParticipantItem, ListViewItemLayoutParams, Bool, Bool)?
|
||||||
|
private var isExtracted = false
|
||||||
private var wavesColor: UIColor?
|
private var wavesColor: UIColor?
|
||||||
|
|
||||||
private var videoNode: GroupVideoNode?
|
private var videoNode: GroupVideoNode?
|
||||||
@ -279,6 +280,8 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.isExtracted = isExtracted
|
||||||
|
|
||||||
if isExtracted {
|
if isExtracted {
|
||||||
strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: item.presentationData.theme.list.itemBlocksBackgroundColor)
|
strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: item.presentationData.theme.list.itemBlocksBackgroundColor)
|
||||||
}
|
}
|
||||||
@ -521,7 +524,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
strongSelf.extractedRect = extractedRect
|
strongSelf.extractedRect = extractedRect
|
||||||
strongSelf.nonExtractedRect = nonExtractedRect
|
strongSelf.nonExtractedRect = nonExtractedRect
|
||||||
|
|
||||||
if strongSelf.contextSourceNode.isExtractedToContextPreview {
|
if strongSelf.isExtracted {
|
||||||
strongSelf.extractedBackgroundImageNode.frame = extractedRect
|
strongSelf.extractedBackgroundImageNode.frame = extractedRect
|
||||||
} else {
|
} else {
|
||||||
strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect
|
strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect
|
||||||
|
@ -30,7 +30,9 @@ func updateAppConfigurationOnce(postbox: Postbox, network: Network) -> Signal<Vo
|
|||||||
|
|
||||||
func managedAppConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
func managedAppConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||||
let poll = Signal<Void, NoError> { subscriber in
|
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
|
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 updateAutodownloadSettingsInteractively(accountManager: accountManager, { _ -> AutodownloadSettings in
|
||||||
return AutodownloadSettings(apiAutodownloadSettings: result)
|
return AutodownloadSettings(apiAutodownloadSettings: result)
|
||||||
})
|
})
|
||||||
}).start()
|
}).start(completed: {
|
||||||
|
subscriber.putCompletion()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
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
|
|> switchToLatest
|
||||||
}).start()
|
}).start(completed: {
|
||||||
|
subscriber.putCompletion()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
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
|
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)
|
self.rootController.setForceInCallStatusBar((self.context.sharedContext as! SharedAccountContextImpl).currentCallStatusBarNode)
|
||||||
if let groupCallController = self.context.sharedContext.currentGroupCallController as? VoiceChatController {
|
if let groupCallController = self.context.sharedContext.currentGroupCallController as? VoiceChatController {
|
||||||
if let overlayController = groupCallController.currentOverlayController {
|
if let overlayController = groupCallController.currentOverlayController {
|
||||||
|
groupCallController.parentNavigationController = self.rootController
|
||||||
self.rootController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false)
|
self.rootController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1364,6 +1364,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
case .replyThread:
|
case .replyThread:
|
||||||
postAsReply = true
|
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({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
@ -2423,7 +2430,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
var items: [ContextMenuItem] = [
|
var items: [ContextMenuItem] = [
|
||||||
.action(ContextMenuActionItem(text: isChannel ? strongSelf.presentationData.strings.Conversation_ContextMenuOpenChannelProfile : strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile, icon: { theme in
|
.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
|
}, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
self?.openPeer(peerId: peer.id, navigation: .info, fromMessage: nil)
|
self?.openPeer(peerId: peer.id, navigation: .info, fromMessage: nil)
|
||||||
@ -7266,19 +7273,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.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)
|
self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
if case .compact = layout.metrics.widthClass {
|
||||||
override public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) {
|
let hasOverlayNodes = self.context.sharedContext.mediaManager.overlayMediaManager.controller?.hasNodes ?? false
|
||||||
guard let layout = self.validLayout, case .compact = layout.metrics.widthClass else {
|
if self.validLayout != nil && layout.size.width > layout.size.height && !hasOverlayNodes && self.traceVisibility() && isTopmostChatController(self) {
|
||||||
return
|
var completed = false
|
||||||
}
|
self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
|
||||||
let hasOverlayNodes = self.context.sharedContext.mediaManager.overlayMediaManager.controller?.hasNodes ?? false
|
if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled {
|
||||||
if self.validLayout != nil && orientation.isLandscape && !hasOverlayNodes && self.traceVisibility() && isTopmostChatController(self) {
|
let _ = self.controllerInteraction?.openMessage(message, .landscape)
|
||||||
var completed = false
|
completed = true
|
||||||
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