mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '66619d2e1789272bd2486bb7d66f79c05ce1ff15'
This commit is contained in:
commit
10ad65523e
@ -9048,7 +9048,7 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Login.Email.CantAccess" = "Can't access this email?";
|
||||
"Login.Email.ResetTitle" = "Reset Email";
|
||||
"Login.Email.ResetText" = "You can change your login email if you are logged into Telegram from another device. Otherwise, if you don't have access to email %@, you can reset this email with an SMS code in 7 days.";
|
||||
"Login.Email.ResetText" = "You can change your login email if you are logged into Telegram from another device. Otherwise, if you don't have access to email %1$@, you can reset this email with an **SMS** code **%2$@**.";
|
||||
"Login.Email.Reset" = "Reset";
|
||||
"Login.Email.ResetNowViaSMS" = "Reset now via SMS";
|
||||
"Login.Email.WillBeResetIn" = "Email will be reset in %@";
|
||||
@ -9061,3 +9061,5 @@ Sorry for the inconvenience.";
|
||||
"Conversation.ForwardOptions.RecipientsMessageForwardHidden" = "Recipients won't see that it was forwarded";
|
||||
"Conversation.ForwardOptions.RecipientsMessagesForwardVisible" = "Recipients will see they were forwarded";
|
||||
"Conversation.ForwardOptions.RecipientsMessagesForwardHidden" = "Recipients won't see they were forwarded";
|
||||
|
||||
"Conversation.SendMessage.SendWhenOnline" = "Send When Online";
|
||||
|
@ -667,4 +667,5 @@ public enum FileMediaResourceMediaStatus: Equatable {
|
||||
|
||||
public protocol ChatMessageItemNodeProtocol: ListViewItemNode {
|
||||
func targetReactionView(value: MessageReaction.Reaction) -> UIView?
|
||||
func contentFrame() -> CGRect
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public final class OpenChatMessageParams {
|
||||
public let playlistLocation: PeerMessagesPlaylistLocation?
|
||||
public let gallerySource: GalleryControllerItemSource?
|
||||
public let centralItemUpdated: ((MessageId) -> Void)?
|
||||
public let getSourceRect: (() -> CGRect?)?
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
@ -72,7 +73,8 @@ public final class OpenChatMessageParams {
|
||||
actionInteraction: GalleryControllerActionInteraction? = nil,
|
||||
playlistLocation: PeerMessagesPlaylistLocation? = nil,
|
||||
gallerySource: GalleryControllerItemSource? = nil,
|
||||
centralItemUpdated: ((MessageId) -> Void)? = nil
|
||||
centralItemUpdated: ((MessageId) -> Void)? = nil,
|
||||
getSourceRect: (() -> CGRect?)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
@ -100,5 +102,6 @@ public final class OpenChatMessageParams {
|
||||
self.playlistLocation = playlistLocation
|
||||
self.gallerySource = gallerySource
|
||||
self.centralItemUpdated = centralItemUpdated
|
||||
self.getSourceRect = getSourceRect
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ public enum AttachmentTextInputPanelSendMode {
|
||||
case generic
|
||||
case silent
|
||||
case schedule
|
||||
case whenOnline
|
||||
}
|
||||
|
||||
public protocol PeerSelectionController: ViewController {
|
||||
|
@ -10,7 +10,10 @@ swift_library(
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities:TextNodeWithEntities",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
355
submodules/AlertUI/Sources/TextAlertWithEntitiesController.swift
Normal file
355
submodules/AlertUI/Sources/TextAlertWithEntitiesController.swift
Normal file
@ -0,0 +1,355 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TextNodeWithEntities
|
||||
|
||||
private let alertWidth: CGFloat = 270.0
|
||||
|
||||
final class TextAlertWithEntitiesContentNode: AlertContentNode {
|
||||
private var theme: AlertControllerTheme
|
||||
private let actionLayout: TextAlertContentActionLayout
|
||||
|
||||
private let titleNode: ImmediateTextNode?
|
||||
private let textNode: ImmediateTextNodeWithEntities
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
private let _dismissOnOutsideTap: Bool
|
||||
override public var dismissOnOutsideTap: Bool {
|
||||
return self._dismissOnOutsideTap
|
||||
}
|
||||
|
||||
private var highlightedItemIndex: Int? = nil
|
||||
|
||||
var textAttributeAction: (NSAttributedString.Key, (Any) -> Void)? {
|
||||
didSet {
|
||||
if let (attribute, textAttributeAction) = self.textAttributeAction {
|
||||
self.textNode.highlightAttributeAction = { attributes in
|
||||
if let _ = attributes[attribute] {
|
||||
return attribute
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
self.textNode.tapAttributeAction = { attributes, _ in
|
||||
if let value = attributes[attribute] {
|
||||
textAttributeAction(value)
|
||||
}
|
||||
}
|
||||
self.textNode.linkHighlightColor = self.theme.accentColor.withAlphaComponent(0.5)
|
||||
} else {
|
||||
self.textNode.highlightAttributeAction = nil
|
||||
self.textNode.tapAttributeAction = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout, dismissOnOutsideTap: Bool) {
|
||||
self.theme = theme
|
||||
self.actionLayout = actionLayout
|
||||
self._dismissOnOutsideTap = dismissOnOutsideTap
|
||||
if let title = title {
|
||||
let titleNode = ImmediateTextNode()
|
||||
titleNode.attributedText = title
|
||||
titleNode.displaysAsynchronously = false
|
||||
titleNode.isUserInteractionEnabled = false
|
||||
titleNode.maximumNumberOfLines = 4
|
||||
titleNode.truncationType = .end
|
||||
titleNode.isAccessibilityElement = true
|
||||
titleNode.accessibilityLabel = title.string
|
||||
self.titleNode = titleNode
|
||||
} else {
|
||||
self.titleNode = nil
|
||||
}
|
||||
|
||||
self.textNode = ImmediateTextNodeWithEntities()
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.attributedText = text
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.isLayerBacked = false
|
||||
self.textNode.isAccessibilityElement = true
|
||||
self.textNode.accessibilityLabel = text.string
|
||||
self.textNode.insets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
if text.length != 0 {
|
||||
if let paragraphStyle = text.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? NSParagraphStyle {
|
||||
self.textNode.textAlignment = paragraphStyle.alignment
|
||||
}
|
||||
}
|
||||
self.textNode.spoilerColor = theme.secondaryColor
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
|
||||
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||
return TextAlertContentActionNode(theme: theme, action: action)
|
||||
}
|
||||
|
||||
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||
if actions.count > 1 {
|
||||
for _ in 0 ..< actions.count - 1 {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.isLayerBacked = true
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
actionVerticalSeparators.append(separatorNode)
|
||||
}
|
||||
}
|
||||
self.actionVerticalSeparators = actionVerticalSeparators
|
||||
|
||||
super.init()
|
||||
|
||||
if let titleNode = self.titleNode {
|
||||
self.addSubnode(titleNode)
|
||||
}
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
var i = 0
|
||||
for actionNode in self.actionNodes {
|
||||
self.addSubnode(actionNode)
|
||||
|
||||
let index = i
|
||||
actionNode.highlightedUpdated = { [weak self] highlighted in
|
||||
if highlighted {
|
||||
self?.highlightedItemIndex = index
|
||||
}
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
}
|
||||
|
||||
func setHighlightedItemIndex(_ index: Int?, update: Bool = false) {
|
||||
self.highlightedItemIndex = index
|
||||
|
||||
if update {
|
||||
var i = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if i == index {
|
||||
actionNode.setHighlighted(true, animated: false)
|
||||
} else {
|
||||
actionNode.setHighlighted(false, animated: false)
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func decreaseHighlightedIndex() {
|
||||
let currentHighlightedIndex = self.highlightedItemIndex ?? 0
|
||||
|
||||
self.setHighlightedItemIndex(max(0, currentHighlightedIndex - 1), update: true)
|
||||
}
|
||||
|
||||
override func increaseHighlightedIndex() {
|
||||
let currentHighlightedIndex = self.highlightedItemIndex ?? -1
|
||||
|
||||
self.setHighlightedItemIndex(min(self.actionNodes.count - 1, currentHighlightedIndex + 1), update: true)
|
||||
}
|
||||
|
||||
override func performHighlightedAction() {
|
||||
guard let highlightedItemIndex = self.highlightedItemIndex else {
|
||||
return
|
||||
}
|
||||
|
||||
var i = 0
|
||||
for itemNode in self.actionNodes {
|
||||
if i == highlightedItemIndex {
|
||||
itemNode.performAction()
|
||||
return
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.theme = theme
|
||||
|
||||
if let titleNode = self.titleNode, let attributedText = titleNode.attributedText {
|
||||
let updatedText = NSMutableAttributedString(attributedString: attributedText)
|
||||
updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length))
|
||||
titleNode.attributedText = updatedText
|
||||
}
|
||||
if let attributedText = self.textNode.attributedText {
|
||||
let updatedText = NSMutableAttributedString(attributedString: attributedText)
|
||||
updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length))
|
||||
self.textNode.attributedText = updatedText
|
||||
}
|
||||
self.textNode.spoilerColor = theme.secondaryColor
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
}
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
_ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
self.validLayout = size
|
||||
|
||||
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0)
|
||||
|
||||
var size = size
|
||||
size.width = min(size.width, alertWidth)
|
||||
|
||||
var titleSize: CGSize?
|
||||
if let titleNode = self.titleNode {
|
||||
titleSize = titleNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude))
|
||||
}
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||
let actionTitleInsets: CGFloat = 8.0
|
||||
|
||||
var effectiveActionLayout = self.actionLayout
|
||||
for actionNode in self.actionNodes {
|
||||
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
|
||||
effectiveActionLayout = .vertical
|
||||
}
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
minActionsWidth += actionTitleSize.width + actionTitleInsets
|
||||
case .vertical:
|
||||
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||
}
|
||||
}
|
||||
|
||||
let resultSize: CGSize
|
||||
|
||||
var actionsHeight: CGFloat = 0.0
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionsHeight = actionButtonHeight
|
||||
case .vertical:
|
||||
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
}
|
||||
|
||||
let contentWidth = alertWidth - insets.left - insets.right
|
||||
if let titleNode = self.titleNode, let titleSize = titleSize {
|
||||
let spacing: CGFloat = 6.0
|
||||
let titleFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - titleSize.width) / 2.0), y: insets.top), size: titleSize)
|
||||
transition.updateFrame(node: titleNode, frame: titleFrame)
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: titleFrame.maxY + spacing), size: textSize)
|
||||
transition.updateFrame(node: self.textNode, frame: textFrame.offsetBy(dx: -1.0, dy: -1.0))
|
||||
|
||||
resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: titleSize.height + spacing + textSize.height + actionsHeight + insets.top + insets.bottom)
|
||||
} else {
|
||||
let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: insets.top), size: textSize)
|
||||
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||
|
||||
resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: textSize.height + actionsHeight + insets.top + insets.bottom)
|
||||
}
|
||||
|
||||
self.actionNodesSeparator.frame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel))
|
||||
|
||||
var actionOffset: CGFloat = 0.0
|
||||
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
|
||||
var separatorIndex = -1
|
||||
var nodeIndex = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if separatorIndex >= 0 {
|
||||
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
|
||||
case .vertical:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
separatorIndex += 1
|
||||
|
||||
let currentActionWidth: CGFloat
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
if nodeIndex == self.actionNodes.count - 1 {
|
||||
currentActionWidth = resultSize.width - actionOffset
|
||||
} else {
|
||||
currentActionWidth = actionWidth
|
||||
}
|
||||
case .vertical:
|
||||
currentActionWidth = resultSize.width
|
||||
}
|
||||
|
||||
let actionNodeFrame: CGRect
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += currentActionWidth
|
||||
case .vertical:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += actionButtonHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
}
|
||||
|
||||
public func textWithEntitiesAlertController(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController {
|
||||
var dismissImpl: (() -> Void)?
|
||||
let controller = AlertController(theme: theme, contentNode: TextAlertWithEntitiesContentNode(theme: theme, title: title, text: text, actions: actions.map { action in
|
||||
return TextAlertAction(type: action.type, title: action.title, action: {
|
||||
if dismissAutomatically {
|
||||
dismissImpl?()
|
||||
}
|
||||
action.action()
|
||||
})
|
||||
}, actionLayout: actionLayout, dismissOnOutsideTap: true), allowInputInset: allowInputInset)
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
public func textWithEntitiesAlertController(alertContext: AlertControllerContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController {
|
||||
let theme = alertContext.theme
|
||||
|
||||
var dismissImpl: (() -> Void)?
|
||||
let controller = AlertController(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title, text: text, actions: actions.map { action in
|
||||
return TextAlertAction(type: action.type, title: action.title, action: {
|
||||
if dismissAutomatically {
|
||||
dismissImpl?()
|
||||
}
|
||||
action.action()
|
||||
})
|
||||
}, actionLayout: actionLayout, dismissOnOutsideTap: true), allowInputInset: allowInputInset)
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
|
||||
let presentationDataDisposable = alertContext.themeSignal.start(next: { [weak controller] theme in
|
||||
controller?.theme = theme
|
||||
})
|
||||
controller.dismissed = { _ in
|
||||
presentationDataDisposable.dispose()
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
|
||||
|
@ -117,6 +117,12 @@ public extension AttachmentContainable {
|
||||
}
|
||||
|
||||
public enum AttachmentMediaPickerSendMode {
|
||||
case generic
|
||||
case silently
|
||||
case whenOnline
|
||||
}
|
||||
|
||||
public enum AttachmentMediaPickerAttachmentMode {
|
||||
case media
|
||||
case files
|
||||
}
|
||||
@ -131,7 +137,7 @@ public protocol AttachmentMediaPickerContext {
|
||||
func mainButtonAction()
|
||||
|
||||
func setCaption(_ caption: NSAttributedString)
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode)
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode)
|
||||
func schedule()
|
||||
}
|
||||
|
||||
@ -380,12 +386,14 @@ public class AttachmentController: ViewController {
|
||||
self.panel.sendMessagePressed = { [weak self] mode in
|
||||
if let strongSelf = self {
|
||||
switch mode {
|
||||
case .generic:
|
||||
strongSelf.mediaPickerContext?.send(silently: false, mode: .media)
|
||||
case .silent:
|
||||
strongSelf.mediaPickerContext?.send(silently: true, mode: .media)
|
||||
case .schedule:
|
||||
strongSelf.mediaPickerContext?.schedule()
|
||||
case .generic:
|
||||
strongSelf.mediaPickerContext?.send(mode: .generic, attachmentMode: .media)
|
||||
case .silent:
|
||||
strongSelf.mediaPickerContext?.send(mode: .silently, attachmentMode: .media)
|
||||
case .schedule:
|
||||
strongSelf.mediaPickerContext?.schedule()
|
||||
case .whenOnline:
|
||||
strongSelf.mediaPickerContext?.send(mode: .whenOnline, attachmentMode: .media)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -925,7 +925,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
return
|
||||
}
|
||||
textInputPanelNode.loadTextInputNodeIfNeeded()
|
||||
guard let textInputNode = textInputPanelNode.textInputNode else {
|
||||
guard let textInputNode = textInputPanelNode.textInputNode, let peerId = chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -933,15 +933,36 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
if case .media = strongSelf.presentationInterfaceState.inputMode {
|
||||
hasEntityKeyboard = true
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, attachment: true, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] silently in
|
||||
textInputPanelNode?.sendMessage(silently ? .silent : .generic)
|
||||
}, schedule: { [weak textInputPanelNode] in
|
||||
textInputPanelNode?.sendMessage(.schedule)
|
||||
let _ = (strongSelf.context.account.viewTracker.peerView(peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerView in
|
||||
guard let strongSelf = self, let peer = peerViewMainPeer(peerView) else {
|
||||
return
|
||||
}
|
||||
var sendWhenOnlineAvailable = false
|
||||
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case .present = presence.status {
|
||||
sendWhenOnlineAvailable = true
|
||||
}
|
||||
if peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id._internalGetInt64Value() == 777000 {
|
||||
sendWhenOnlineAvailable = false
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, attachment: true, canSendWhenOnline: sendWhenOnlineAvailable, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] mode in
|
||||
switch mode {
|
||||
case .generic:
|
||||
textInputPanelNode?.sendMessage(.generic)
|
||||
case .silently:
|
||||
textInputPanelNode?.sendMessage(.silent)
|
||||
case .whenOnline:
|
||||
textInputPanelNode?.sendMessage(.whenOnline)
|
||||
}
|
||||
}, schedule: { [weak textInputPanelNode] in
|
||||
textInputPanelNode?.sendMessage(.schedule)
|
||||
})
|
||||
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
|
||||
strongSelf.presentInGlobalOverlay(controller)
|
||||
})
|
||||
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
|
||||
strongSelf.presentInGlobalOverlay(controller)
|
||||
}, openScheduledMessages: {
|
||||
}, openPeersNearby: {
|
||||
}, displaySearchResultsTooltip: { _, _ in
|
||||
|
@ -38,6 +38,8 @@ swift_library(
|
||||
"//submodules/InvisibleInkDustNode:InvisibleInkDustNode",
|
||||
"//submodules/AuthorizationUtils:AuthorizationUtils",
|
||||
"//submodules/ManagedAnimationNode:ManagedAnimationNode",
|
||||
"//submodules/AlertUI:AlertUI",
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities:TextNodeWithEntities",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -12,9 +12,9 @@ import PhoneNumberFormat
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import SolidRoundedButtonNode
|
||||
import InvisibleInkDustNode
|
||||
import AuthorizationUtils
|
||||
import TelegramStringFormatting
|
||||
import TextNodeWithEntities
|
||||
|
||||
final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextFieldDelegate {
|
||||
private let strings: PresentationStrings
|
||||
@ -24,9 +24,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let titleActivateAreaNode: AccessibilityAreaNode
|
||||
private let titleIconNode: ASImageNode
|
||||
private let currentOptionNode: ImmediateTextNode
|
||||
private let currentOptionNode: ImmediateTextNodeWithEntities
|
||||
private let currentOptionActivateAreaNode: AccessibilityAreaNode
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
|
||||
private let currentOptionInfoNode: ASTextNode
|
||||
private let currentOptionInfoActivateAreaNode: AccessibilityAreaNode
|
||||
@ -105,11 +104,12 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.titleIconNode.displayWithoutProcessing = true
|
||||
self.titleIconNode.displaysAsynchronously = false
|
||||
|
||||
self.currentOptionNode = ImmediateTextNode()
|
||||
self.currentOptionNode = ImmediateTextNodeWithEntities()
|
||||
self.currentOptionNode.isUserInteractionEnabled = false
|
||||
self.currentOptionNode.displaysAsynchronously = false
|
||||
self.currentOptionNode.lineSpacing = 0.1
|
||||
self.currentOptionNode.maximumNumberOfLines = 0
|
||||
self.currentOptionNode.spoilerColor = self.theme.list.itemSecondaryTextColor
|
||||
|
||||
self.currentOptionActivateAreaNode = AccessibilityAreaNode()
|
||||
self.currentOptionActivateAreaNode.accessibilityTraits = .staticText
|
||||
@ -570,23 +570,6 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
|
||||
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - additionalBottomInset)), items: items, transition: transition, failIfDoesNotFit: false)
|
||||
|
||||
if let textLayout = self.currentOptionNode.cachedLayout, !textLayout.spoilers.isEmpty {
|
||||
if self.dustNode == nil {
|
||||
let dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: true)
|
||||
self.dustNode = dustNode
|
||||
self.currentOptionNode.supernode?.insertSubnode(dustNode, aboveSubnode: self.currentOptionNode)
|
||||
|
||||
}
|
||||
if let dustNode = self.dustNode {
|
||||
let textFrame = self.currentOptionNode.frame
|
||||
dustNode.update(size: textFrame.size, color: self.theme.list.itemSecondaryTextColor, textColor: self.theme.list.itemPrimaryTextColor, rects: textLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: textLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
|
||||
transition.updateFrame(node: dustNode, frame: textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0))
|
||||
}
|
||||
} else if let dustNode = self.dustNode {
|
||||
self.dustNode = nil
|
||||
dustNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
self.nextOptionTitleNode.frame = self.nextOptionButtonNode.bounds
|
||||
|
||||
self.titleActivateAreaNode.frame = self.titleNode.frame
|
||||
|
@ -18,6 +18,8 @@ import LegacyMediaPickerUI
|
||||
import PasswordSetupUI
|
||||
import TelegramNotices
|
||||
import AuthenticationServices
|
||||
import Markdown
|
||||
import AlertUI
|
||||
|
||||
private enum InnerState: Equatable {
|
||||
case state(UnauthorizedAccountStateContents)
|
||||
@ -280,7 +282,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
return controller
|
||||
}
|
||||
|
||||
private func codeEntryController(number: String, email: String?, type: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) -> AuthorizationSequenceCodeEntryController {
|
||||
private func codeEntryController(number: String, phoneCodeHash: String, email: String?, type: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) -> AuthorizationSequenceCodeEntryController {
|
||||
var currentController: AuthorizationSequenceCodeEntryController?
|
||||
for c in self.viewControllers {
|
||||
if let c = c as? AuthorizationSequenceCodeEntryController {
|
||||
@ -302,8 +304,57 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
|
||||
})
|
||||
controller.resetEmail = {
|
||||
|
||||
controller.resetEmail = { [weak self, weak controller] in
|
||||
if let self, case let .email(pattern, _, resetAvailablePeriod, resetPendingDate, _, setup) = type, !setup {
|
||||
if let _ = resetPendingDate {
|
||||
|
||||
} else if let resetAvailablePeriod {
|
||||
let pattern = pattern.replacingOccurrences(of: "*", with: "#")
|
||||
let title = NSAttributedString(string: self.presentationData.strings.Login_Email_ResetTitle, font: Font.semibold(self.presentationData.listsFontSize.baseDisplaySize), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
||||
let availableIn = unmuteIntervalString(strings: self.presentationData.strings, value: resetAvailablePeriod)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(self.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(self.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
||||
let text = parseMarkdownIntoAttributedString(self.presentationData.strings.Login_Email_ResetText(pattern, availableIn).string, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil }), textAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
||||
if let regex = try? NSRegularExpression(pattern: "\\#", options: []) {
|
||||
let matches = regex.matches(in: text.string, options: [], range: NSMakeRange(0, text.length))
|
||||
if let first = matches.first {
|
||||
text.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: NSRange(location: first.range.location, length: matches.count))
|
||||
}
|
||||
}
|
||||
|
||||
let alertController = textWithEntitiesAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Login_Email_Reset, action: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.actionDisposable.set(
|
||||
(resetLoginEmail(account: self.account, phoneNumber: number, phoneCodeHash: phoneCodeHash)
|
||||
|> deliverOnMainQueue).start(error: { [weak self] error in
|
||||
Queue.mainQueue().async {
|
||||
guard let self, let controller = controller else {
|
||||
return
|
||||
}
|
||||
controller.inProgress = false
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = self.presentationData.strings.Login_CodeFloodError
|
||||
case .generic:
|
||||
text = self.presentationData.strings.Login_UnknownError
|
||||
case .codeExpired:
|
||||
text = self.presentationData.strings.Login_CodeExpired
|
||||
let account = self.account
|
||||
let _ = TelegramEngineUnauthorized(account: self.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start()
|
||||
}
|
||||
|
||||
controller.presentInGlobalOverlay(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]))
|
||||
}
|
||||
})
|
||||
)
|
||||
})])
|
||||
controller?.present(alertController, in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.loginWithCode = { [weak self, weak controller] code in
|
||||
if let strongSelf = self {
|
||||
@ -1068,7 +1119,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
|
||||
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number, splashController: previousSplashController))
|
||||
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty && (previousSplashController == nil || self.viewControllers.count > 2))
|
||||
case let .confirmationCodeEntry(number, type, _, timeout, nextType, _):
|
||||
case let .confirmationCodeEntry(number, type, phoneCodeHash, timeout, nextType, _):
|
||||
var controllers: [ViewController] = []
|
||||
if !self.otherAccountPhoneNumbers.1.isEmpty {
|
||||
controllers.append(self.splashController())
|
||||
@ -1081,7 +1132,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
if let _ = self.currentEmail {
|
||||
controllers.append(self.emailSetupController(number: number, appleSignInAllowed: self.appleSignInAllowed))
|
||||
}
|
||||
controllers.append(self.codeEntryController(number: number, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, termsOfService: nil))
|
||||
controllers.append(self.codeEntryController(number: number, phoneCodeHash: phoneCodeHash, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, termsOfService: nil))
|
||||
}
|
||||
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
|
||||
case let .passwordEntry(hint, _, _, suggestReset, syncContacts):
|
||||
|
@ -29,12 +29,8 @@ public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, ph
|
||||
return NSAttributedString(string: "", font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center)
|
||||
case let .email(emailPattern, _, _, _, _, _):
|
||||
let mutableString = NSAttributedString(string: strings.Login_EnterCodeEmailText(email ?? emailPattern).string, font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
||||
|
||||
let string = mutableString.string
|
||||
let nsString = string as NSString
|
||||
|
||||
if let regex = try? NSRegularExpression(pattern: "\\*", options: []) {
|
||||
let matches = regex.matches(in: string, options: [], range: NSMakeRange(0, nsString.length))
|
||||
let matches = regex.matches(in: mutableString.string, options: [], range: NSMakeRange(0, mutableString.length))
|
||||
if let first = matches.first {
|
||||
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: NSRange(location: first.range.location, length: matches.count))
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ import TelegramCore
|
||||
import TextFormat
|
||||
|
||||
public final class ChatSendMessageActionSheetController: ViewController {
|
||||
public enum SendMode {
|
||||
case generic
|
||||
case silently
|
||||
case whenOnline
|
||||
}
|
||||
private var controllerNode: ChatSendMessageActionSheetControllerNode {
|
||||
return self.displayNode as! ChatSendMessageActionSheetControllerNode
|
||||
}
|
||||
@ -24,8 +29,9 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
private let sourceSendButton: ASDisplayNode
|
||||
private let textInputNode: EditableTextNode
|
||||
private let attachment: Bool
|
||||
private let canSendWhenOnline: Bool
|
||||
private let completion: () -> Void
|
||||
private let sendMessage: (Bool) -> Void
|
||||
private let sendMessage: (SendMode) -> Void
|
||||
private let schedule: () -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
@ -39,7 +45,7 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
|
||||
public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id?, forwardMessageIds: [EngineMessage.Id]?, hasEntityKeyboard: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, completion: @escaping () -> Void, sendMessage: @escaping (Bool) -> Void, schedule: @escaping () -> Void) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id?, forwardMessageIds: [EngineMessage.Id]?, hasEntityKeyboard: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, canSendWhenOnline: Bool, completion: @escaping () -> Void, sendMessage: @escaping (SendMode) -> Void, schedule: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.forwardMessageIds = forwardMessageIds
|
||||
@ -48,6 +54,7 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
self.sourceSendButton = sourceSendButton
|
||||
self.textInputNode = textInputNode
|
||||
self.attachment = attachment
|
||||
self.canSendWhenOnline = canSendWhenOnline
|
||||
self.completion = completion
|
||||
self.sendMessage = sendMessage
|
||||
self.schedule = schedule
|
||||
@ -95,11 +102,14 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
canSchedule = !isSecret
|
||||
}
|
||||
|
||||
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, forwardedCount: forwardedCount, hasEntityKeyboard: self.hasEntityKeyboard, emojiViewProvider: self.emojiViewProvider, send: { [weak self] in
|
||||
self?.sendMessage(false)
|
||||
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, canSendWhenOnline: self.canSendWhenOnline, forwardedCount: forwardedCount, hasEntityKeyboard: self.hasEntityKeyboard, emojiViewProvider: self.emojiViewProvider, send: { [weak self] in
|
||||
self?.sendMessage(.generic)
|
||||
self?.dismiss(cancel: false)
|
||||
}, sendSilently: { [weak self] in
|
||||
self?.sendMessage(true)
|
||||
self?.sendMessage(.silently)
|
||||
self?.dismiss(cancel: false)
|
||||
}, sendWhenOnline: { [weak self] in
|
||||
self?.sendMessage(.whenOnline)
|
||||
self?.dismiss(cancel: false)
|
||||
}, schedule: !canSchedule ? nil : { [weak self] in
|
||||
self?.schedule()
|
||||
|
@ -17,15 +17,18 @@ private let rightInset: CGFloat = 16.0
|
||||
|
||||
private enum ChatSendMessageActionIcon {
|
||||
case sendWithoutSound
|
||||
case sendWhenOnline
|
||||
case schedule
|
||||
|
||||
func image(theme: PresentationTheme) -> UIImage? {
|
||||
let imageName: String
|
||||
switch self {
|
||||
case .sendWithoutSound:
|
||||
imageName = "Chat/Input/Menu/SilentIcon"
|
||||
case .schedule:
|
||||
imageName = "Chat/Input/Menu/ScheduleIcon"
|
||||
case .sendWithoutSound:
|
||||
imageName = "Chat/Input/Menu/SilentIcon"
|
||||
case .sendWhenOnline:
|
||||
imageName = "Chat/Input/Menu/WhenOnlineIcon"
|
||||
case .schedule:
|
||||
imageName = "Chat/Input/Menu/ScheduleIcon"
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
||||
}
|
||||
@ -191,7 +194,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
|
||||
private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, hasEntityKeyboard: Bool, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
|
||||
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, canSendWhenOnline: Bool, forwardedCount: Int?, hasEntityKeyboard: Bool, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, send: (() -> Void)?, sendSilently: (() -> Void)?, sendWhenOnline: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.sourceSendButton = sourceSendButton
|
||||
@ -249,6 +252,11 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: self.presentationData.strings.Conversation_SendMessage_SendSilently, icon: .sendWithoutSound, hasSeparator: true, action: {
|
||||
sendSilently?()
|
||||
}))
|
||||
if canSendWhenOnline {
|
||||
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: self.presentationData.strings.Conversation_SendMessage_SendWhenOnline, icon: .sendWhenOnline, hasSeparator: true, action: {
|
||||
sendWhenOnline?()
|
||||
}))
|
||||
}
|
||||
}
|
||||
if let _ = schedule {
|
||||
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: reminders ? self.presentationData.strings.Conversation_SendMessage_SetReminder: self.presentationData.strings.Conversation_SendMessage_ScheduleMessage, icon: .schedule, hasSeparator: false, action: {
|
||||
|
@ -536,7 +536,7 @@ private final class CreatePollContext: AttachmentMediaPickerContext {
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
@ -558,6 +558,44 @@ public class CreatePollControllerImpl: ItemListController, AttachmentContainable
|
||||
public var mediaPickerContext: AttachmentMediaPickerContext? {
|
||||
return CreatePollContext()
|
||||
}
|
||||
|
||||
fileprivate var stateValue: Atomic<CreatePollControllerState>?
|
||||
|
||||
private var hasContent: Bool {
|
||||
if let stateValue {
|
||||
let state = stateValue.with { $0 }
|
||||
var hasNonEmptyOptions = false
|
||||
for i in 0 ..< state.options.count {
|
||||
let optionText = state.options[i].item.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !optionText.isEmpty {
|
||||
hasNonEmptyOptions = true
|
||||
}
|
||||
}
|
||||
if hasNonEmptyOptions || !state.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var context: AccountContext?
|
||||
public func requestDismiss(completion: @escaping () -> Void) {
|
||||
if self.hasContent, let context = self.context {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.present(textAlertController(context: context, updatedPresentationData: nil, title: nil, text: presentationData.strings.CreatePoll_CancelConfirmation, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_No, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: {
|
||||
completion()
|
||||
})]), in: .window(.root))
|
||||
} else {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
public func shouldDismissImmediately() -> Bool {
|
||||
return !self.hasContent
|
||||
}
|
||||
}
|
||||
|
||||
public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> CreatePollControllerImpl {
|
||||
@ -579,7 +617,6 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
||||
var ensureSolutionVisibleImpl: (() -> Void)?
|
||||
var ensureQuestionVisibleImpl: (() -> Void)?
|
||||
var displayQuizTooltipImpl: ((Bool) -> Void)?
|
||||
var attemptNavigationImpl: (() -> Bool)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
@ -923,9 +960,7 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
||||
})
|
||||
|
||||
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
||||
if let attemptNavigationImpl = attemptNavigationImpl, attemptNavigationImpl() {
|
||||
dismissImpl?()
|
||||
}
|
||||
dismissImpl?()
|
||||
})
|
||||
|
||||
let optionIds = state.options.map { $0.item.id }
|
||||
@ -966,6 +1001,8 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
||||
|
||||
weak var currentTooltipController: TooltipController?
|
||||
let controller = CreatePollControllerImpl(context: context, state: signal)
|
||||
controller.context = context
|
||||
controller.stateValue = stateValue
|
||||
controller.navigationPresentation = .modal
|
||||
controller.visibleBottomContentOffsetChanged = { [weak controller] _ in
|
||||
controller?.updateTabBarAlpha(1.0, .immediate)
|
||||
@ -1193,31 +1230,6 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
||||
|
||||
return .single(didReorder)
|
||||
})
|
||||
attemptNavigationImpl = {
|
||||
let state = stateValue.with { $0 }
|
||||
var hasNonEmptyOptions = false
|
||||
for i in 0 ..< state.options.count {
|
||||
let optionText = state.options[i].item.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !optionText.isEmpty {
|
||||
hasNonEmptyOptions = true
|
||||
}
|
||||
}
|
||||
if hasNonEmptyOptions || !state.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.CreatePoll_CancelConfirmation, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_No, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: {
|
||||
dismissImpl?()
|
||||
})]), nil)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
controller.attemptNavigation = { _ in
|
||||
if let attemptNavigationImpl = attemptNavigationImpl, attemptNavigationImpl() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
dismissInputImpl = { [weak controller] in
|
||||
controller?.view.endEditing(true)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public final class TextAlertContentActionNode: HighlightableButtonNode {
|
||||
|
||||
private let backgroundNode: ASDisplayNode
|
||||
|
||||
var highlightedUpdated: (Bool) -> Void = { _ in }
|
||||
public var highlightedUpdated: (Bool) -> Void = { _ in }
|
||||
|
||||
public init(theme: AlertControllerTheme, action: TextAlertAction) {
|
||||
self.theme = theme
|
||||
@ -68,13 +68,13 @@ public final class TextAlertContentActionNode: HighlightableButtonNode {
|
||||
})
|
||||
}
|
||||
|
||||
func performAction() {
|
||||
public func performAction() {
|
||||
if self.actionEnabled {
|
||||
self.action.action()
|
||||
}
|
||||
}
|
||||
|
||||
func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
||||
public func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
||||
self.highlightedUpdated(highlighted)
|
||||
if highlighted {
|
||||
if self.backgroundNode.supernode == nil {
|
||||
|
@ -336,6 +336,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
self.textNode = ImmediateTextNodeWithEntities()
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.linkHighlightColor = UIColor(rgb: 0x5ac8fa, alpha: 0.2)
|
||||
self.textNode.displaySpoilerEffect = false
|
||||
|
||||
self.authorNameNode = ASTextNode()
|
||||
self.authorNameNode.maximumNumberOfLines = 1
|
||||
@ -802,6 +803,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
if let textLayout = self.textNode.cachedLayout, !textLayout.spoilers.isEmpty {
|
||||
if self.spoilerTextNode == nil {
|
||||
let spoilerTextNode = ImmediateTextNodeWithEntities()
|
||||
spoilerTextNode.displaySpoilerEffect = false
|
||||
spoilerTextNode.attributedText = textNode.attributedText
|
||||
spoilerTextNode.maximumNumberOfLines = 0
|
||||
spoilerTextNode.linkHighlightColor = UIColor(rgb: 0x5ac8fa, alpha: 0.2)
|
||||
|
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Schedule.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Schedule.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "schedule.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
97
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Schedule.imageset/schedule.pdf
vendored
Normal file
97
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Schedule.imageset/schedule.pdf
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.334961 3.334961 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
8.000000 16.665077 m
|
||||
8.000000 17.032347 8.297730 17.330078 8.665000 17.330078 c
|
||||
13.450547 17.330078 17.330002 13.450625 17.330002 8.665078 c
|
||||
17.330002 3.879531 13.450547 0.000076 8.665000 0.000076 c
|
||||
3.879452 0.000076 0.000000 3.879531 0.000000 8.665078 c
|
||||
0.000000 11.755159 1.617408 14.466341 4.050117 16.000078 c
|
||||
2.165000 16.000078 l
|
||||
1.797731 16.000078 1.500000 16.297810 1.500000 16.665077 c
|
||||
1.500000 17.032347 1.797731 17.330078 2.165000 17.330078 c
|
||||
5.665000 17.330078 l
|
||||
6.032269 17.330078 6.330000 17.032347 6.330000 16.665077 c
|
||||
6.330000 13.165078 l
|
||||
6.330000 12.797809 6.032269 12.500078 5.665000 12.500078 c
|
||||
5.297730 12.500078 5.000000 12.797809 5.000000 13.165078 c
|
||||
5.000000 15.020401 l
|
||||
2.805339 13.751994 1.330000 11.380217 1.330000 8.665078 c
|
||||
1.330000 4.614069 4.613991 1.330078 8.665000 1.330078 c
|
||||
12.716009 1.330078 16.000000 4.614069 16.000000 8.665078 c
|
||||
16.000000 12.716087 12.716009 16.000078 8.665000 16.000078 c
|
||||
8.297730 16.000078 8.000000 16.297810 8.000000 16.665077 c
|
||||
h
|
||||
8.665000 14.330078 m
|
||||
9.032269 14.330078 9.330000 14.032348 9.330000 13.665078 c
|
||||
9.330000 8.940530 l
|
||||
12.135226 6.135303 l
|
||||
12.394924 5.875606 12.394924 5.454551 12.135226 5.194852 c
|
||||
11.875527 4.935153 11.454473 4.935153 11.194774 5.194852 c
|
||||
8.194774 8.194853 l
|
||||
8.070063 8.319564 8.000000 8.488708 8.000000 8.665078 c
|
||||
8.000000 13.665078 l
|
||||
8.000000 14.032348 8.297730 14.330078 8.665000 14.330078 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1511
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001601 00000 n
|
||||
0000001624 00000 n
|
||||
0000001797 00000 n
|
||||
0000001871 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1930
|
||||
%%EOF
|
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Silently.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Silently.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "sendwithoutsound.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
154
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Silently.imageset/sendwithoutsound.pdf
vendored
Normal file
154
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Silently.imageset/sendwithoutsound.pdf
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.334961 3.205078 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
1.135226 17.265186 m
|
||||
0.875527 17.524885 0.454473 17.524885 0.194774 17.265186 c
|
||||
-0.064925 17.005487 -0.064925 16.584435 0.194774 16.324736 c
|
||||
16.194775 0.324734 l
|
||||
16.454473 0.065035 16.875528 0.065035 17.135227 0.324734 c
|
||||
17.394926 0.584433 17.394926 1.005487 17.135227 1.265186 c
|
||||
12.830019 5.570395 l
|
||||
12.830019 13.984108 l
|
||||
12.830019 14.015735 l
|
||||
12.830019 14.015746 l
|
||||
12.830019 14.015758 l
|
||||
12.830032 14.503190 12.830044 14.912979 12.802612 15.227596 c
|
||||
12.776955 15.521866 12.718998 15.904351 12.465319 16.192924 c
|
||||
12.149200 16.552528 11.677307 16.734966 11.201504 16.681524 c
|
||||
10.819681 16.638639 10.519508 16.394609 10.302576 16.194126 c
|
||||
10.070642 15.979778 9.794991 15.676547 9.467113 15.315862 c
|
||||
9.467100 15.315848 l
|
||||
9.445834 15.292454 l
|
||||
6.911015 12.504154 l
|
||||
6.870810 12.460040 l
|
||||
6.811123 12.459965 l
|
||||
6.165019 12.459965 l
|
||||
6.142232 12.459965 l
|
||||
6.073141 12.459966 6.005919 12.459967 5.940522 12.459891 c
|
||||
1.135226 17.265186 l
|
||||
h
|
||||
7.233788 11.166624 m
|
||||
11.500019 6.900394 l
|
||||
11.500019 13.984108 l
|
||||
11.500019 14.511556 11.499405 14.862436 11.477638 15.112073 c
|
||||
11.466372 15.241299 11.451292 15.307571 11.443966 15.335192 c
|
||||
11.425201 15.348718 11.403254 15.357203 11.380270 15.359817 c
|
||||
11.356270 15.344307 11.300531 15.305413 11.205269 15.217373 c
|
||||
11.021238 15.047297 10.784756 14.788080 10.429955 14.397799 c
|
||||
7.895135 11.609499 l
|
||||
7.876595 11.588985 l
|
||||
7.810806 11.515999 7.711236 11.405536 7.585287 11.322461 c
|
||||
7.477557 11.251403 7.358773 11.198743 7.233788 11.166624 c
|
||||
h
|
||||
3.310589 11.708942 m
|
||||
4.251275 10.768256 l
|
||||
4.114416 10.639768 4.004863 10.482624 3.931640 10.305847 c
|
||||
3.894677 10.216611 3.864227 10.089064 3.847507 9.844008 c
|
||||
3.830379 9.592980 3.830019 9.270005 3.830019 8.794965 c
|
||||
3.830019 8.319924 3.830379 7.996948 3.847507 7.745921 c
|
||||
3.864227 7.500866 3.894677 7.373319 3.931640 7.284082 c
|
||||
4.067134 6.956970 4.327024 6.697080 4.654137 6.561585 c
|
||||
4.743373 6.524623 4.870920 6.494172 5.115975 6.477452 c
|
||||
5.367003 6.460325 5.689979 6.459965 6.165019 6.459965 c
|
||||
6.811123 6.459965 l
|
||||
6.838768 6.460045 l
|
||||
6.838777 6.460045 l
|
||||
6.937038 6.460461 7.085750 6.461090 7.231940 6.423779 c
|
||||
7.357602 6.391706 7.477026 6.338876 7.585287 6.267468 c
|
||||
7.711238 6.184393 7.810808 6.073929 7.876598 6.000941 c
|
||||
7.895135 5.980431 l
|
||||
10.429956 3.192128 l
|
||||
10.784757 2.801847 11.021239 2.542631 11.205269 2.372556 c
|
||||
11.300533 2.284515 11.356270 2.245622 11.380270 2.230112 c
|
||||
11.403254 2.232725 11.425201 2.241211 11.443966 2.254738 c
|
||||
11.451292 2.282358 11.466372 2.348630 11.477638 2.477856 c
|
||||
11.498196 2.713622 11.499886 3.039693 11.500010 3.519522 c
|
||||
12.789057 2.230474 l
|
||||
12.756243 1.960018 12.682525 1.644088 12.465319 1.397003 c
|
||||
12.149200 1.037399 11.677307 0.854963 11.201504 0.908403 c
|
||||
10.819681 0.951288 10.519508 1.195318 10.302577 1.395802 c
|
||||
10.070659 1.610135 9.795034 1.913337 9.467189 2.273985 c
|
||||
9.467137 2.274039 l
|
||||
9.467128 2.274051 l
|
||||
9.445836 2.297473 l
|
||||
6.911015 5.085775 l
|
||||
6.870807 5.129889 l
|
||||
6.811123 5.129965 l
|
||||
6.165019 5.129965 l
|
||||
6.142203 5.129965 l
|
||||
6.142138 5.129965 l
|
||||
5.695606 5.129959 5.327103 5.129954 5.025440 5.150537 c
|
||||
4.712668 5.171878 4.423473 5.217547 4.145168 5.332826 c
|
||||
3.492168 5.603307 2.973362 6.122113 2.702880 6.775113 c
|
||||
2.587602 7.053419 2.541932 7.342614 2.520592 7.655386 c
|
||||
2.500008 7.957066 2.500013 8.325591 2.500019 8.772156 c
|
||||
2.500019 8.772170 l
|
||||
2.500019 8.794965 l
|
||||
2.500019 8.817760 l
|
||||
2.500019 8.817774 l
|
||||
2.500013 9.264338 2.500008 9.632866 2.520592 9.934544 c
|
||||
2.541932 10.247315 2.587602 10.536510 2.702880 10.814816 c
|
||||
2.843596 11.154535 3.051523 11.457933 3.310589 11.708942 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
3618
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000003708 00000 n
|
||||
0000003731 00000 n
|
||||
0000003904 00000 n
|
||||
0000003978 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4037
|
||||
%%EOF
|
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/WhenOnline.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/WhenOnline.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "sendthenonline.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
123
submodules/LegacyComponents/LegacyImages.xcassets/Editor/WhenOnline.imageset/sendthenonline.pdf
vendored
Normal file
123
submodules/LegacyComponents/LegacyImages.xcassets/Editor/WhenOnline.imageset/sendthenonline.pdf
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 15.000000 4.000000 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
5.000000 2.500000 m
|
||||
5.000000 1.119288 3.880712 0.000000 2.500000 0.000000 c
|
||||
1.119288 0.000000 0.000000 1.119288 0.000000 2.500000 c
|
||||
0.000000 3.880712 1.119288 5.000000 2.500000 5.000000 c
|
||||
3.880712 5.000000 5.000000 3.880712 5.000000 2.500000 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.334961 3.334961 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
1.330000 8.665078 m
|
||||
1.330000 12.716087 4.613991 16.000078 8.665000 16.000078 c
|
||||
12.716008 16.000078 16.000000 12.716087 16.000000 8.665078 c
|
||||
16.000000 7.971566 15.903754 7.300534 15.723890 6.664610 c
|
||||
16.154043 6.472708 16.542303 6.203824 16.871166 5.875466 c
|
||||
17.168650 6.750837 17.330002 7.689115 17.330002 8.665078 c
|
||||
17.330002 13.450625 13.450547 17.330078 8.665000 17.330078 c
|
||||
3.879453 17.330078 0.000000 13.450625 0.000000 8.665078 c
|
||||
0.000000 3.879531 3.879453 0.000076 8.665000 0.000076 c
|
||||
9.641031 0.000076 10.579370 0.161449 11.454794 0.458973 c
|
||||
11.126430 0.787828 10.857537 1.176086 10.665626 1.606233 c
|
||||
10.029655 1.426340 9.358569 1.330078 8.665000 1.330078 c
|
||||
6.949595 1.330078 5.371725 1.918934 4.122502 2.905533 c
|
||||
4.297272 3.127586 4.536829 3.393646 4.847776 3.660172 c
|
||||
5.621715 4.323548 6.847626 5.000078 8.665000 5.000078 c
|
||||
9.428206 5.000078 10.087104 4.880767 10.652022 4.693223 c
|
||||
10.837114 5.118156 11.097044 5.502989 11.415169 5.831069 c
|
||||
10.648278 6.131837 9.735907 6.330078 8.665000 6.330078 c
|
||||
6.482374 6.330078 4.958285 5.506608 3.982224 4.669984 c
|
||||
3.639743 4.376429 3.365922 4.082502 3.154341 3.823979 c
|
||||
2.018686 5.115683 1.330000 6.809955 1.330000 8.665078 c
|
||||
h
|
||||
12.678360 5.175269 m
|
||||
12.317028 4.907584 12.030398 4.544794 11.855478 4.123891 c
|
||||
12.090899 3.974664 12.299200 3.817050 12.482224 3.660172 c
|
||||
12.793171 3.393646 13.032728 3.127586 13.207498 2.905533 c
|
||||
12.806664 2.588965 12.371993 2.313348 11.909800 2.084994 c
|
||||
12.111738 1.664135 12.428010 1.308554 12.818370 1.058498 c
|
||||
14.273650 1.854803 15.475398 3.056577 16.271671 4.511877 c
|
||||
16.021608 4.902231 15.666019 5.218495 15.245155 5.420424 c
|
||||
14.958824 4.840852 14.598176 4.304554 14.175659 3.823979 c
|
||||
13.964078 4.082502 13.690256 4.376430 13.347776 4.669984 c
|
||||
13.147928 4.841282 12.925106 5.012029 12.678360 5.175269 c
|
||||
h
|
||||
6.830039 10.665039 m
|
||||
6.830039 11.678482 7.651597 12.500039 8.665039 12.500039 c
|
||||
9.678482 12.500039 10.500039 11.678482 10.500039 10.665039 c
|
||||
10.500039 9.651596 9.678482 8.830039 8.665039 8.830039 c
|
||||
7.651597 8.830039 6.830039 9.651596 6.830039 10.665039 c
|
||||
h
|
||||
8.665039 13.830039 m
|
||||
6.917058 13.830039 5.500039 12.413020 5.500039 10.665039 c
|
||||
5.500039 8.917058 6.917058 7.500039 8.665039 7.500039 c
|
||||
10.413020 7.500039 11.830039 8.917058 11.830039 10.665039 c
|
||||
11.830039 12.413020 10.413020 13.830039 8.665039 13.830039 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
2777
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000002867 00000 n
|
||||
0000002890 00000 n
|
||||
0000003063 00000 n
|
||||
0000003137 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
3196
|
||||
%%EOF
|
@ -95,7 +95,7 @@ typedef enum
|
||||
- (UIBarButtonItem *)leftBarButtonItem;
|
||||
- (UIBarButtonItem *)rightBarButtonItem;
|
||||
|
||||
- (void)send:(bool)silently;
|
||||
- (void)send:(bool)silently whenOnline:(bool)whenOnline;
|
||||
- (void)schedule:(bool)schedule;
|
||||
|
||||
- (NSArray *)resultSignalsWithCurrentItem:(TGMediaAsset *)currentItem descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *, NSString *))descriptionGenerator;
|
||||
|
@ -6,10 +6,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@property (nonatomic, copy) void (^send)(void);
|
||||
@property (nonatomic, copy) void (^sendSilently)(void);
|
||||
@property (nonatomic, copy) void (^sendWhenOnline)(void);
|
||||
@property (nonatomic, copy) void (^schedule)(void);
|
||||
@property (nonatomic, copy) void (^sendWithTimer)(void);
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context isDark:(bool)isDark sendButtonFrame:(CGRect)sendButtonFrame canSendSilently:(bool)canSendSilently canSchedule:(bool)canSchedule reminder:(bool)reminder hasTimer:(bool)hasTimer;
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context isDark:(bool)isDark sendButtonFrame:(CGRect)sendButtonFrame canSendSilently:(bool)canSendSilently canSendWhenOnline:(bool)canSendWhenOnline canSchedule:(bool)canSchedule reminder:(bool)reminder hasTimer:(bool)hasTimer;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -1568,7 +1568,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
}
|
||||
}
|
||||
|
||||
TGMediaPickerSendActionSheetController *controller = [[TGMediaPickerSendActionSheetController alloc] initWithContext:strongSelf->_context isDark:true sendButtonFrame:strongModel.interfaceView.doneButtonFrame canSendSilently:strongSelf->_hasSilentPosting canSchedule:effectiveHasSchedule reminder:strongSelf->_reminder hasTimer:strongSelf->_hasTimer];
|
||||
TGMediaPickerSendActionSheetController *controller = [[TGMediaPickerSendActionSheetController alloc] initWithContext:strongSelf->_context isDark:true sendButtonFrame:strongModel.interfaceView.doneButtonFrame canSendSilently:strongSelf->_hasSilentPosting canSendWhenOnline:false canSchedule:effectiveHasSchedule reminder:strongSelf->_reminder hasTimer:strongSelf->_hasTimer];
|
||||
controller.send = ^{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
__strong TGMediaPickerGalleryModel *strongModel = weakModel;
|
||||
@ -1621,6 +1621,32 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
|
||||
[strongSelf _dismissTransitionForResultController:strongController];
|
||||
};
|
||||
controller.sendWhenOnline = ^{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
__strong TGMediaPickerGalleryModel *strongModel = weakModel;
|
||||
|
||||
if (strongSelf == nil || strongModel == nil)
|
||||
return;
|
||||
|
||||
__strong TGModernGalleryController *strongController = weakGalleryController;
|
||||
if (strongController == nil)
|
||||
return;
|
||||
|
||||
if ([item isKindOfClass:[TGMediaPickerGalleryVideoItem class]])
|
||||
{
|
||||
TGMediaPickerGalleryVideoItemView *itemView = (TGMediaPickerGalleryVideoItemView *)[strongController itemViewForItem:item];
|
||||
[itemView stop];
|
||||
[itemView setPlayButtonHidden:true animated:true];
|
||||
}
|
||||
|
||||
if (strongSelf->_selectionContext.allowGrouping)
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@(!strongSelf->_selectionContext.grouping) forKey:@"TG_mediaGroupingDisabled_v0"];
|
||||
|
||||
if (strongSelf.finishedWithResults != nil)
|
||||
strongSelf.finishedWithResults(strongController, strongSelf->_selectionContext, strongSelf->_editingContext, item.asset, false, 0x7ffffffe);
|
||||
|
||||
[strongSelf _dismissTransitionForResultController:strongController];
|
||||
};
|
||||
controller.schedule = ^{
|
||||
__strong TGCameraController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
|
@ -1711,9 +1711,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)send:(bool)silently
|
||||
- (void)send:(bool)silently whenOnline:(bool)whenOnlne
|
||||
{
|
||||
[self completeWithCurrentItem:nil silentPosting:silently scheduleTime:0];
|
||||
[self completeWithCurrentItem:nil silentPosting:silently scheduleTime:whenOnlne ? 0x7ffffffe : 0];
|
||||
}
|
||||
|
||||
- (void)schedule:(bool)media {
|
||||
|
@ -165,7 +165,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
TGMediaPickerSendActionSheetController *controller = [[TGMediaPickerSendActionSheetController alloc] initWithContext:strongSelf->_context isDark:true sendButtonFrame:strongSelf.galleryModel.interfaceView.doneButtonFrame canSendSilently:hasSilentPosting canSchedule:effectiveHasSchedule reminder:reminder hasTimer:hasTimer];
|
||||
TGMediaPickerSendActionSheetController *controller = [[TGMediaPickerSendActionSheetController alloc] initWithContext:strongSelf->_context isDark:true sendButtonFrame:strongSelf.galleryModel.interfaceView.doneButtonFrame canSendSilently:hasSilentPosting canSendWhenOnline:true canSchedule:effectiveHasSchedule reminder:reminder hasTimer:hasTimer];
|
||||
controller.send = ^{
|
||||
__strong TGMediaPickerModernGalleryMixin *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
@ -186,6 +186,16 @@
|
||||
if (strongSelf.completeWithItem != nil)
|
||||
strongSelf.completeWithItem(item, true, 0);
|
||||
};
|
||||
controller.sendWhenOnline = ^{
|
||||
__strong TGMediaPickerModernGalleryMixin *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
strongSelf->_galleryModel.dismiss(true, false);
|
||||
|
||||
if (strongSelf.completeWithItem != nil)
|
||||
strongSelf.completeWithItem(item, false, 0x7ffffffe);
|
||||
};
|
||||
controller.schedule = ^{
|
||||
__strong TGMediaPickerModernGalleryMixin *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
|
@ -105,6 +105,7 @@
|
||||
bool _isDark;
|
||||
CGRect _sendButtonFrame;
|
||||
bool _canSendSilently;
|
||||
bool _canSendWhenOnline;
|
||||
bool _canSchedule;
|
||||
bool _reminder;
|
||||
bool _hasTimer;
|
||||
@ -117,6 +118,7 @@
|
||||
UIView *_containerView;
|
||||
UIView *_separatorView;
|
||||
TGMediaPickerSendActionSheetItemView *_sendSilentlyButton;
|
||||
TGMediaPickerSendActionSheetItemView *_sendWhenOnlineButton;
|
||||
TGMediaPickerSendActionSheetItemView *_scheduleButton;
|
||||
TGMediaPickerSendActionSheetItemView *_timerButton;
|
||||
}
|
||||
@ -124,13 +126,14 @@
|
||||
|
||||
@implementation TGMediaPickerSendActionSheetController
|
||||
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context isDark:(bool)isDark sendButtonFrame:(CGRect)sendButtonFrame canSendSilently:(bool)canSendSilently canSchedule:(bool)canSchedule reminder:(bool)reminder hasTimer:(bool)hasTimer {
|
||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context isDark:(bool)isDark sendButtonFrame:(CGRect)sendButtonFrame canSendSilently:(bool)canSendSilently canSendWhenOnline:(bool)canSendWhenOnline canSchedule:(bool)canSchedule reminder:(bool)reminder hasTimer:(bool)hasTimer {
|
||||
self = [super initWithContext:context];
|
||||
if (self != nil) {
|
||||
_context = context;
|
||||
_isDark = isDark;
|
||||
_sendButtonFrame = sendButtonFrame;
|
||||
_canSendSilently = canSendSilently;
|
||||
_canSendWhenOnline = canSendWhenOnline;
|
||||
_canSchedule = canSchedule;
|
||||
_reminder = reminder;
|
||||
_hasTimer = hasTimer;
|
||||
@ -163,7 +166,7 @@
|
||||
|
||||
__weak TGMediaPickerSendActionSheetController *weakSelf = self;
|
||||
if (_canSendSilently) {
|
||||
_sendSilentlyButton = [[TGMediaPickerSendActionSheetItemView alloc] initWithTitle:TGLocalized(@"Conversation.SendMessage.SendSilently") icon:TGComponentsImageNamed(@"MediaMute") isDark:_isDark isLast:!_canSchedule && !_hasTimer];
|
||||
_sendSilentlyButton = [[TGMediaPickerSendActionSheetItemView alloc] initWithTitle:TGLocalized(@"Conversation.SendMessage.SendSilently") icon:TGComponentsImageNamed(@"Editor/Silently") isDark:_isDark isLast:!_canSchedule && !_hasTimer && !_canSendWhenOnline];
|
||||
_sendSilentlyButton.pressed = ^{
|
||||
__strong TGMediaPickerSendActionSheetController *strongSelf = weakSelf;
|
||||
[strongSelf sendSilentlyPressed];
|
||||
@ -171,8 +174,17 @@
|
||||
[_containerView addSubview:_sendSilentlyButton];
|
||||
}
|
||||
|
||||
if (_canSendWhenOnline) {
|
||||
_sendWhenOnlineButton = [[TGMediaPickerSendActionSheetItemView alloc] initWithTitle:TGLocalized(@"Conversation.SendMessage.SendWhenOnline") icon:TGComponentsImageNamed(@"Editor/WhenOnline") isDark:_isDark isLast:!_canSchedule && !_hasTimer];
|
||||
_sendWhenOnlineButton.pressed = ^{
|
||||
__strong TGMediaPickerSendActionSheetController *strongSelf = weakSelf;
|
||||
[strongSelf sendWhenOnlinePressed];
|
||||
};
|
||||
[_containerView addSubview:_sendWhenOnlineButton];
|
||||
}
|
||||
|
||||
if (_canSchedule) {
|
||||
_scheduleButton = [[TGMediaPickerSendActionSheetItemView alloc] initWithTitle:TGLocalized(_reminder ? @"Conversation.SendMessage.SetReminder" : @"Conversation.SendMessage.ScheduleMessage") icon:TGComponentsImageNamed(@"MediaSchedule") isDark:_isDark isLast:!_hasTimer];
|
||||
_scheduleButton = [[TGMediaPickerSendActionSheetItemView alloc] initWithTitle:TGLocalized(_reminder ? @"Conversation.SendMessage.SetReminder" : @"Conversation.SendMessage.ScheduleMessage") icon:TGComponentsImageNamed(@"Editor/Schedule") isDark:_isDark isLast:!_hasTimer];
|
||||
_scheduleButton.pressed = ^{
|
||||
__strong TGMediaPickerSendActionSheetController *strongSelf = weakSelf;
|
||||
[strongSelf schedulePressed];
|
||||
@ -295,8 +307,8 @@
|
||||
|
||||
CGFloat itemHeight = 44.0;
|
||||
CGFloat containerWidth = 240.0;
|
||||
CGFloat containerHeight = (_canSendSilently + _canSchedule + _hasTimer) * itemHeight;
|
||||
containerWidth = MAX(containerWidth, MAX(_timerButton.buttonLabel.frame.size.width, MAX(_sendSilentlyButton.buttonLabel.frame.size.width, _scheduleButton.buttonLabel.frame.size.width)) + 84.0);
|
||||
CGFloat containerHeight = (_canSendSilently + _canSchedule + _hasTimer + _canSendWhenOnline) * itemHeight;
|
||||
containerWidth = MAX(containerWidth, MAX(_timerButton.buttonLabel.frame.size.width, MAX(_sendSilentlyButton.buttonLabel.frame.size.width, MAX(_sendWhenOnlineButton.buttonLabel.frame.size.width, _scheduleButton.buttonLabel.frame.size.width))) + 84.0);
|
||||
if (!_dismissed) {
|
||||
_containerView.frame = CGRectMake(CGRectGetMaxX(_sendButtonFrame) - containerWidth - 8.0, _sendButtonFrame.origin.y - containerHeight - 4.0, containerWidth, containerHeight);
|
||||
}
|
||||
@ -305,6 +317,9 @@
|
||||
_sendSilentlyButton.frame = CGRectMake(0.0, offset, containerWidth, itemHeight);
|
||||
offset += _sendSilentlyButton.frame.size.height;
|
||||
|
||||
_sendWhenOnlineButton.frame = CGRectMake(0.0, offset, containerWidth, itemHeight);
|
||||
offset += _sendWhenOnlineButton.frame.size.height;
|
||||
|
||||
_scheduleButton.frame = CGRectMake(0.0, offset, containerWidth, itemHeight);
|
||||
offset += _scheduleButton.frame.size.height;
|
||||
|
||||
@ -327,6 +342,14 @@
|
||||
self.sendSilently();
|
||||
}
|
||||
|
||||
- (void)sendWhenOnlinePressed {
|
||||
[self animateOut:false];
|
||||
|
||||
if (self.sendWhenOnline != nil)
|
||||
self.sendWhenOnline();
|
||||
}
|
||||
|
||||
|
||||
- (void)schedulePressed {
|
||||
[self animateOut:false];
|
||||
|
||||
|
@ -776,7 +776,7 @@ typedef enum
|
||||
[_generator impactOccurred];
|
||||
}
|
||||
|
||||
TGMediaPickerSendActionSheetController *controller = [[TGMediaPickerSendActionSheetController alloc] initWithContext:_context isDark:self.pallete.isDark sendButtonFrame:[_controlsView convertRect:[_controlsView frameForSendButton] toView:nil] canSendSilently:_canSendSilently canSchedule:_canSchedule reminder:_reminder hasTimer:false];
|
||||
TGMediaPickerSendActionSheetController *controller = [[TGMediaPickerSendActionSheetController alloc] initWithContext:_context isDark:self.pallete.isDark sendButtonFrame:[_controlsView convertRect:[_controlsView frameForSendButton] toView:nil] canSendSilently:_canSendSilently canSendWhenOnline:false canSchedule:_canSchedule reminder:_reminder hasTimer:false];
|
||||
__weak TGVideoMessageCaptureController *weakSelf = self;
|
||||
controller.send = ^{
|
||||
__strong TGVideoMessageCaptureController *strongSelf = weakSelf;
|
||||
@ -800,6 +800,17 @@ typedef enum
|
||||
_automaticDismiss = true;
|
||||
[strongSelf dismiss:false];
|
||||
};
|
||||
controller.sendWhenOnline = ^{
|
||||
__strong TGVideoMessageCaptureController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[strongSelf finishWithURL:strongSelf->_url dimensions:CGSizeMake(240.0f, 240.0f) duration:strongSelf->_duration liveUploadData:strongSelf->_liveUploadData thumbnailImage:strongSelf->_thumbnailImage isSilent:false scheduleTimestamp:0x7ffffffe];
|
||||
|
||||
_automaticDismiss = true;
|
||||
[strongSelf dismiss:false];
|
||||
};
|
||||
controller.schedule = ^{
|
||||
__strong TGVideoMessageCaptureController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
|
@ -105,8 +105,8 @@ public class LegacyAssetPickerContext: AttachmentMediaPickerContext {
|
||||
self.controller?.editingContext.setForcedCaption(caption, skipUpdate: true)
|
||||
}
|
||||
|
||||
public func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
self.controller?.send(silently)
|
||||
public func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
self.controller?.send(mode == .silently, whenOnline: mode == .whenOnline)
|
||||
}
|
||||
|
||||
public func schedule() {
|
||||
|
@ -389,7 +389,7 @@ private final class LocationPickerContext: AttachmentMediaPickerContext {
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
|
@ -236,52 +236,82 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
let sheetController = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: hasTimer)
|
||||
let dismissImpl = { [weak model] in
|
||||
model?.dismiss(true, false)
|
||||
dismissAll()
|
||||
}
|
||||
sheetController.send = {
|
||||
completed(item.asset, false, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.sendSilently = {
|
||||
completed(item.asset, true, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.schedule = {
|
||||
presentSchedulePicker(true, { time in
|
||||
completed(item.asset, false, time, {
|
||||
dismissImpl()
|
||||
})
|
||||
})
|
||||
}
|
||||
sheetController.sendWithTimer = {
|
||||
presentTimerPicker { time in
|
||||
var items = selectionContext.selectedItems() ?? []
|
||||
items.append(item.asset as Any)
|
||||
|
||||
for case let item as TGMediaEditableItem in items {
|
||||
editingContext?.setTimer(time as NSNumber, for: item)
|
||||
|
||||
let sendWhenOnlineAvailable: Signal<Bool, NoError>
|
||||
if let peer {
|
||||
sendWhenOnlineAvailable = context.account.viewTracker.peerView(peer.id)
|
||||
|> take(1)
|
||||
|> map { peerView -> Bool in
|
||||
guard let peer = peerViewMainPeer(peerView) else {
|
||||
return false
|
||||
}
|
||||
|
||||
var sendWhenOnlineAvailable = false
|
||||
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case .present = presence.status {
|
||||
sendWhenOnlineAvailable = true
|
||||
}
|
||||
if peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id._internalGetInt64Value() == 777000 {
|
||||
sendWhenOnlineAvailable = false
|
||||
}
|
||||
return sendWhenOnlineAvailable
|
||||
}
|
||||
} else {
|
||||
sendWhenOnlineAvailable = .single(false)
|
||||
}
|
||||
|
||||
let _ = (sendWhenOnlineAvailable
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sendWhenOnlineAvailable in
|
||||
let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
let sheetController = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSendWhenOnline: sendWhenOnlineAvailable, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: hasTimer)
|
||||
let dismissImpl = { [weak model] in
|
||||
model?.dismiss(true, false)
|
||||
dismissAll()
|
||||
}
|
||||
sheetController.send = {
|
||||
completed(item.asset, false, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
}
|
||||
sheetController.customDismissBlock = { [weak legacySheetController] in
|
||||
legacySheetController?.dismiss()
|
||||
}
|
||||
legacySheetController.bind(controller: sheetController)
|
||||
present(legacySheetController, nil)
|
||||
|
||||
let hapticFeedback = HapticFeedback()
|
||||
hapticFeedback.impact()
|
||||
sheetController.sendSilently = {
|
||||
completed(item.asset, true, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.sendWhenOnline = {
|
||||
completed(item.asset, false, scheduleWhenOnlineTimestamp, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.schedule = {
|
||||
presentSchedulePicker(true, { time in
|
||||
completed(item.asset, false, time, {
|
||||
dismissImpl()
|
||||
})
|
||||
})
|
||||
}
|
||||
sheetController.sendWithTimer = {
|
||||
presentTimerPicker { time in
|
||||
var items = selectionContext.selectedItems() ?? []
|
||||
items.append(item.asset as Any)
|
||||
|
||||
for case let item as TGMediaEditableItem in items {
|
||||
editingContext?.setTimer(time as NSNumber, for: item)
|
||||
}
|
||||
|
||||
completed(item.asset, false, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
}
|
||||
sheetController.customDismissBlock = { [weak legacySheetController] in
|
||||
legacySheetController?.dismiss()
|
||||
}
|
||||
legacySheetController.bind(controller: sheetController)
|
||||
present(legacySheetController, nil)
|
||||
|
||||
let hapticFeedback = HapticFeedback()
|
||||
hapticFeedback.impact()
|
||||
})
|
||||
}
|
||||
}
|
||||
model.interfaceView.setThumbnailSignalForItem { item in
|
||||
|
@ -408,17 +408,26 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
if let controller = self.controller, case .assets(nil) = controller.subject {
|
||||
let enableAnimations = self.controller?.context.sharedContext.energyUsageSettings.fullTranslucency ?? true
|
||||
|
||||
let cameraView = TGAttachmentCameraView(forSelfPortrait: false, videoModeByDefault: controller.bannedSendPhotos != nil && controller.bannedSendVideos == nil)!
|
||||
cameraView.clipsToBounds = true
|
||||
cameraView.removeCorners()
|
||||
cameraView.pressed = { [weak self] in
|
||||
cameraView.pressed = { [weak self, weak cameraView] in
|
||||
if let strongSelf = self, !strongSelf.openingMedia {
|
||||
strongSelf.dismissInput()
|
||||
strongSelf.controller?.openCamera?(strongSelf.cameraView)
|
||||
|
||||
if !enableAnimations {
|
||||
cameraView?.startPreview()
|
||||
}
|
||||
}
|
||||
}
|
||||
self.cameraView = cameraView
|
||||
cameraView.startPreview()
|
||||
|
||||
if enableAnimations {
|
||||
cameraView.startPreview()
|
||||
}
|
||||
|
||||
self.gridNode.scrollView.addSubview(cameraView)
|
||||
self.gridNode.addSubnode(self.cameraActivateAreaNode)
|
||||
@ -1758,8 +1767,8 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
|
||||
self.interaction?.editingState.setForcedCaption(caption, skipUpdate: true)
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
self.interaction?.sendSelected(nil, silently, nil, true, {})
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
self.interaction?.sendSelected(nil, mode == .silently, mode == .whenOnline ? scheduleWhenOnlineTimestamp : nil, true, {})
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
|
@ -1406,14 +1406,14 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
footerItem = ChannelAdminAddBotFooterItem(theme: presentationData.theme, title: state.adminRights ? presentationData.strings.Bot_AddToChat_Add_AddAsAdmin : presentationData.strings.Bot_AddToChat_Add_AddAsMember, action: {
|
||||
if state.adminRights {
|
||||
let theme = AlertControllerTheme(presentationData: presentationData)
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_AdminAlertTitle, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_AdminAlertTitle, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
let text = isGroup ? presentationData.strings.Bot_AddToChat_Add_AdminAlertTextGroup(peerTitle).string : presentationData.strings.Bot_AddToChat_Add_AdminAlertTextChannel(peerTitle).string
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
|
||||
let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Bot_AddToChat_Add_AdminAlertAdd, action: {
|
||||
rightButtonActionImpl()
|
||||
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
|
@ -559,9 +559,9 @@ private func confirmChannelOwnershipTransferController(context: AccountContext,
|
||||
text = presentationData.strings.Channel_OwnershipTransfer_DescriptionInfo(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
|
||||
let attributedTitle = NSAttributedString(string: title, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor)
|
||||
let attributedTitle = NSAttributedString(string: title, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Channel_OwnershipTransfer_ChangeOwner, action: {
|
||||
@ -575,16 +575,17 @@ func channelOwnershipTransferController(context: AccountContext, updatedPresenta
|
||||
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = AlertControllerTheme(presentationData: presentationData)
|
||||
|
||||
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.medium(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
var text = presentationData.strings.OwnershipTransfer_SecurityRequirements
|
||||
let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0
|
||||
|
||||
var isGroup = true
|
||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
isGroup = false
|
||||
}
|
||||
|
||||
var actions: [TextAlertAction] = []
|
||||
|
||||
switch initialError {
|
||||
case .requestPassword:
|
||||
return confirmChannelOwnershipTransferController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, member: member, present: present, completion: completion)
|
||||
@ -618,8 +619,8 @@ func channelOwnershipTransferController(context: AccountContext, updatedPresenta
|
||||
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
|
||||
}
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
return richTextAlertController(context: context, title: title, text: attributedText, actions: actions)
|
||||
|
@ -966,9 +966,9 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
|
||||
controller.navigationPresentation = .modal
|
||||
controller.setState(.custom(icon: .animation("BroadcastGroup"), title: presentationData.strings.BroadcastGroups_IntroTitle, subtitle: nil, text: presentationData.strings.BroadcastGroups_IntroText, buttonTitle: presentationData.strings.BroadcastGroups_Convert, secondaryButtonTitle: presentationData.strings.BroadcastGroups_Cancel, footerText: nil), animated: false)
|
||||
controller.proceed = { [weak controller] result in
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.medium(17.0), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BroadcastGroups_ConfirmationAlert_Convert, action: { [weak controller] in
|
||||
|
@ -457,6 +457,7 @@ final class PhoneDemoComponent: Component {
|
||||
self.containerView.clipsToBounds = true
|
||||
|
||||
self.phoneView = PhoneView(frame: CGRect(origin: .zero, size: phoneSize))
|
||||
self.phoneView.isUserInteractionEnabled = false
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
|
@ -283,15 +283,18 @@ final class DemoPagerComponent: Component {
|
||||
|
||||
let items: [Item]
|
||||
let index: Int
|
||||
let nextAction: ActionSlot<Void>?
|
||||
let updated: (CGFloat, Int) -> Void
|
||||
|
||||
public init(
|
||||
items: [Item],
|
||||
index: Int = 0,
|
||||
nextAction: ActionSlot<Void>? = nil,
|
||||
updated: @escaping (CGFloat, Int) -> Void
|
||||
) {
|
||||
self.items = items
|
||||
self.index = index
|
||||
self.nextAction = nextAction
|
||||
self.updated = updated
|
||||
}
|
||||
|
||||
@ -346,6 +349,17 @@ final class DemoPagerComponent: Component {
|
||||
func update(component: DemoPagerComponent, availableSize: CGSize, transition: Transition) -> CGSize {
|
||||
var validIds: [AnyHashable] = []
|
||||
|
||||
component.nextAction?.connect { [weak self] in
|
||||
if let self {
|
||||
var nextContentOffset = self.scrollView.contentOffset
|
||||
nextContentOffset.x += self.scrollView.frame.width
|
||||
if nextContentOffset.x >= self.scrollView.contentSize.width {
|
||||
nextContentOffset.x = 0.0
|
||||
}
|
||||
self.scrollView.contentOffset = nextContentOffset
|
||||
}
|
||||
}
|
||||
|
||||
let firstTime = self.itemViews.isEmpty
|
||||
|
||||
let contentSize = CGSize(width: availableSize.width * CGFloat(component.items.count), height: availableSize.height)
|
||||
@ -787,7 +801,8 @@ private final class DemoSheetContent: CombinedComponent {
|
||||
content: AnyComponent(
|
||||
StickersCarouselComponent(
|
||||
context: component.context,
|
||||
stickers: stickers
|
||||
stickers: stickers,
|
||||
tapAction: {}
|
||||
)
|
||||
),
|
||||
title: strings.Premium_Stickers,
|
||||
|
@ -1145,7 +1145,7 @@ private final class PremiumGiftContext: AttachmentMediaPickerContext {
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
|
@ -618,6 +618,8 @@ public class PremiumLimitsListScreen: ViewController {
|
||||
var disposable: Disposable?
|
||||
var promoConfiguration: PremiumPromoConfiguration?
|
||||
|
||||
let nextAction = ActionSlot<Void>()
|
||||
|
||||
init(context: AccountContext, controller: PremiumLimitsListScreen, buttonTitle: String, gloss: Bool) {
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -761,6 +763,8 @@ public class PremiumLimitsListScreen: ViewController {
|
||||
|
||||
self.dim.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
|
||||
|
||||
self.pagerView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.pagerTapGesture(_:))))
|
||||
|
||||
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||
}
|
||||
|
||||
@ -770,6 +774,12 @@ public class PremiumLimitsListScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
@objc func pagerTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.nextAction.invoke(Void())
|
||||
}
|
||||
}
|
||||
|
||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if let layout = self.currentLayout {
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
@ -1067,7 +1077,10 @@ public class PremiumLimitsListScreen: ViewController {
|
||||
content: AnyComponent(
|
||||
StickersCarouselComponent(
|
||||
context: context,
|
||||
stickers: stickers
|
||||
stickers: stickers,
|
||||
tapAction: { [weak self] in
|
||||
self?.nextAction.invoke(Void())
|
||||
}
|
||||
)
|
||||
),
|
||||
title: strings.Premium_Stickers,
|
||||
@ -1224,6 +1237,7 @@ public class PremiumLimitsListScreen: ViewController {
|
||||
DemoPagerComponent(
|
||||
items: items,
|
||||
index: index,
|
||||
nextAction: nextAction,
|
||||
updated: { [weak self] position, count in
|
||||
if let strongSelf = self {
|
||||
strongSelf.footerNode.updatePosition(position, count: count)
|
||||
|
@ -19,13 +19,16 @@ final class StickersCarouselComponent: Component {
|
||||
|
||||
let context: AccountContext
|
||||
let stickers: [TelegramMediaFile]
|
||||
let tapAction: () -> Void
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
stickers: [TelegramMediaFile]
|
||||
stickers: [TelegramMediaFile],
|
||||
tapAction: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.stickers = stickers
|
||||
self.tapAction = tapAction
|
||||
}
|
||||
|
||||
public static func ==(lhs: StickersCarouselComponent, rhs: StickersCarouselComponent) -> Bool {
|
||||
@ -48,7 +51,8 @@ final class StickersCarouselComponent: Component {
|
||||
if self.node == nil && !component.stickers.isEmpty {
|
||||
let node = StickersCarouselNode(
|
||||
context: component.context,
|
||||
stickers: component.stickers
|
||||
stickers: component.stickers,
|
||||
tapAction: component.tapAction
|
||||
)
|
||||
self.node = node
|
||||
self.addSubnode(node)
|
||||
@ -278,6 +282,8 @@ private class StickerNode: ASDisplayNode {
|
||||
private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private let stickers: [TelegramMediaFile]
|
||||
private let tapAction: () -> Void
|
||||
|
||||
private var itemContainerNodes: [ASDisplayNode] = []
|
||||
private var itemNodes: [Int: StickerNode] = [:]
|
||||
private let scrollNode: ASScrollNode
|
||||
@ -296,9 +302,10 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private var previousInteractionTimestamp: Double = 0.0
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
|
||||
init(context: AccountContext, stickers: [TelegramMediaFile]) {
|
||||
init(context: AccountContext, stickers: [TelegramMediaFile], tapAction: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.stickers = stickers
|
||||
self.tapAction = tapAction
|
||||
|
||||
self.scrollNode = ASScrollNode()
|
||||
self.tapNode = ASDisplayNode()
|
||||
@ -335,11 +342,17 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
@objc private func stickerTapped(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||
self.previousInteractionTimestamp = CACurrentMediaTime() + 1.0
|
||||
|
||||
let point = gestureRecognizer.location(in: self.view)
|
||||
let size = self.bounds.size
|
||||
if point.y > size.height / 3.0 && point.y < size.height - size.height / 3.0 {
|
||||
self.tapAction()
|
||||
return
|
||||
}
|
||||
|
||||
guard self.animator == nil, self.scrollStartPosition == nil else {
|
||||
return
|
||||
}
|
||||
|
||||
let point = gestureRecognizer.location(in: self.view)
|
||||
guard let index = self.itemContainerNodes.firstIndex(where: { $0.frame.contains(point) }) else {
|
||||
return
|
||||
}
|
||||
|
@ -31,3 +31,19 @@ public func textAlertController(sharedContext: SharedAccountContext, title: Stri
|
||||
public func richTextAlertController(context: AccountContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController {
|
||||
return richTextAlertController(alertContext: AlertControllerContext(theme: AlertControllerTheme(presentationData: context.sharedContext.currentPresentationData.with { $0 }), themeSignal: context.sharedContext.presentationData |> map { presentationData in AlertControllerTheme(presentationData: presentationData) }), title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissAutomatically: dismissAutomatically)
|
||||
}
|
||||
|
||||
public func textWithEntitiesAlertController(context: AccountContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController {
|
||||
return textWithEntitiesAlertController(
|
||||
alertContext: AlertControllerContext(
|
||||
theme: AlertControllerTheme(presentationData: context.sharedContext.currentPresentationData.with { $0 }),
|
||||
themeSignal: context.sharedContext.presentationData |> map { presentationData in AlertControllerTheme(presentationData: presentationData) }
|
||||
),
|
||||
title: title,
|
||||
text: text,
|
||||
actions: actions,
|
||||
actionLayout: actionLayout,
|
||||
allowInputInset: allowInputInset,
|
||||
dismissAutomatically: dismissAutomatically
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -375,6 +375,16 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
sortedWallpapers = wallpapers.map(\.wallpaper)
|
||||
}
|
||||
|
||||
if let builtinIndex = sortedWallpapers.firstIndex(where: { wallpaper in
|
||||
if case .builtin = wallpaper {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
sortedWallpapers[builtinIndex] = defaultBuiltinWallpaper(data: .legacy, colors: legacyBuiltinWallpaperGradientColors.map(\.rgb))
|
||||
}
|
||||
|
||||
for wallpaper in sortedWallpapers {
|
||||
if case let .file(file) = wallpaper, (wallpaper.isPattern && file.settings.colors.isEmpty) {
|
||||
continue
|
||||
|
@ -697,11 +697,11 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
if node.isHidden {
|
||||
continue
|
||||
}
|
||||
if let result = node.hitTest(point.offsetBy(dx: -nodeFrame.minX, dy: -nodeFrame.minY), with: event) {
|
||||
if let result = node.hitTest(point.offsetBy(dx: -self.headerNode.frame.minX, dy: -self.headerNode.frame.minY).offsetBy(dx: -nodeFrame.minX, dy: -nodeFrame.minY), with: event) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
|
@ -255,9 +255,11 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
guard let strongSelf = self, !strongSelf.isDismissed else {
|
||||
return
|
||||
}
|
||||
if let (layout, _, _, _) = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
return
|
||||
}
|
||||
let contentOffset = strongSelf.gridNode.scrollView.contentOffset
|
||||
let insets = strongSelf.gridNode.scrollView.contentInset
|
||||
|
||||
if contentOffset.y <= -insets.top - 30.0 {
|
||||
strongSelf.isDismissed = true
|
||||
DispatchQueue.main.async {
|
||||
@ -1203,7 +1205,9 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|
||||
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
var insets = layout.insets(options: [.statusBar])
|
||||
if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height {
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
insets.top = 0.0
|
||||
} else if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height {
|
||||
insets.top = 0.0
|
||||
} else {
|
||||
insets.top += 10.0
|
||||
@ -1271,11 +1275,14 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|
||||
let initialRevealedRowCount: CGFloat = 4.5
|
||||
|
||||
let topInset = max(0.0, layout.size.height - floor(initialRevealedRowCount * itemWidth) - insets.top - actionAreaHeight - titleAreaInset)
|
||||
|
||||
let topInset: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
topInset = 0.0
|
||||
} else {
|
||||
topInset = insets.top + max(0.0, layout.size.height - floor(initialRevealedRowCount * itemWidth) - insets.top - actionAreaHeight - titleAreaInset)
|
||||
}
|
||||
let additionalGridBottomInset = max(0.0, gridFrame.size.height - actionAreaHeight - contentHeight)
|
||||
|
||||
let gridInsets = UIEdgeInsets(top: insets.top + topInset, left: gridLeftInset, bottom: actionAreaHeight + additionalGridBottomInset, right: layout.size.width - fillingWidth - gridLeftInset)
|
||||
let gridInsets = UIEdgeInsets(top: topInset, left: gridLeftInset, bottom: actionAreaHeight + additionalGridBottomInset, right: layout.size.width - fillingWidth - gridLeftInset)
|
||||
|
||||
let firstTime = self.validLayout == nil
|
||||
self.validLayout = (layout, gridFrame, titleAreaInset, gridInsets)
|
||||
@ -1354,9 +1361,16 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
self.titleSeparatorNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: max(minBackgroundY, unclippedBackgroundY)), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
var backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: max(minBackgroundY, unclippedBackgroundY)), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
var titleContainerFrame: CGRect
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
backgroundFrame.origin.y = min(0.0, backgroundFrame.origin.y)
|
||||
titleContainerFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((backgroundFrame.width) / 2.0), y: floor((56.0) / 2.0)), size: CGSize())
|
||||
} else {
|
||||
titleContainerFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((backgroundFrame.width) / 2.0), y: backgroundFrame.minY + floor((56.0) / 2.0)), size: CGSize())
|
||||
}
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.titleContainer, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((backgroundFrame.width) / 2.0), y: backgroundFrame.minY + floor((56.0) / 2.0)), size: CGSize()))
|
||||
transition.updateFrame(node: self.titleContainer, frame: titleContainerFrame)
|
||||
transition.updateFrame(node: self.titleSeparatorNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY + 56.0 - UIScreenPixel), size: CGSize(width: backgroundFrame.width, height: UIScreenPixel)))
|
||||
transition.updateFrame(node: self.titleBackgroundnode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.width, height: 56.0)))
|
||||
self.titleBackgroundnode.update(size: CGSize(width: layout.size.width, height: 56.0), transition: .immediate)
|
||||
@ -1427,6 +1441,8 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
private let openMention: (String) -> Void
|
||||
|
||||
private let dimNode: ASDisplayNode
|
||||
private let shadowNode: ASImageNode
|
||||
private let arrowNode: ASImageNode
|
||||
private let containerContainingNode: ASDisplayNode
|
||||
|
||||
private var containers: [Int: StickerPackContainer] = [:]
|
||||
@ -1475,12 +1491,23 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||
self.dimNode.alpha = 0.0
|
||||
|
||||
self.shadowNode = ASImageNode()
|
||||
self.shadowNode.displaysAsynchronously = false
|
||||
self.shadowNode.isUserInteractionEnabled = false
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.isUserInteractionEnabled = false
|
||||
self.arrowNode.image = generateArrowImage(color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
|
||||
self.containerContainingNode = ASDisplayNode()
|
||||
self.containerContainingNode.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.dimNode)
|
||||
|
||||
self.addSubnode(self.shadowNode)
|
||||
self.addSubnode(self.arrowNode)
|
||||
self.addSubnode(self.containerContainingNode)
|
||||
}
|
||||
|
||||
@ -1494,6 +1521,7 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
for (_, container) in self.containers {
|
||||
container.updatePresentationData(presentationData)
|
||||
}
|
||||
self.arrowNode.image = generateArrowImage(color: presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
@ -1502,10 +1530,65 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
self.validLayout = layout
|
||||
|
||||
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
transition.updateFrame(node: self.containerContainingNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
|
||||
let containerContainingFrame: CGRect
|
||||
let containerInsets: UIEdgeInsets
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.01)
|
||||
self.containerContainingNode.cornerRadius = 10.0
|
||||
|
||||
let size = CGSize(width: 390.0, height: min(620.0, layout.size.height - 60.0))
|
||||
var contentRect: CGRect
|
||||
if let sourceRect = self.controller?.getSourceRect?() {
|
||||
let sideSpacing: CGFloat = 10.0
|
||||
let margin: CGFloat = 64.0
|
||||
contentRect = CGRect(origin: CGPoint(x: sourceRect.maxX + sideSpacing, y: floor(sourceRect.midY - size.height / 2.0)), size: size)
|
||||
contentRect.origin.y = min(layout.size.height - margin - size.height - layout.intrinsicInsets.bottom, max(margin, contentRect.origin.y))
|
||||
|
||||
let arrowSize = CGSize(width: 23.0, height: 12.0)
|
||||
let arrowFrame: CGRect
|
||||
if contentRect.maxX > layout.size.width {
|
||||
contentRect.origin.x = sourceRect.minX - size.width - sideSpacing
|
||||
arrowFrame = CGRect(origin: CGPoint(x: contentRect.maxX - (arrowSize.width - arrowSize.height) / 2.0, y: floor(sourceRect.midY - arrowSize.height / 2.0)), size: arrowSize)
|
||||
self.arrowNode.transform = CATransform3DMakeRotation(-.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
} else {
|
||||
arrowFrame = CGRect(origin: CGPoint(x: contentRect.minX - arrowSize.width + (arrowSize.width - arrowSize.height) / 2.0, y: floor(sourceRect.midY - arrowSize.height / 2.0)), size: arrowSize)
|
||||
self.arrowNode.transform = CATransform3DMakeRotation(.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
}
|
||||
|
||||
self.arrowNode.frame = arrowFrame
|
||||
self.arrowNode.isHidden = false
|
||||
|
||||
} else {
|
||||
let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0))
|
||||
let detailWidth = layout.size.width - masterWidth
|
||||
contentRect = CGRect(origin: CGPoint(x: masterWidth + floor((detailWidth - size.width) / 2.0), y: floor((layout.size.height - size.height) / 2.0)), size: size)
|
||||
self.arrowNode.isHidden = true
|
||||
}
|
||||
|
||||
containerContainingFrame = contentRect
|
||||
containerInsets = .zero
|
||||
|
||||
self.shadowNode.alpha = 1.0
|
||||
if self.shadowNode.image == nil {
|
||||
self.shadowNode.image = generateShadowImage()
|
||||
}
|
||||
} else {
|
||||
self.containerContainingNode.cornerRadius = 0.0
|
||||
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||
containerContainingFrame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
containerInsets = layout.intrinsicInsets
|
||||
|
||||
self.arrowNode.isHidden = true
|
||||
self.shadowNode.alpha = 0.0
|
||||
}
|
||||
transition.updateFrame(node: self.containerContainingNode, frame: containerContainingFrame)
|
||||
|
||||
let shadowFrame = containerContainingFrame.insetBy(dx: -60.0, dy: -60.0)
|
||||
transition.updateFrame(node: self.shadowNode, frame: shadowFrame)
|
||||
|
||||
let expandProgress: CGFloat = 1.0
|
||||
|
||||
let scaledInset: CGFloat = 12.0
|
||||
let scaledDistance: CGFloat = 4.0
|
||||
let minScale = (layout.size.width - scaledInset * 2.0) / layout.size.width
|
||||
@ -1593,11 +1676,15 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
self.containers[i] = container
|
||||
}
|
||||
|
||||
let containerFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * layout.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: layout.size)
|
||||
let containerFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * containerContainingFrame.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: containerContainingFrame.size)
|
||||
containerTransition.updateFrame(node: container, frame: containerFrame, beginWithCurrentState: true)
|
||||
containerTransition.updateSublayerTransformScaleAndOffset(node: container, scale: containerScale, offset: CGPoint(), beginWithCurrentState: true)
|
||||
var containerLayout = layout
|
||||
containerLayout.size = containerFrame.size
|
||||
containerLayout.intrinsicInsets = containerInsets
|
||||
|
||||
if container.validLayout?.0 != layout {
|
||||
container.updateLayout(layout: layout, transition: containerTransition)
|
||||
container.updateLayout(layout: containerLayout, transition: containerTransition)
|
||||
}
|
||||
|
||||
if wasAdded {
|
||||
@ -1680,23 +1767,40 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
guard let layout = self.validLayout else {
|
||||
return
|
||||
}
|
||||
self.dimNode.alpha = 1.0
|
||||
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
|
||||
} else {
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
guard let layout = self.validLayout else {
|
||||
return
|
||||
}
|
||||
self.dimNode.alpha = 0.0
|
||||
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
|
||||
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
|
||||
self.modalProgressUpdated(0.0, .animated(duration: 0.2, curve: .easeInOut))
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
self.layer.allowsGroupOpacity = true
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
} else {
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
|
||||
self.modalProgressUpdated(0.0, .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
|
||||
func dismiss() {
|
||||
@ -1782,6 +1886,8 @@ public final class StickerPackScreenImpl: ViewController {
|
||||
public var dismissed: (() -> Void)?
|
||||
public var actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)?
|
||||
|
||||
public var getSourceRect: (() -> CGRect?)?
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override public var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
@ -2032,8 +2138,9 @@ public func StickerPackScreen(
|
||||
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil,
|
||||
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)? = nil,
|
||||
actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)? = nil,
|
||||
dismissed: (() -> Void)? = nil) -> ViewController
|
||||
{
|
||||
dismissed: (() -> Void)? = nil,
|
||||
getSourceRect: (() -> CGRect?)? = nil
|
||||
) -> ViewController {
|
||||
let controller = StickerPackScreenImpl(
|
||||
context: context,
|
||||
stickerPacks: stickerPacks,
|
||||
@ -2045,6 +2152,7 @@ public func StickerPackScreen(
|
||||
actionPerformed: actionPerformed
|
||||
)
|
||||
controller.dismissed = dismissed
|
||||
controller.getSourceRect = getSourceRect
|
||||
return controller
|
||||
}
|
||||
|
||||
@ -2062,3 +2170,34 @@ private final class StickerPackContextReferenceContentSource: ContextReferenceCo
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func generateShadowImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.saveGState()
|
||||
context.setShadow(offset: CGSize(), blur: 60.0, color: UIColor(white: 0.0, alpha: 0.4).cgColor)
|
||||
let path = UIBezierPath(roundedRect: CGRect(x: 60.0, y: 60.0, width: 20.0, height: 20.0), cornerRadius: 10.0).cgPath
|
||||
context.addPath(path)
|
||||
context.fillPath()
|
||||
|
||||
context.restoreGState()
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
context.addPath(path)
|
||||
context.fillPath()
|
||||
})?.stretchableImage(withLeftCapWidth: 70, topCapHeight: 70)
|
||||
}
|
||||
|
||||
private func generateArrowImage(color: UIColor) -> UIImage? {
|
||||
return generateImage(CGSize(width: 23.0, height: 12.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setFillColor(color.cgColor)
|
||||
|
||||
context.translateBy(x: -183.0, y: -209.0)
|
||||
|
||||
try? drawSvgPath(context, path: "M183.219,208.89 H206.781 C205.648,208.89 204.567,209.371 203.808,210.214 L197.23,217.523 C196.038,218.848 193.962,218.848 192.77,217.523 L186.192,210.214 C185.433,209.371 184.352,208.89 183.219,208.89 Z ")
|
||||
})
|
||||
}
|
||||
|
@ -805,6 +805,62 @@ public func verifyLoginEmailSetup(account: UnauthorizedAccount, code: Authorizat
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public enum AuthorizationEmailResetError {
|
||||
case generic
|
||||
case limitExceeded
|
||||
case codeExpired
|
||||
}
|
||||
|
||||
public func resetLoginEmail(account: UnauthorizedAccount, phoneNumber: String, phoneCodeHash: String) -> Signal<Never, AuthorizationEmailResetError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Never, AuthorizationEmailResetError> in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
switch state.contents {
|
||||
case let .confirmationCodeEntry(phoneNumber, _, phoneCodeHash, _, _, syncContacts):
|
||||
return account.network.request(Api.functions.auth.resetLoginEmail(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash), automaticFloodWait: false)
|
||||
|> `catch` { error -> Signal<Api.auth.SentCode, AuthorizationEmailResetError> in
|
||||
let errorDescription = error.errorDescription ?? ""
|
||||
if errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .fail(.limitExceeded)
|
||||
} else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" {
|
||||
return .fail(.codeExpired)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { sentCode -> Signal<Never, AuthorizationEmailResetError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Never, NoError> in
|
||||
switch sentCode {
|
||||
case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout):
|
||||
var parsedNextType: AuthorizationCodeNextType?
|
||||
if let nextType = nextType {
|
||||
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
|
||||
}
|
||||
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts)))
|
||||
|
||||
return .complete()
|
||||
case .sentCodeSuccess:
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|> switchToLatest
|
||||
|> mapError { _ -> AuthorizationEmailResetError in
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
default:
|
||||
return .fail(.generic)
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> AuthorizationEmailResetError in
|
||||
}
|
||||
|> switchToLatest
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func authorizeWithCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, code: AuthorizationCode, termsOfService: UnauthorizedAccountTermsOfService?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> {
|
||||
return account.postbox.transaction { transaction -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
|
@ -1049,6 +1049,10 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||
)
|
||||
}
|
||||
|
||||
public let legacyBuiltinWallpaperGradientColors: [UIColor] = [
|
||||
UIColor(rgb: 0xd6e2ee)
|
||||
]
|
||||
|
||||
public let defaultBuiltinWallpaperGradientColors: [UIColor] = [
|
||||
UIColor(rgb: 0xdbddbb),
|
||||
UIColor(rgb: 0x6ba587),
|
||||
@ -1076,6 +1080,15 @@ public extension BuiltinWallpaperData {
|
||||
datacenterId: 4,
|
||||
fileSize: 183832
|
||||
)
|
||||
static let legacy = BuiltinWallpaperData(
|
||||
wallpaperId: 5911458201550716931,
|
||||
wallpaperAccessHash: -5164387148619674119,
|
||||
slug: "Ye7DfT2kCVIKAAAAhzXfrkdOjxs",
|
||||
fileId: 5911315028815907420,
|
||||
fileAccessHash: 5205407890340371688,
|
||||
datacenterId: 2,
|
||||
fileSize: 71715
|
||||
)
|
||||
static let variant1 = BuiltinWallpaperData(
|
||||
wallpaperId: 5784984711902265347,
|
||||
wallpaperAccessHash: -7073897034484875424,
|
||||
@ -1206,6 +1219,7 @@ public extension BuiltinWallpaperData {
|
||||
static func generate(account: Account) {
|
||||
let slugToName: [(String, String)] = [
|
||||
("fqv01SQemVIBAAAApND8LDRUhRU", "`default`"),
|
||||
("Ye7DfT2kCVIKAAAAhzXfrkdOjxs", "legacy"),
|
||||
("RlZs2PJkSFADAAAAElGaGwgJBgU", "variant1"),
|
||||
("9LW_RcoOSVACAAAAFTk3DTyXN-M", "variant2"),
|
||||
("CJNyxPMgSVAEAAAAvW9sMwc51cw", "variant3"),
|
||||
|
@ -383,7 +383,10 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
let effectiveColors = themeSettings.themeSpecificAccentColors[effectiveTheme.index]
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.colorFor(baseTheme: preferredBaseTheme ?? .day), bubbleColors: effectiveColors?.customBubbleColors ?? [], baseColor: effectiveColors?.baseColor) ?? defaultPresentationTheme
|
||||
|
||||
let effectiveChatWallpaper: TelegramWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: effectiveTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[effectiveTheme.index]) ?? theme.chat.defaultWallpaper
|
||||
var effectiveChatWallpaper: TelegramWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: effectiveTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[effectiveTheme.index]) ?? theme.chat.defaultWallpaper
|
||||
if case .builtin = effectiveChatWallpaper {
|
||||
effectiveChatWallpaper = defaultBuiltinWallpaper(data: .legacy, colors: legacyBuiltinWallpaperGradientColors.map(\.rgb))
|
||||
}
|
||||
|
||||
let dateTimeFormat = currentDateTimeFormat()
|
||||
let stringsValue: PresentationStrings
|
||||
@ -763,6 +766,10 @@ public func updatedPresentationData(accountManager: AccountManager<TelegramAccou
|
||||
}
|
||||
}
|
||||
|
||||
if case .builtin = effectiveChatWallpaper {
|
||||
effectiveChatWallpaper = defaultBuiltinWallpaper(data: .legacy, colors: legacyBuiltinWallpaperGradientColors.map(\.rgb))
|
||||
}
|
||||
|
||||
if let colors = effectiveColors, colors.baseColor == .theme {
|
||||
effectiveColors = nil
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/EmojiTextAttachmentView:EmojiTextAttachmentView",
|
||||
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
|
||||
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
|
||||
"//submodules/InvisibleInkDustNode:InvisibleInkDustNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -8,6 +8,7 @@ import AccountContext
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import TelegramCore
|
||||
import InvisibleInkDustNode
|
||||
|
||||
private extension CGRect {
|
||||
var center: CGPoint {
|
||||
@ -287,12 +288,15 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
public var textStroke: (UIColor, CGFloat)?
|
||||
public var cutout: TextNodeCutout?
|
||||
public var displaySpoilers = false
|
||||
public var displaySpoilerEffect = true
|
||||
public var spoilerColor: UIColor = .black
|
||||
|
||||
private var enableLooping: Bool = true
|
||||
|
||||
public var arguments: TextNodeWithEntities.Arguments?
|
||||
|
||||
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:]
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
|
||||
public var visibility: Bool = false {
|
||||
didSet {
|
||||
@ -337,7 +341,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
public var linkHighlightColor: UIColor?
|
||||
|
||||
public var trailingLineWidth: CGFloat?
|
||||
|
||||
|
||||
var constrainedSize: CGSize?
|
||||
|
||||
public var highlightAttributeAction: (([NSAttributedString.Key: Any]) -> NSAttributedString.Key?)? {
|
||||
@ -378,9 +382,12 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
|
||||
let _ = apply()
|
||||
|
||||
var enableAnimations = true
|
||||
if let arguments = self.arguments {
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor)
|
||||
enableAnimations = arguments.context.sharedContext.energyUsageSettings.fullTranslucency
|
||||
}
|
||||
self.updateSpoilers(enableAnimations: enableAnimations, textLayout: layout)
|
||||
|
||||
if layout.numberOfLines > 1 {
|
||||
self.trailingLineWidth = layout.trailingLineWidth
|
||||
@ -443,6 +450,25 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateSpoilers(enableAnimations: Bool, textLayout: TextNodeLayout) {
|
||||
if !textLayout.spoilers.isEmpty && self.displaySpoilerEffect {
|
||||
if self.dustNode == nil {
|
||||
let dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: enableAnimations)
|
||||
self.dustNode = dustNode
|
||||
self.addSubnode(dustNode)
|
||||
|
||||
}
|
||||
if let dustNode = self.dustNode {
|
||||
let textFrame = CGRect(origin: .zero, size: textLayout.size)
|
||||
dustNode.update(size: textFrame.size, color: self.spoilerColor, textColor: self.spoilerColor, rects: textLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: textLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
|
||||
dustNode.frame = textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)
|
||||
}
|
||||
} else if let dustNode = self.dustNode {
|
||||
self.dustNode = nil
|
||||
dustNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
public func updateLayoutInfo(_ constrainedSize: CGSize) -> ImmediateTextNodeLayoutInfo {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Schedule@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Schedule@3x.png",
|
||||
"scale" : "3x"
|
||||
"filename" : "schedule.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1004 B |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
97
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/schedule.pdf
vendored
Normal file
97
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/ScheduleIcon.imageset/schedule.pdf
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.334961 3.334961 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
8.000000 16.665077 m
|
||||
8.000000 17.032347 8.297730 17.330078 8.665000 17.330078 c
|
||||
13.450547 17.330078 17.330002 13.450625 17.330002 8.665078 c
|
||||
17.330002 3.879531 13.450547 0.000076 8.665000 0.000076 c
|
||||
3.879452 0.000076 0.000000 3.879531 0.000000 8.665078 c
|
||||
0.000000 11.755159 1.617408 14.466341 4.050117 16.000078 c
|
||||
2.165000 16.000078 l
|
||||
1.797731 16.000078 1.500000 16.297810 1.500000 16.665077 c
|
||||
1.500000 17.032347 1.797731 17.330078 2.165000 17.330078 c
|
||||
5.665000 17.330078 l
|
||||
6.032269 17.330078 6.330000 17.032347 6.330000 16.665077 c
|
||||
6.330000 13.165078 l
|
||||
6.330000 12.797809 6.032269 12.500078 5.665000 12.500078 c
|
||||
5.297730 12.500078 5.000000 12.797809 5.000000 13.165078 c
|
||||
5.000000 15.020401 l
|
||||
2.805339 13.751994 1.330000 11.380217 1.330000 8.665078 c
|
||||
1.330000 4.614069 4.613991 1.330078 8.665000 1.330078 c
|
||||
12.716009 1.330078 16.000000 4.614069 16.000000 8.665078 c
|
||||
16.000000 12.716087 12.716009 16.000078 8.665000 16.000078 c
|
||||
8.297730 16.000078 8.000000 16.297810 8.000000 16.665077 c
|
||||
h
|
||||
8.665000 14.330078 m
|
||||
9.032269 14.330078 9.330000 14.032348 9.330000 13.665078 c
|
||||
9.330000 8.940530 l
|
||||
12.135226 6.135303 l
|
||||
12.394924 5.875606 12.394924 5.454551 12.135226 5.194852 c
|
||||
11.875527 4.935153 11.454473 4.935153 11.194774 5.194852 c
|
||||
8.194774 8.194853 l
|
||||
8.070063 8.319564 8.000000 8.488708 8.000000 8.665078 c
|
||||
8.000000 13.665078 l
|
||||
8.000000 14.032348 8.297730 14.330078 8.665000 14.330078 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1511
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001601 00000 n
|
||||
0000001624 00000 n
|
||||
0000001797 00000 n
|
||||
0000001871 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1930
|
||||
%%EOF
|
@ -1,22 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Mute@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Mute@3x.png",
|
||||
"scale" : "3x"
|
||||
"filename" : "sendwithoutsound.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 868 B |
Binary file not shown.
Before Width: | Height: | Size: 1.2 KiB |
154
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/SilentIcon.imageset/sendwithoutsound.pdf
vendored
Normal file
154
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/SilentIcon.imageset/sendwithoutsound.pdf
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.334961 3.205078 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
1.135226 17.265186 m
|
||||
0.875527 17.524885 0.454473 17.524885 0.194774 17.265186 c
|
||||
-0.064925 17.005487 -0.064925 16.584435 0.194774 16.324736 c
|
||||
16.194775 0.324734 l
|
||||
16.454473 0.065035 16.875528 0.065035 17.135227 0.324734 c
|
||||
17.394926 0.584433 17.394926 1.005487 17.135227 1.265186 c
|
||||
12.830019 5.570395 l
|
||||
12.830019 13.984108 l
|
||||
12.830019 14.015735 l
|
||||
12.830019 14.015746 l
|
||||
12.830019 14.015758 l
|
||||
12.830032 14.503190 12.830044 14.912979 12.802612 15.227596 c
|
||||
12.776955 15.521866 12.718998 15.904351 12.465319 16.192924 c
|
||||
12.149200 16.552528 11.677307 16.734966 11.201504 16.681524 c
|
||||
10.819681 16.638639 10.519508 16.394609 10.302576 16.194126 c
|
||||
10.070642 15.979778 9.794991 15.676547 9.467113 15.315862 c
|
||||
9.467100 15.315848 l
|
||||
9.445834 15.292454 l
|
||||
6.911015 12.504154 l
|
||||
6.870810 12.460040 l
|
||||
6.811123 12.459965 l
|
||||
6.165019 12.459965 l
|
||||
6.142232 12.459965 l
|
||||
6.073141 12.459966 6.005919 12.459967 5.940522 12.459891 c
|
||||
1.135226 17.265186 l
|
||||
h
|
||||
7.233788 11.166624 m
|
||||
11.500019 6.900394 l
|
||||
11.500019 13.984108 l
|
||||
11.500019 14.511556 11.499405 14.862436 11.477638 15.112073 c
|
||||
11.466372 15.241299 11.451292 15.307571 11.443966 15.335192 c
|
||||
11.425201 15.348718 11.403254 15.357203 11.380270 15.359817 c
|
||||
11.356270 15.344307 11.300531 15.305413 11.205269 15.217373 c
|
||||
11.021238 15.047297 10.784756 14.788080 10.429955 14.397799 c
|
||||
7.895135 11.609499 l
|
||||
7.876595 11.588985 l
|
||||
7.810806 11.515999 7.711236 11.405536 7.585287 11.322461 c
|
||||
7.477557 11.251403 7.358773 11.198743 7.233788 11.166624 c
|
||||
h
|
||||
3.310589 11.708942 m
|
||||
4.251275 10.768256 l
|
||||
4.114416 10.639768 4.004863 10.482624 3.931640 10.305847 c
|
||||
3.894677 10.216611 3.864227 10.089064 3.847507 9.844008 c
|
||||
3.830379 9.592980 3.830019 9.270005 3.830019 8.794965 c
|
||||
3.830019 8.319924 3.830379 7.996948 3.847507 7.745921 c
|
||||
3.864227 7.500866 3.894677 7.373319 3.931640 7.284082 c
|
||||
4.067134 6.956970 4.327024 6.697080 4.654137 6.561585 c
|
||||
4.743373 6.524623 4.870920 6.494172 5.115975 6.477452 c
|
||||
5.367003 6.460325 5.689979 6.459965 6.165019 6.459965 c
|
||||
6.811123 6.459965 l
|
||||
6.838768 6.460045 l
|
||||
6.838777 6.460045 l
|
||||
6.937038 6.460461 7.085750 6.461090 7.231940 6.423779 c
|
||||
7.357602 6.391706 7.477026 6.338876 7.585287 6.267468 c
|
||||
7.711238 6.184393 7.810808 6.073929 7.876598 6.000941 c
|
||||
7.895135 5.980431 l
|
||||
10.429956 3.192128 l
|
||||
10.784757 2.801847 11.021239 2.542631 11.205269 2.372556 c
|
||||
11.300533 2.284515 11.356270 2.245622 11.380270 2.230112 c
|
||||
11.403254 2.232725 11.425201 2.241211 11.443966 2.254738 c
|
||||
11.451292 2.282358 11.466372 2.348630 11.477638 2.477856 c
|
||||
11.498196 2.713622 11.499886 3.039693 11.500010 3.519522 c
|
||||
12.789057 2.230474 l
|
||||
12.756243 1.960018 12.682525 1.644088 12.465319 1.397003 c
|
||||
12.149200 1.037399 11.677307 0.854963 11.201504 0.908403 c
|
||||
10.819681 0.951288 10.519508 1.195318 10.302577 1.395802 c
|
||||
10.070659 1.610135 9.795034 1.913337 9.467189 2.273985 c
|
||||
9.467137 2.274039 l
|
||||
9.467128 2.274051 l
|
||||
9.445836 2.297473 l
|
||||
6.911015 5.085775 l
|
||||
6.870807 5.129889 l
|
||||
6.811123 5.129965 l
|
||||
6.165019 5.129965 l
|
||||
6.142203 5.129965 l
|
||||
6.142138 5.129965 l
|
||||
5.695606 5.129959 5.327103 5.129954 5.025440 5.150537 c
|
||||
4.712668 5.171878 4.423473 5.217547 4.145168 5.332826 c
|
||||
3.492168 5.603307 2.973362 6.122113 2.702880 6.775113 c
|
||||
2.587602 7.053419 2.541932 7.342614 2.520592 7.655386 c
|
||||
2.500008 7.957066 2.500013 8.325591 2.500019 8.772156 c
|
||||
2.500019 8.772170 l
|
||||
2.500019 8.794965 l
|
||||
2.500019 8.817760 l
|
||||
2.500019 8.817774 l
|
||||
2.500013 9.264338 2.500008 9.632866 2.520592 9.934544 c
|
||||
2.541932 10.247315 2.587602 10.536510 2.702880 10.814816 c
|
||||
2.843596 11.154535 3.051523 11.457933 3.310589 11.708942 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
3618
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000003708 00000 n
|
||||
0000003731 00000 n
|
||||
0000003904 00000 n
|
||||
0000003978 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4037
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/WhenOnlineIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/WhenOnlineIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "sendthenonline.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
123
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/WhenOnlineIcon.imageset/sendthenonline.pdf
vendored
Normal file
123
submodules/TelegramUI/Images.xcassets/Chat/Input/Menu/WhenOnlineIcon.imageset/sendthenonline.pdf
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 15.000000 4.000000 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
5.000000 2.500000 m
|
||||
5.000000 1.119288 3.880712 0.000000 2.500000 0.000000 c
|
||||
1.119288 0.000000 0.000000 1.119288 0.000000 2.500000 c
|
||||
0.000000 3.880712 1.119288 5.000000 2.500000 5.000000 c
|
||||
3.880712 5.000000 5.000000 3.880712 5.000000 2.500000 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.334961 3.334961 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
1.330000 8.665078 m
|
||||
1.330000 12.716087 4.613991 16.000078 8.665000 16.000078 c
|
||||
12.716008 16.000078 16.000000 12.716087 16.000000 8.665078 c
|
||||
16.000000 7.971566 15.903754 7.300534 15.723890 6.664610 c
|
||||
16.154043 6.472708 16.542303 6.203824 16.871166 5.875466 c
|
||||
17.168650 6.750837 17.330002 7.689115 17.330002 8.665078 c
|
||||
17.330002 13.450625 13.450547 17.330078 8.665000 17.330078 c
|
||||
3.879453 17.330078 0.000000 13.450625 0.000000 8.665078 c
|
||||
0.000000 3.879531 3.879453 0.000076 8.665000 0.000076 c
|
||||
9.641031 0.000076 10.579370 0.161449 11.454794 0.458973 c
|
||||
11.126430 0.787828 10.857537 1.176086 10.665626 1.606233 c
|
||||
10.029655 1.426340 9.358569 1.330078 8.665000 1.330078 c
|
||||
6.949595 1.330078 5.371725 1.918934 4.122502 2.905533 c
|
||||
4.297272 3.127586 4.536829 3.393646 4.847776 3.660172 c
|
||||
5.621715 4.323548 6.847626 5.000078 8.665000 5.000078 c
|
||||
9.428206 5.000078 10.087104 4.880767 10.652022 4.693223 c
|
||||
10.837114 5.118156 11.097044 5.502989 11.415169 5.831069 c
|
||||
10.648278 6.131837 9.735907 6.330078 8.665000 6.330078 c
|
||||
6.482374 6.330078 4.958285 5.506608 3.982224 4.669984 c
|
||||
3.639743 4.376429 3.365922 4.082502 3.154341 3.823979 c
|
||||
2.018686 5.115683 1.330000 6.809955 1.330000 8.665078 c
|
||||
h
|
||||
12.678360 5.175269 m
|
||||
12.317028 4.907584 12.030398 4.544794 11.855478 4.123891 c
|
||||
12.090899 3.974664 12.299200 3.817050 12.482224 3.660172 c
|
||||
12.793171 3.393646 13.032728 3.127586 13.207498 2.905533 c
|
||||
12.806664 2.588965 12.371993 2.313348 11.909800 2.084994 c
|
||||
12.111738 1.664135 12.428010 1.308554 12.818370 1.058498 c
|
||||
14.273650 1.854803 15.475398 3.056577 16.271671 4.511877 c
|
||||
16.021608 4.902231 15.666019 5.218495 15.245155 5.420424 c
|
||||
14.958824 4.840852 14.598176 4.304554 14.175659 3.823979 c
|
||||
13.964078 4.082502 13.690256 4.376430 13.347776 4.669984 c
|
||||
13.147928 4.841282 12.925106 5.012029 12.678360 5.175269 c
|
||||
h
|
||||
6.830039 10.665039 m
|
||||
6.830039 11.678482 7.651597 12.500039 8.665039 12.500039 c
|
||||
9.678482 12.500039 10.500039 11.678482 10.500039 10.665039 c
|
||||
10.500039 9.651596 9.678482 8.830039 8.665039 8.830039 c
|
||||
7.651597 8.830039 6.830039 9.651596 6.830039 10.665039 c
|
||||
h
|
||||
8.665039 13.830039 m
|
||||
6.917058 13.830039 5.500039 12.413020 5.500039 10.665039 c
|
||||
5.500039 8.917058 6.917058 7.500039 8.665039 7.500039 c
|
||||
10.413020 7.500039 11.830039 8.917058 11.830039 10.665039 c
|
||||
11.830039 12.413020 10.413020 13.830039 8.665039 13.830039 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
2777
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000002867 00000 n
|
||||
0000002890 00000 n
|
||||
0000003063 00000 n
|
||||
0000003137 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
3196
|
||||
%%EOF
|
Binary file not shown.
Before Width: | Height: | Size: 498 KiB |
BIN
submodules/TelegramUI/Resources/Ye7DfT2kCVIKAAAAhzXfrkdOjxs.tgv
Normal file
BIN
submodules/TelegramUI/Resources/Ye7DfT2kCVIKAAAAhzXfrkdOjxs.tgv
Normal file
Binary file not shown.
@ -183,7 +183,7 @@ private final class AttachmentFileContext: AttachmentMediaPickerContext {
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
|
@ -430,6 +430,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
private weak var searchResultsTooltipController: TooltipController?
|
||||
private weak var messageTooltipController: TooltipController?
|
||||
private weak var videoUnmuteTooltipController: TooltipController?
|
||||
private var didDisplayVideoUnmuteTooltip = false
|
||||
private weak var silentPostTooltipController: TooltipController?
|
||||
private weak var mediaRecordingModeTooltipController: TooltipController?
|
||||
private weak var mediaRestrictedTooltipController: TooltipController?
|
||||
@ -995,78 +996,92 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}))
|
||||
}
|
||||
}, actionInteraction: GalleryControllerActionInteraction(openUrl: { [weak self] url, concealed in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrl(url, concealed: concealed, message: nil)
|
||||
}
|
||||
}, openUrlIn: { [weak self] url in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrlIn(url)
|
||||
}
|
||||
}, openPeerMention: { [weak self] mention in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeerMention(mention)
|
||||
}
|
||||
}, openPeer: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeer(peer, .default, nil, .default)
|
||||
}
|
||||
}, openHashtag: { [weak self] peerName, hashtag in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openHashtag(peerName, hashtag)
|
||||
}
|
||||
}, openBotCommand: { [weak self] command in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.sendBotCommand(nil, command)
|
||||
}
|
||||
}, addContact: { [weak self] phoneNumber in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.addContact(phoneNumber)
|
||||
}
|
||||
}, storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var storedState: MediaPlaybackStoredState?
|
||||
if let timestamp = timestamp {
|
||||
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate))
|
||||
}
|
||||
let _ = updateMediaPlaybackStoredStateInteractively(engine: strongSelf.context.engine, messageId: messageId, state: storedState).start()
|
||||
}, editMedia: { [weak self] messageId, snapshots, transitionCompletion in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] message in
|
||||
guard let strongSelf = self, let message = message else {
|
||||
}, actionInteraction: GalleryControllerActionInteraction(
|
||||
openUrl: { [weak self] url, concealed in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrl(url, concealed: concealed, message: nil)
|
||||
}
|
||||
}, openUrlIn: { [weak self] url in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrlIn(url)
|
||||
}
|
||||
}, openPeerMention: { [weak self] mention in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeerMention(mention)
|
||||
}
|
||||
}, openPeer: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeer(peer, .default, nil, .default)
|
||||
}
|
||||
}, openHashtag: { [weak self] peerName, hashtag in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openHashtag(peerName, hashtag)
|
||||
}
|
||||
}, openBotCommand: { [weak self] command in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.sendBotCommand(nil, command)
|
||||
}
|
||||
}, addContact: { [weak self] phoneNumber in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.addContact(phoneNumber)
|
||||
}
|
||||
}, storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var storedState: MediaPlaybackStoredState?
|
||||
if let timestamp = timestamp {
|
||||
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate))
|
||||
}
|
||||
let _ = updateMediaPlaybackStoredStateInteractively(engine: strongSelf.context.engine, messageId: messageId, state: storedState).start()
|
||||
}, editMedia: { [weak self] messageId, snapshots, transitionCompletion in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var mediaReference: AnyMediaReference?
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
mediaReference = AnyMediaReference.standalone(media: image)
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
mediaReference = AnyMediaReference.standalone(media: file)
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] message in
|
||||
guard let strongSelf = self, let message = message else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: {
|
||||
transitionCompletion()
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false)
|
||||
|
||||
var mediaReference: AnyMediaReference?
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
mediaReference = AnyMediaReference.standalone(media: image)
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
mediaReference = AnyMediaReference.standalone(media: file)
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
}
|
||||
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: {
|
||||
transitionCompletion()
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false)
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
}
|
||||
})
|
||||
}),
|
||||
getSourceRect: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
})))
|
||||
var rect: CGRect?
|
||||
strongSelf.chatDisplayNode.historyNode.forEachVisibleMessageItemNode({ itemNode in
|
||||
if itemNode.item?.message.id == message.id {
|
||||
rect = itemNode.view.convert(itemNode.contentFrame(), to: nil)
|
||||
}
|
||||
})
|
||||
return rect
|
||||
}
|
||||
))
|
||||
}, openPeer: { [weak self] peer, navigation, fromMessage, source in
|
||||
self?.openPeer(peer: peer, navigation: navigation, fromMessage: fromMessage, fromReactionMessageId: source == .reaction ? fromMessage?.id : nil, expandAvatar: source == .groupParticipant)
|
||||
}, openPeerMention: { [weak self] name in
|
||||
@ -4288,30 +4303,30 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let botAdminRights {
|
||||
if botAdminRights.rights.isEmpty {
|
||||
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteAdminText(botName, peerName)
|
||||
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
for range in stringWithRanges.ranges.prefix(2) {
|
||||
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range)
|
||||
formattedString.addAttribute(.font, value: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), range: range.range)
|
||||
}
|
||||
attributedText = formattedString
|
||||
} else {
|
||||
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteWithRightsText(botName, peerName, stringForAdminRights(strings: strongSelf.presentationData.strings, adminRights: botAdminRights, isChannel: isChannel))
|
||||
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
for range in stringWithRanges.ranges.prefix(2) {
|
||||
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range)
|
||||
formattedString.addAttribute(.font, value: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), range: range.range)
|
||||
}
|
||||
attributedText = formattedString
|
||||
}
|
||||
} else {
|
||||
if case let .group(group) = peerType, group.botParticipant {
|
||||
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteText(botName, peerName)
|
||||
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
for range in stringWithRanges.ranges.prefix(2) {
|
||||
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range)
|
||||
formattedString.addAttribute(.font, value: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), range: range.range)
|
||||
}
|
||||
attributedText = formattedString
|
||||
} else {
|
||||
attributedTitle = nil
|
||||
attributedText = NSAttributedString(string: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationTitle(peerName, botName).string, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
attributedText = NSAttributedString(string: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationTitle(peerName, botName).string, font: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8986,14 +9001,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
}, displayVideoUnmuteTip: { [weak self] location in
|
||||
guard let strongSelf = self, let layout = strongSelf.validLayout, strongSelf.traceVisibility() && isTopmostChatController(strongSelf) else {
|
||||
guard let strongSelf = self, !strongSelf.didDisplayVideoUnmuteTooltip, let layout = strongSelf.validLayout, strongSelf.traceVisibility() && isTopmostChatController(strongSelf) else {
|
||||
return
|
||||
}
|
||||
|
||||
if let location = location, location.y < strongSelf.navigationLayout(layout: layout).navigationFrame.maxY {
|
||||
return
|
||||
}
|
||||
|
||||
let icon: UIImage?
|
||||
if layout.deviceMetrics.hasTopNotch || layout.deviceMetrics.hasDynamicIsland {
|
||||
icon = UIImage(bundleImageName: "Chat/Message/VolumeButtonIconX")
|
||||
@ -9001,6 +9014,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
icon = UIImage(bundleImageName: "Chat/Message/VolumeButtonIcon")
|
||||
}
|
||||
if let location = location, let icon = icon {
|
||||
strongSelf.didDisplayVideoUnmuteTooltip = true
|
||||
strongSelf.videoUnmuteTooltipController?.dismiss()
|
||||
let tooltipController = TooltipController(content: .iconAndText(icon, strongSelf.presentationInterfaceState.strings.Conversation_PressVolumeButtonForSound), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, timeout: 3.5, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
||||
strongSelf.videoUnmuteTooltipController = tooltipController
|
||||
@ -9832,7 +9846,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.window?.presentInGlobalOverlay(slowmodeTooltipController)
|
||||
}, displaySendMessageOptions: { [weak self] node, gesture in
|
||||
if let strongSelf = self, let textInputNode = strongSelf.chatDisplayNode.textInputNode(), let layout = strongSelf.validLayout {
|
||||
if let strongSelf = self, let peerId = strongSelf.chatLocation.peerId, let textInputNode = strongSelf.chatDisplayNode.textInputNode(), let layout = strongSelf.validLayout {
|
||||
let previousSupportedOrientations = strongSelf.supportedOrientations
|
||||
if layout.size.width > layout.size.height {
|
||||
strongSelf.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .landscape)
|
||||
@ -9847,26 +9861,55 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
hasEntityKeyboard = true
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.supportedOrientations = previousSupportedOrientations
|
||||
let _ = (strongSelf.context.account.viewTracker.peerView(peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerView in
|
||||
guard let strongSelf = self, let peer = peerViewMainPeer(peerView) else {
|
||||
return
|
||||
}
|
||||
}, sendMessage: { [weak self] silently in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.sendCurrentMessage(silently)
|
||||
var sendWhenOnlineAvailable = false
|
||||
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case .present = presence.status {
|
||||
sendWhenOnlineAvailable = true
|
||||
}
|
||||
}, schedule: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.scheduleCurrentMessage()
|
||||
if peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id._internalGetInt64Value() == 777000 {
|
||||
sendWhenOnlineAvailable = false
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, canSendWhenOnline: sendWhenOnlineAvailable, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.supportedOrientations = previousSupportedOrientations
|
||||
}
|
||||
}, sendMessage: { [weak self] mode in
|
||||
if let strongSelf = self {
|
||||
switch mode {
|
||||
case .generic:
|
||||
strongSelf.controllerInteraction?.sendCurrentMessage(false)
|
||||
case .silently:
|
||||
strongSelf.controllerInteraction?.sendCurrentMessage(true)
|
||||
case .whenOnline:
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleWhenOnlineTimestamp) { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: strongSelf.presentationInterfaceState.subject != .scheduledMessages, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) }
|
||||
})
|
||||
strongSelf.openScheduledMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, schedule: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.scheduleCurrentMessage()
|
||||
}
|
||||
})
|
||||
controller.emojiViewProvider = strongSelf.chatDisplayNode.textInputPanelNode?.emojiViewProvider
|
||||
strongSelf.sendMessageActionsController = controller
|
||||
if layout.isNonExclusive {
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
} else {
|
||||
strongSelf.presentInGlobalOverlay(controller, with: nil)
|
||||
}
|
||||
})
|
||||
controller.emojiViewProvider = strongSelf.chatDisplayNode.textInputPanelNode?.emojiViewProvider
|
||||
strongSelf.sendMessageActionsController = controller
|
||||
if layout.isNonExclusive {
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
} else {
|
||||
strongSelf.presentInGlobalOverlay(controller, with: nil)
|
||||
}
|
||||
}
|
||||
}, openScheduledMessages: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
@ -11056,9 +11099,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if values.contains(.convertToGigagroup) && !strongSelf.displayedConvertToGigagroupSuggestion {
|
||||
strongSelf.displayedConvertToGigagroupSuggestion = true
|
||||
|
||||
let attributedTitle = NSAttributedString(string: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_Title, font: Font.medium(17.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor)
|
||||
let attributedTitle = NSAttributedString(string: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_Title, font: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor)
|
||||
|
||||
let participantsLimit = strongSelf.context.currentLimitsConfiguration.with { $0 }.maxSupergroupMemberCount
|
||||
let text = strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_Text(presentationStringsFormattedNumber(participantsLimit, strongSelf.presentationData.dateTimeFormat.groupingSeparator)).string
|
||||
@ -11074,9 +11117,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
controller.navigationPresentation = .modal
|
||||
controller.setState(.custom(icon: .animation("BroadcastGroup"), title: presentationData.strings.BroadcastGroups_IntroTitle, subtitle: nil, text: presentationData.strings.BroadcastGroups_IntroText, buttonTitle: presentationData.strings.BroadcastGroups_Convert, secondaryButtonTitle: presentationData.strings.BroadcastGroups_Cancel, footerText: nil), animated: false)
|
||||
controller.proceed = { [weak controller] result in
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.medium(17.0), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
@ -12790,24 +12833,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
break
|
||||
case .gift:
|
||||
initialButton = .gift
|
||||
case let .bot(botId, _, _):
|
||||
for bot in attachMenuBots.reversed() {
|
||||
var peerType = peerType
|
||||
if bot.peer.id == peer.id {
|
||||
peerType.insert(.sameBot)
|
||||
peerType.remove(.bot)
|
||||
}
|
||||
let button: AttachmentButtonType = .app(bot.peer, bot.shortName, bot.icons)
|
||||
if !bot.peerTypes.intersection(peerType).isEmpty {
|
||||
buttons.insert(button, at: 1)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
for bot in attachMenuBots.reversed() {
|
||||
var peerType = peerType
|
||||
if bot.peer.id == peer.id {
|
||||
peerType.insert(.sameBot)
|
||||
peerType.remove(.bot)
|
||||
}
|
||||
let button: AttachmentButtonType = .app(bot.peer, bot.shortName, bot.icons)
|
||||
if !bot.peerTypes.intersection(peerType).isEmpty {
|
||||
buttons.insert(button, at: 1)
|
||||
|
||||
if case let .bot(botId, _, _) = subject {
|
||||
if initialButton == nil && bot.peer.id == botId {
|
||||
initialButton = button
|
||||
}
|
||||
}
|
||||
allButtons.insert(button, at: 1)
|
||||
}
|
||||
allButtons.insert(button, at: 1)
|
||||
}
|
||||
|
||||
return (buttons, allButtons, initialButton)
|
||||
}
|
||||
} else {
|
||||
@ -16331,6 +16379,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
commit(transformedMessages)
|
||||
}
|
||||
})
|
||||
case .whenOnline:
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleWhenOnlineTimestamp)
|
||||
commit(transformedMessages)
|
||||
}
|
||||
}
|
||||
controller.peerSelected = { [weak self, weak controller] peer, threadId in
|
||||
@ -17340,7 +17391,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
@available(iOSApplicationExtension 11.0, iOS 11.0, *)
|
||||
public func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
|
||||
session.loadObjects(ofClass: UIImage.self) { [weak self] imageItems in
|
||||
guard let strongSelf = self else {
|
||||
guard let strongSelf = self, !imageItems.isEmpty else {
|
||||
return
|
||||
}
|
||||
let images = imageItems as! [UIImage]
|
||||
|
@ -1361,6 +1361,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
if (isChat && (wasPlaying || currentlyPlayingVideo)) || (!isChat && !wasPlaying && currentlyPlayingVideo) {
|
||||
var currentIsVisible = true
|
||||
var nextIsVisible = false
|
||||
if let appliedPlayingMessageId = strongSelf.appliedPlayingMessageId {
|
||||
currentIsVisible = false
|
||||
strongSelf.forEachVisibleMessageItemNode({ view in
|
||||
@ -1369,7 +1370,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
})
|
||||
}
|
||||
if currentIsVisible && currentlyPlayingVideo {
|
||||
strongSelf.forEachVisibleMessageItemNode({ view in
|
||||
if view.item?.message.id == currentlyPlayingMessageId.id {
|
||||
nextIsVisible = true
|
||||
}
|
||||
})
|
||||
if currentIsVisible && nextIsVisible && currentlyPlayingVideo {
|
||||
updatedScrollPosition = .index(index: .message(currentlyPlayingMessageId), position: .center(.bottom), directionHint: .Up, animated: true, highlight: true, displayLink: true)
|
||||
scrollAnimationCurve = .Spring(duration: 0.4)
|
||||
}
|
||||
|
@ -2889,6 +2889,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
override func unreadMessageRangeUpdated() {
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.imageNode.frame
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimatedEmojiSoundsConfiguration {
|
||||
|
@ -4562,4 +4562,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.backgroundNode.frame
|
||||
}
|
||||
}
|
||||
|
@ -1399,4 +1399,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.interactiveVideoNode.frame
|
||||
}
|
||||
}
|
||||
|
@ -951,4 +951,8 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
|
||||
|
||||
func unreadMessageRangeUpdated() {
|
||||
}
|
||||
|
||||
public func contentFrame() -> CGRect {
|
||||
return self.bounds
|
||||
}
|
||||
}
|
||||
|
@ -1833,4 +1833,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.imageNode.frame
|
||||
}
|
||||
}
|
||||
|
@ -444,8 +444,8 @@ final class ContactsPickerContext: AttachmentMediaPickerContext {
|
||||
self.controller?.caption = caption
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
self.controller?.contactsNode.requestMultipleAction?(silently, nil)
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
self.controller?.contactsNode.requestMultipleAction?(mode == .silently, mode == .whenOnline ? scheduleWhenOnlineTimestamp : nil)
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
|
@ -113,7 +113,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
}, getSourceRect: params.getSourceRect)
|
||||
params.dismissInput()
|
||||
params.present(controller, nil)
|
||||
return true
|
||||
|
@ -79,7 +79,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
let addMemberImpl = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = AlertControllerTheme(presentationData: presentationData)
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_MemberAlertTitle, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_MemberAlertTitle, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
var isGroup: Bool = false
|
||||
var peerTitle: String = ""
|
||||
@ -95,8 +95,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
|
||||
let text = isGroup ? presentationData.strings.Bot_AddToChat_Add_MemberAlertTextGroup(peerTitle).string : presentationData.strings.Bot_AddToChat_Add_MemberAlertTextChannel(peerTitle).string
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Bot_AddToChat_Add_MemberAlertAdd, action: {
|
||||
|
@ -84,11 +84,11 @@ func ownershipTransferController(context: AccountContext, updatedPresentationDat
|
||||
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = AlertControllerTheme(presentationData: presentationData)
|
||||
|
||||
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.medium(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
var text = presentationData.strings.OwnershipTransfer_SecurityRequirements
|
||||
var actions: [TextAlertAction] = []
|
||||
|
||||
let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0
|
||||
switch initialError {
|
||||
case .requestPassword:
|
||||
return commitOwnershipTransferController(context: context, updatedPresentationData: updatedPresentationData, present: present, commit: commit, completion: completion)
|
||||
@ -114,8 +114,8 @@ func ownershipTransferController(context: AccountContext, updatedPresentationDat
|
||||
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
|
||||
}
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor)
|
||||
let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
return richTextAlertController(context: context, title: title, text: attributedText, actions: actions)
|
||||
|
@ -124,7 +124,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
|
||||
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(id: PeerId(0)), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
|
||||
|
||||
self.presentationInterfaceState = self.presentationInterfaceState.updatedInterfaceState { $0.withUpdatedForwardMessageIds(forwardedMessageIds).withUpdatedForwardOptionsState(ChatInterfaceForwardOptionsState(hideNames: false, hideCaptions: false, unhideNamesOnCaptionChange: false)) }
|
||||
self.presentationInterfaceState = self.presentationInterfaceState.updatedInterfaceState { $0.withUpdatedForwardMessageIds(forwardedMessageIds) }
|
||||
self.presentationInterfaceStatePromise.set(self.presentationInterfaceState)
|
||||
|
||||
if let _ = self.requestPeerType {
|
||||
@ -342,9 +342,9 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
}, forwardSelectedMessages: {
|
||||
}, forwardCurrentForwardMessages: {
|
||||
}, forwardMessages: { _ in
|
||||
}, updateForwardOptionsState: { [weak self] value in
|
||||
}, updateForwardOptionsState: { [weak self] f in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardOptionsState($0.forwardOptionsState) }) })
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardOptionsState(f($0.forwardOptionsState ?? ChatInterfaceForwardOptionsState(hideNames: false, hideCaptions: false, unhideNamesOnCaptionChange: false))) }) })
|
||||
}
|
||||
}, presentForwardOptions: { [weak self] sourceNode in
|
||||
guard let strongSelf = self else {
|
||||
@ -659,9 +659,16 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
hasEntityKeyboard = true
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] silently in
|
||||
textInputPanelNode?.sendMessage(silently ? .silent : .generic)
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, canSendWhenOnline: false, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] mode in
|
||||
switch mode {
|
||||
case .generic:
|
||||
textInputPanelNode?.sendMessage(.generic)
|
||||
case .silently:
|
||||
textInputPanelNode?.sendMessage(.silent)
|
||||
case .whenOnline:
|
||||
textInputPanelNode?.sendMessage(.whenOnline)
|
||||
}
|
||||
}, schedule: { [weak textInputPanelNode] in
|
||||
textInputPanelNode?.sendMessage(.schedule)
|
||||
})
|
||||
|
@ -11,7 +11,6 @@ import AccountContext
|
||||
import LocalizedPeerData
|
||||
import PhotoResources
|
||||
import TelegramStringFormatting
|
||||
import InvisibleInkDustNode
|
||||
import TextFormat
|
||||
import ChatPresentationInterfaceState
|
||||
import TextNodeWithEntities
|
||||
@ -29,7 +28,6 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
||||
let iconNode: ASImageNode
|
||||
let titleNode: ImmediateTextNode
|
||||
let textNode: ImmediateTextNodeWithEntities
|
||||
var dustNode: InvisibleInkDustNode?
|
||||
let imageNode: TransformImageNode
|
||||
|
||||
private let actionArea: AccessibilityAreaNode
|
||||
@ -73,6 +71,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.insets = UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0)
|
||||
self.textNode.visibility = true
|
||||
self.textNode.spoilerColor = self.theme.chat.inputPanel.secondaryTextColor
|
||||
|
||||
if let animationCache = animationCache, let animationRenderer = animationRenderer {
|
||||
self.textNode.arguments = TextNodeWithEntities.Arguments(
|
||||
@ -293,6 +292,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
||||
if let text = self.textNode.attributedText?.string {
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: self.theme.chat.inputPanel.primaryTextColor)
|
||||
}
|
||||
self.textNode.spoilerColor = self.theme.chat.inputPanel.secondaryTextColor
|
||||
|
||||
if let (size, inset, interfaceState) = self.validLayout {
|
||||
self.updateState(size: size, inset: inset, interfaceState: interfaceState)
|
||||
@ -345,21 +345,6 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
||||
if self.textNode.supernode == self {
|
||||
self.textNode.frame = textFrame
|
||||
}
|
||||
|
||||
if let textLayout = self.textNode.cachedLayout, !textLayout.spoilers.isEmpty {
|
||||
if self.dustNode == nil {
|
||||
let dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency)
|
||||
self.dustNode = dustNode
|
||||
self.textNode.supernode?.insertSubnode(dustNode, aboveSubnode: self.textNode)
|
||||
}
|
||||
if let dustNode = self.dustNode {
|
||||
dustNode.update(size: textFrame.size, color: self.theme.chat.inputPanel.secondaryTextColor, textColor: self.theme.chat.inputPanel.primaryTextColor, rects: textLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: textLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
|
||||
dustNode.frame = textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)
|
||||
}
|
||||
} else if let dustNode = self.dustNode {
|
||||
self.dustNode = nil
|
||||
dustNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func closePressed() {
|
||||
|
@ -36,7 +36,8 @@ func makeTelegramAccountAuxiliaryMethods(appDelegate: AppDelegate?) -> AccountAu
|
||||
}
|
||||
} else if let wallpaperResource = resource as? WallpaperDataResource {
|
||||
let builtinWallpapers: [String] = [
|
||||
"fqv01SQemVIBAAAApND8LDRUhRU"
|
||||
"fqv01SQemVIBAAAApND8LDRUhRU",
|
||||
"Ye7DfT2kCVIKAAAAhzXfrkdOjxs"
|
||||
]
|
||||
if builtinWallpapers.contains(wallpaperResource.slug) {
|
||||
if let url = getAppBundle().url(forResource: wallpaperResource.slug, withExtension: "tgv") {
|
||||
@ -67,6 +68,19 @@ func makeTelegramAccountAuxiliaryMethods(appDelegate: AppDelegate?) -> AccountAu
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else if cloudDocumentMediaResource.fileId == 5911315028815907420 {
|
||||
if let url = getAppBundle().url(forResource: "Ye7DfT2kCVIKAAAAhzXfrkdOjxs", withExtension: "tgv") {
|
||||
return Signal { subscriber in
|
||||
subscriber.putNext(.reset)
|
||||
if let data = try? Data(contentsOf: url, options: .mappedRead) {
|
||||
subscriber.putNext(.dataPart(resourceOffset: 0, data: data, range: 0 ..< Int64(data.count), complete: true))
|
||||
}
|
||||
|
||||
return EmptyDisposable
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else if let cloudDocumentSizeMediaResource = resource as? CloudDocumentSizeMediaResource {
|
||||
if cloudDocumentSizeMediaResource.documentId == 5789658100176783156 && cloudDocumentSizeMediaResource.sizeSpec == "m" {
|
||||
|
@ -1059,7 +1059,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
if patternIsBlack {
|
||||
self.patternImageLayer.softlightMode = .never
|
||||
} else {
|
||||
if self.useSharedAnimationPhase {
|
||||
if self.useSharedAnimationPhase && file.settings.colors.count > 2 {
|
||||
self.patternImageLayer.softlightMode = .whileAnimating
|
||||
} else {
|
||||
self.patternImageLayer.softlightMode = .always
|
||||
|
@ -576,8 +576,8 @@ public class WebSearchPickerContext: AttachmentMediaPickerContext {
|
||||
self.interaction?.editingState.setForcedCaption(caption, skipUpdate: true)
|
||||
}
|
||||
|
||||
public func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
self.interaction?.sendSelected(nil, silently, nil)
|
||||
public func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
self.interaction?.sendSelected(nil, mode == .silently, nil)
|
||||
}
|
||||
|
||||
public func schedule() {
|
||||
|
@ -1340,7 +1340,7 @@ final class WebAppPickerContext: AttachmentMediaPickerContext {
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user