Merge commit '66619d2e1789272bd2486bb7d66f79c05ce1ff15'

This commit is contained in:
Ali 2023-03-10 13:50:07 +04:00
commit 10ad65523e
83 changed files with 2126 additions and 385 deletions

View File

@ -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";

View File

@ -667,4 +667,5 @@ public enum FileMediaResourceMediaStatus: Equatable {
public protocol ChatMessageItemNodeProtocol: ListViewItemNode {
func targetReactionView(value: MessageReaction.Reaction) -> UIView?
func contentFrame() -> CGRect
}

View File

@ -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
}
}

View File

@ -83,6 +83,7 @@ public enum AttachmentTextInputPanelSendMode {
case generic
case silent
case schedule
case whenOnline
}
public protocol PeerSelectionController: ViewController {

View File

@ -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",

View 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
}

View File

@ -1,5 +1,6 @@
import Foundation
import UIKit
import AsyncDisplayKit
import Display
import SwiftSignalKit

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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):

View File

@ -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))
}

View File

@ -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()

View File

@ -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: {

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "schedule.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "sendwithoutsound.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "sendthenonline.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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];

View File

@ -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) {

View File

@ -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() {

View File

@ -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() {

View File

@ -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

View File

@ -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() {

View File

@ -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: {

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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() {

View File

@ -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)

View File

@ -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
}

View File

@ -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
)
}

View File

@ -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

View File

@ -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)
}

View File

@ -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 ")
})
}

View File

@ -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 {

View File

@ -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"),

View File

@ -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
}

View File

@ -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",

View File

@ -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

View File

@ -1,9 +1,9 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}
}

View File

@ -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

View 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

View File

@ -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

View 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

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "sendthenonline.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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

View File

@ -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() {

View File

@ -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]

View File

@ -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)
}

View File

@ -2889,6 +2889,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
override func unreadMessageRangeUpdated() {
self.updateVisibility()
}
override func contentFrame() -> CGRect {
return self.imageNode.frame
}
}
struct AnimatedEmojiSoundsConfiguration {

View File

@ -4562,4 +4562,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
return false
}
override func contentFrame() -> CGRect {
return self.backgroundNode.frame
}
}

View File

@ -1399,4 +1399,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
}
return nil
}
override func contentFrame() -> CGRect {
return self.interactiveVideoNode.frame
}
}

View File

@ -951,4 +951,8 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
func unreadMessageRangeUpdated() {
}
public func contentFrame() -> CGRect {
return self.bounds
}
}

View File

@ -1833,4 +1833,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
}
return nil
}
override func contentFrame() -> CGRect {
return self.imageNode.frame
}
}

View File

@ -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() {

View File

@ -113,7 +113,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
}))
}
}
})
}, getSourceRect: params.getSourceRect)
params.dismissInput()
params.present(controller, nil)
return true

View File

@ -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: {

View File

@ -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)

View File

@ -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)
})

View File

@ -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() {

View File

@ -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" {

View File

@ -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

View File

@ -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() {

View File

@ -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() {