mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
d2bb1dc57f
commit
2364234f04
@ -9914,14 +9914,17 @@ Sorry for the inconvenience.";
|
|||||||
"Gallery.ViewOncePhotoTooltip" = "This photo can only be viewed once.";
|
"Gallery.ViewOncePhotoTooltip" = "This photo can only be viewed once.";
|
||||||
"Gallery.ViewOnceVideoTooltip" = "This video can only be viewed once.";
|
"Gallery.ViewOnceVideoTooltip" = "This video can only be viewed once.";
|
||||||
|
|
||||||
"WebApp.DisclaimerTitle" = "Warning";
|
"WebApp.DisclaimerTitle" = "Terms of Use";
|
||||||
"WebApp.DisclaimerText" = "You are about to use a mini app operated by an independent party not affiliated with Telegram. You must agree to the Terms of Use of mini apps to continue.";
|
"WebApp.DisclaimerText" = "You are about to use a mini app operated by an independent party not affiliated with Telegram. You must agree to the Terms of Use of mini apps to continue.";
|
||||||
"WebApp.DisclaimerShortcutsText" = "**%@** shortcuts will be added in your attachment menu.";
|
"WebApp.DisclaimerShortcutsText" = "**%@** shortcut will be added in your attachment menu.";
|
||||||
"WebApp.DisclaimerShortcutsSettingsText" = "**%@** shortcuts will be added in your attachment menu and Settings.";
|
"WebApp.DisclaimerShortcutsSettingsText" = "**%@** shortcuts will be added in your attachment menu and Settings.";
|
||||||
"WebApp.DisclaimerAgree" = "I agree to the [Terms of Use]()";
|
"WebApp.DisclaimerAgree" = "I agree to the [Terms of Use]()";
|
||||||
"WebApp.DisclaimerContinue" = "Continue";
|
"WebApp.DisclaimerContinue" = "Continue";
|
||||||
"WebApp.Disclaimer_URL" = "https://telegram.org/tos/mini-apps";
|
"WebApp.Disclaimer_URL" = "https://telegram.org/tos/mini-apps";
|
||||||
|
|
||||||
|
"WebApp.ShortcutsAdded" = "**%@** shortcut added in attachment menu.";
|
||||||
|
"WebApp.ShortcutsSettingsAdded" = "**%@** shortcut added in attachment menu and Settings.";
|
||||||
|
|
||||||
"WebApp.AllowWriteTitle" = "Allow Sending Messages?";
|
"WebApp.AllowWriteTitle" = "Allow Sending Messages?";
|
||||||
"WebApp.AllowWriteConfirmation" = "This will allow the bot **%@** to message you on Telegram.";
|
"WebApp.AllowWriteConfirmation" = "This will allow the bot **%@** to message you on Telegram.";
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ public enum AttachmentButtonType: Equatable {
|
|||||||
case location
|
case location
|
||||||
case contact
|
case contact
|
||||||
case poll
|
case poll
|
||||||
case app(EnginePeer, String, [AttachMenuBots.Bot.IconName: TelegramMediaFile])
|
case app(AttachMenuBot)
|
||||||
case gift
|
case gift
|
||||||
case standalone
|
case standalone
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ public enum AttachmentButtonType: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .app(lhsPeer, lhsTitle, lhsIcons):
|
case let .app(lhsBot):
|
||||||
if case let .app(rhsPeer, rhsTitle, rhsIcons) = rhs, lhsPeer == rhsPeer, lhsTitle == rhsTitle, lhsIcons == rhsIcons {
|
if case let .app(rhsBot) = rhs, lhsBot.peer.id == rhsBot.peer.id {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -446,9 +446,9 @@ public class AttachmentController: ViewController {
|
|||||||
|
|
||||||
if let controller = self.controller {
|
if let controller = self.controller {
|
||||||
let _ = self.switchToController(controller.initialButton)
|
let _ = self.switchToController(controller.initialButton)
|
||||||
if case let .app(bot, _, _) = controller.initialButton {
|
if case let .app(bot) = controller.initialButton {
|
||||||
if let index = controller.buttons.firstIndex(where: {
|
if let index = controller.buttons.firstIndex(where: {
|
||||||
if case let .app(otherBot, _, _) = $0, otherBot.id == bot.id {
|
if case let .app(otherBot) = $0, otherBot.peer.id == bot.peer.id {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -200,15 +200,15 @@ private final class AttachButtonComponent: CombinedComponent {
|
|||||||
case .gift:
|
case .gift:
|
||||||
name = strings.Attachment_Gift
|
name = strings.Attachment_Gift
|
||||||
imageName = "Chat/Attach Menu/Gift"
|
imageName = "Chat/Attach Menu/Gift"
|
||||||
case let .app(peer, appName, appIcons):
|
case let .app(bot):
|
||||||
botPeer = peer
|
botPeer = bot.peer
|
||||||
name = appName
|
name = bot.shortName
|
||||||
imageName = ""
|
imageName = ""
|
||||||
if let file = appIcons[.iOSAnimated] {
|
if let file = bot.icons[.iOSAnimated] {
|
||||||
animationFile = file
|
animationFile = file
|
||||||
} else if let file = appIcons[.iOSStatic] {
|
} else if let file = bot.icons[.iOSStatic] {
|
||||||
imageFile = file
|
imageFile = file
|
||||||
} else if let file = appIcons[.default] {
|
} else if let file = bot.icons[.default] {
|
||||||
imageFile = file
|
imageFile = file
|
||||||
}
|
}
|
||||||
case .standalone:
|
case .standalone:
|
||||||
@ -1142,10 +1142,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let type = self.buttons[i]
|
let type = self.buttons[i]
|
||||||
if case let .app(peer, _, iconFiles) = type {
|
if case let .app(bot) = type {
|
||||||
for (name, file) in iconFiles {
|
for (name, file) in bot.icons {
|
||||||
if [.default, .iOSAnimated, .placeholder].contains(name) {
|
if [.default, .iOSAnimated, .iOSSettingsStatic, .placeholder].contains(name) {
|
||||||
if self.iconDisposables[file.fileId] == nil, let peer = PeerReference(peer._asPeer()) {
|
if self.iconDisposables[file.fileId] == nil, let peer = PeerReference(bot.peer._asPeer()) {
|
||||||
if case .placeholder = name {
|
if case .placeholder = name {
|
||||||
let account = self.context.account
|
let account = self.context.account
|
||||||
let path = account.postbox.mediaBox.cachedRepresentationCompletePath(file.resource.id, representation: CachedPreparedSvgRepresentation())
|
let path = account.postbox.mediaBox.cachedRepresentationCompletePath(file.resource.id, representation: CachedPreparedSvgRepresentation())
|
||||||
@ -1214,8 +1214,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
accessibilityTitle = self.presentationData.strings.Attachment_Poll
|
accessibilityTitle = self.presentationData.strings.Attachment_Poll
|
||||||
case .gift:
|
case .gift:
|
||||||
accessibilityTitle = self.presentationData.strings.Attachment_Gift
|
accessibilityTitle = self.presentationData.strings.Attachment_Gift
|
||||||
case let .app(_, appName, _):
|
case let .app(bot):
|
||||||
accessibilityTitle = appName
|
accessibilityTitle = bot.shortName
|
||||||
case .standalone:
|
case .standalone:
|
||||||
accessibilityTitle = ""
|
accessibilityTitle = ""
|
||||||
}
|
}
|
||||||
|
@ -60,16 +60,20 @@ private final class SecretMediaPreviewControllerNode: GalleryControllerNode {
|
|||||||
|
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
var beginTimeAndTimeout: (Double, Double)? {
|
var beginTimeAndTimeout: (Double, Double, Bool)? {
|
||||||
didSet {
|
didSet {
|
||||||
if let (beginTime, timeout) = self.beginTimeAndTimeout {
|
if let (beginTime, timeout, isOutgoing) = self.beginTimeAndTimeout {
|
||||||
var beginTime = beginTime
|
var beginTime = beginTime
|
||||||
if self.timeoutNode == nil {
|
if self.timeoutNode == nil {
|
||||||
let timeoutNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5))
|
let timeoutNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5))
|
||||||
self.timeoutNode = timeoutNode
|
self.timeoutNode = timeoutNode
|
||||||
let icon: RadialStatusNodeState.SecretTimeoutIcon
|
let icon: RadialStatusNodeState.SecretTimeoutIcon
|
||||||
let timeoutValue = Int32(timeout)
|
let timeoutValue = Int32(timeout)
|
||||||
if timeoutValue == viewOnceTimeout {
|
|
||||||
|
let state: RadialStatusNodeState
|
||||||
|
if timeoutValue == 0 && isOutgoing {
|
||||||
|
state = .staticTimeout
|
||||||
|
} else if timeoutValue == viewOnceTimeout {
|
||||||
beginTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
beginTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
||||||
|
|
||||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/ViewOnce"), color: .white) {
|
if let image = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/ViewOnce"), color: .white) {
|
||||||
@ -77,10 +81,11 @@ private final class SecretMediaPreviewControllerNode: GalleryControllerNode {
|
|||||||
} else {
|
} else {
|
||||||
icon = .flame
|
icon = .flame
|
||||||
}
|
}
|
||||||
|
state = .secretTimeout(color: .white, icon: icon, beginTime: beginTime, timeout: timeout, sparks: isOutgoing ? false : true)
|
||||||
} else {
|
} else {
|
||||||
icon = .flame
|
state = .secretTimeout(color: .white, icon: .flame, beginTime: beginTime, timeout: timeout, sparks: true)
|
||||||
}
|
}
|
||||||
timeoutNode.transitionToState(.secretTimeout(color: .white, icon: icon, beginTime: beginTime, timeout: timeout, sparks: true), completion: {})
|
timeoutNode.transitionToState(state, completion: {})
|
||||||
self.addSubnode(timeoutNode)
|
self.addSubnode(timeoutNode)
|
||||||
|
|
||||||
timeoutNode.addTarget(self, action: #selector(self.statusTapGesture), forControlEvents: .touchUpInside)
|
timeoutNode.addTarget(self, action: #selector(self.statusTapGesture), forControlEvents: .touchUpInside)
|
||||||
@ -308,7 +313,7 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
var hiddenItem: (MessageId, Media)?
|
var hiddenItem: (MessageId, Media)?
|
||||||
if let _ = index {
|
if let _ = index {
|
||||||
if let message = strongSelf.messageView?.message, let media = mediaForMessage(message: message) {
|
if let message = strongSelf.messageView?.message, let media = mediaForMessage(message: message) {
|
||||||
var beginTimeAndTimeout: (Double, Double)?
|
var beginTimeAndTimeout: (Double, Double, Bool)?
|
||||||
var videoDuration: Double?
|
var videoDuration: Double?
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
@ -316,26 +321,31 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isOutgoing = !message.flags.contains(.Incoming)
|
||||||
if let attribute = message.autoclearAttribute {
|
if let attribute = message.autoclearAttribute {
|
||||||
strongSelf.currentNodeMessageIsViewOnce = attribute.timeout == viewOnceTimeout
|
strongSelf.currentNodeMessageIsViewOnce = attribute.timeout == viewOnceTimeout
|
||||||
|
|
||||||
if let countdownBeginTime = attribute.countdownBeginTime {
|
if let countdownBeginTime = attribute.countdownBeginTime {
|
||||||
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
||||||
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)))
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)), isOutgoing)
|
||||||
} else {
|
} else {
|
||||||
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout))
|
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout), isOutgoing)
|
||||||
}
|
}
|
||||||
|
} else if isOutgoing {
|
||||||
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, attribute.timeout != viewOnceTimeout ? 0.0 : Double(viewOnceTimeout), isOutgoing)
|
||||||
}
|
}
|
||||||
} else if let attribute = message.autoremoveAttribute {
|
} else if let attribute = message.autoremoveAttribute {
|
||||||
strongSelf.currentNodeMessageIsViewOnce = attribute.timeout == viewOnceTimeout
|
strongSelf.currentNodeMessageIsViewOnce = attribute.timeout == viewOnceTimeout
|
||||||
|
|
||||||
if let countdownBeginTime = attribute.countdownBeginTime {
|
if let countdownBeginTime = attribute.countdownBeginTime {
|
||||||
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
||||||
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)))
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)), isOutgoing)
|
||||||
} else {
|
} else {
|
||||||
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout))
|
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout), isOutgoing)
|
||||||
}
|
}
|
||||||
}
|
} else if isOutgoing {
|
||||||
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, attribute.timeout != viewOnceTimeout ? 0.0 : Double(viewOnceTimeout), isOutgoing)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
@ -537,28 +547,34 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
self._ready.set(ready |> map { true })
|
self._ready.set(ready |> map { true })
|
||||||
self.markMessageAsConsumedDisposable.set(self.context.engine.messages.markMessageContentAsConsumedInteractively(messageId: message.id).start())
|
self.markMessageAsConsumedDisposable.set(self.context.engine.messages.markMessageContentAsConsumedInteractively(messageId: message.id).start())
|
||||||
} else {
|
} else {
|
||||||
var beginTimeAndTimeout: (Double, Double)?
|
var beginTimeAndTimeout: (Double, Double, Bool)?
|
||||||
var videoDuration: Double?
|
var videoDuration: Double?
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
videoDuration = file.duration
|
videoDuration = file.duration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isOutgoing = !message.flags.contains(.Incoming)
|
||||||
if let attribute = message.autoclearAttribute {
|
if let attribute = message.autoclearAttribute {
|
||||||
if let countdownBeginTime = attribute.countdownBeginTime {
|
if let countdownBeginTime = attribute.countdownBeginTime {
|
||||||
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
||||||
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)))
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)), isOutgoing)
|
||||||
} else {
|
} else {
|
||||||
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout))
|
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout), isOutgoing)
|
||||||
}
|
}
|
||||||
|
} else if isOutgoing {
|
||||||
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, attribute.timeout != viewOnceTimeout ? 0.0 : Double(viewOnceTimeout), isOutgoing)
|
||||||
}
|
}
|
||||||
} else if let attribute = message.autoremoveAttribute {
|
} else if let attribute = message.autoremoveAttribute {
|
||||||
if let countdownBeginTime = attribute.countdownBeginTime {
|
if let countdownBeginTime = attribute.countdownBeginTime {
|
||||||
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
if let videoDuration = videoDuration, attribute.timeout != viewOnceTimeout {
|
||||||
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)))
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, max(videoDuration, Double(attribute.timeout)), isOutgoing)
|
||||||
} else {
|
} else {
|
||||||
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout))
|
beginTimeAndTimeout = (Double(countdownBeginTime), Double(attribute.timeout), isOutgoing)
|
||||||
}
|
}
|
||||||
|
} else if isOutgoing {
|
||||||
|
beginTimeAndTimeout = (CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, attribute.timeout != viewOnceTimeout ? 0.0 : Double(viewOnceTimeout), isOutgoing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,6 +633,7 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
location: .point(location, .top),
|
location: .point(location, .top),
|
||||||
displayDuration: .default,
|
displayDuration: .default,
|
||||||
inset: 8.0,
|
inset: 8.0,
|
||||||
|
cornerRadius: 8.0,
|
||||||
shouldDismissOnTouch: { _, _ in
|
shouldDismissOnTouch: { _, _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@
|
|||||||
- (void)editorTransitionIn;
|
- (void)editorTransitionIn;
|
||||||
- (void)editorTransitionOut;
|
- (void)editorTransitionOut;
|
||||||
|
|
||||||
|
- (void)onDismiss;
|
||||||
|
|
||||||
- (void)setTabBarUserInteractionEnabled:(bool)enabled;
|
- (void)setTabBarUserInteractionEnabled:(bool)enabled;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -1328,6 +1328,10 @@
|
|||||||
[_captionMixin onAnimateOut];
|
[_captionMixin onAnimateOut];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)onDismiss {
|
||||||
|
[_captionMixin onAnimateOut];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setTransitionOutProgress:(CGFloat)transitionOutProgress manual:(bool)manual
|
- (void)setTransitionOutProgress:(CGFloat)transitionOutProgress manual:(bool)manual
|
||||||
{
|
{
|
||||||
[_captionMixin onAnimateOut];
|
[_captionMixin onAnimateOut];
|
||||||
|
@ -282,7 +282,9 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
|
|||||||
dismissImpl()
|
dismissImpl()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sheetController.sendSilently = {
|
sheetController.sendSilently = { [weak model] in
|
||||||
|
model?.interfaceView.onDismiss()
|
||||||
|
|
||||||
completed(item.asset, true, nil, {
|
completed(item.asset, true, nil, {
|
||||||
dismissImpl()
|
dismissImpl()
|
||||||
})
|
})
|
||||||
|
@ -50,6 +50,7 @@ final class MediaPickerTitleView: UIView {
|
|||||||
transition.updateAlpha(node: self.arrowNode, alpha: self.segmentsHidden ? 1.0 : 0.0)
|
transition.updateAlpha(node: self.arrowNode, alpha: self.segmentsHidden ? 1.0 : 0.0)
|
||||||
transition.updateAlpha(node: self.segmentedControlNode, alpha: self.segmentsHidden ? 0.0 : 1.0)
|
transition.updateAlpha(node: self.segmentedControlNode, alpha: self.segmentsHidden ? 0.0 : 1.0)
|
||||||
self.segmentedControlNode.isUserInteractionEnabled = !self.segmentsHidden
|
self.segmentedControlNode.isUserInteractionEnabled = !self.segmentsHidden
|
||||||
|
self.buttonNode.isUserInteractionEnabled = self.isEnabled && self.segmentsHidden
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ private final class RadialStatusIconContentNodeParameters: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class RadialStatusIconContentNode: RadialStatusContentNode {
|
final class RadialStatusIconContentNode: RadialStatusContentNode {
|
||||||
private let icon: RadialStatusIcon
|
let icon: RadialStatusIcon
|
||||||
|
|
||||||
private var animationNode: FireIconNode?
|
private var animationNode: FireIconNode?
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ final class RadialStatusIconContentNode: RadialStatusContentNode {
|
|||||||
self.isOpaque = false
|
self.isOpaque = false
|
||||||
|
|
||||||
if case .timeout = icon {
|
if case .timeout = icon {
|
||||||
let animationNode = FireIconNode()
|
let animationNode = FireIconNode(animate: true)
|
||||||
self.animationNode = animationNode
|
self.animationNode = animationNode
|
||||||
self.addSubnode(animationNode)
|
self.addSubnode(animationNode)
|
||||||
}
|
}
|
||||||
@ -44,7 +44,14 @@ final class RadialStatusIconContentNode: RadialStatusContentNode {
|
|||||||
override func layout() {
|
override func layout() {
|
||||||
super.layout()
|
super.layout()
|
||||||
|
|
||||||
self.animationNode?.frame = CGRect(x: 6.0, y: 2.0, width: 36.0, height: 36.0)
|
var factor: CGFloat = 0.75
|
||||||
|
var offset: CGFloat = 0.0415
|
||||||
|
if self.bounds.width < 30.0 {
|
||||||
|
factor = 1.0
|
||||||
|
offset = 0.0
|
||||||
|
}
|
||||||
|
let size = floorToScreenPixels(self.bounds.width * factor)
|
||||||
|
self.animationNode?.frame = CGRect(x: floorToScreenPixels((self.bounds.width - size) / 2.0), y: ceil(self.bounds.height * offset), width: size, height: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
||||||
|
@ -224,7 +224,11 @@ public enum RadialStatusNodeState: Equatable {
|
|||||||
case .staticTimeout:
|
case .staticTimeout:
|
||||||
return RadialStatusIconContentNode(icon: .timeout, synchronous: synchronous)
|
return RadialStatusIconContentNode(icon: .timeout, synchronous: synchronous)
|
||||||
case let .secretTimeout(color, icon, beginTime, timeout, sparks):
|
case let .secretTimeout(color, icon, beginTime, timeout, sparks):
|
||||||
return RadialStatusSecretTimeoutContentNode(color: color, beginTime: beginTime, timeout: timeout, icon: icon, sparks: sparks)
|
var animate = true
|
||||||
|
if let current = current as? RadialStatusIconContentNode, case .timeout = current.icon {
|
||||||
|
animate = false
|
||||||
|
}
|
||||||
|
return RadialStatusSecretTimeoutContentNode(color: color, beginTime: beginTime, timeout: timeout, icon: icon, sparks: sparks, animate: animate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,15 @@ private final class RadialStatusSecretTimeoutContentNodeParameters: NSObject {
|
|||||||
let progress: CGFloat
|
let progress: CGFloat
|
||||||
let sparks: Bool
|
let sparks: Bool
|
||||||
let particles: [ContentParticle]
|
let particles: [ContentParticle]
|
||||||
|
let alphaProgress: CGFloat
|
||||||
|
|
||||||
init(color: UIColor, icon: RadialStatusNodeState.SecretTimeoutIcon, progress: CGFloat, sparks: Bool, particles: [ContentParticle]) {
|
init(color: UIColor, icon: RadialStatusNodeState.SecretTimeoutIcon, progress: CGFloat, sparks: Bool, particles: [ContentParticle], alphaProgress: CGFloat) {
|
||||||
self.color = color
|
self.color = color
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.progress = progress
|
self.progress = progress
|
||||||
self.sparks = sparks
|
self.sparks = sparks
|
||||||
self.particles = particles
|
self.particles = particles
|
||||||
|
self.alphaProgress = alphaProgress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +53,17 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
private let icon: RadialStatusNodeState.SecretTimeoutIcon
|
private let icon: RadialStatusNodeState.SecretTimeoutIcon
|
||||||
private let sparks: Bool
|
private let sparks: Bool
|
||||||
|
|
||||||
|
private var animationBeginTime: Double?
|
||||||
|
|
||||||
private var progress: CGFloat = 0.0
|
private var progress: CGFloat = 0.0
|
||||||
|
private var alphaProgress: CGFloat = 0.0
|
||||||
private var particles: [ContentParticle] = []
|
private var particles: [ContentParticle] = []
|
||||||
|
|
||||||
private let animationNode = FireIconNode()
|
private var animationNode: FireIconNode?
|
||||||
|
|
||||||
private var displayLink: CADisplayLink?
|
private var displayLink: CADisplayLink?
|
||||||
|
|
||||||
init(color: UIColor, beginTime: Double, timeout: Double, icon: RadialStatusNodeState.SecretTimeoutIcon, sparks: Bool) {
|
init(color: UIColor, beginTime: Double, timeout: Double, icon: RadialStatusNodeState.SecretTimeoutIcon, sparks: Bool, animate: Bool = true) {
|
||||||
self.color = color
|
self.color = color
|
||||||
self.beginTime = beginTime
|
self.beginTime = beginTime
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
@ -85,7 +90,13 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
self.displayLink?.add(to: RunLoop.main, forMode: .common)
|
self.displayLink?.add(to: RunLoop.main, forMode: .common)
|
||||||
|
|
||||||
if case .flame = icon {
|
if case .flame = icon {
|
||||||
self.addSubnode(self.animationNode)
|
if !animate {
|
||||||
|
self.animationBeginTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
||||||
|
}
|
||||||
|
|
||||||
|
let animationNode = FireIconNode(animate: animate)
|
||||||
|
self.animationNode = animationNode
|
||||||
|
self.addSubnode(animationNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +114,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
offset = 0.08
|
offset = 0.08
|
||||||
}
|
}
|
||||||
let size = floorToScreenPixels(self.bounds.width * factor)
|
let size = floorToScreenPixels(self.bounds.width * factor)
|
||||||
self.animationNode.frame = CGRect(x: floorToScreenPixels((self.bounds.width - size) / 2.0), y: ceil(self.bounds.height * offset), width: size, height: size)
|
self.animationNode?.frame = CGRect(x: floorToScreenPixels((self.bounds.width - size) / 2.0), y: ceil(self.bounds.height * offset), width: size, height: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) {
|
override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) {
|
||||||
@ -132,12 +143,23 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let absoluteTimestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
let absoluteTimestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
||||||
|
|
||||||
|
let alphaProgress: CGFloat
|
||||||
|
if let animationBeginTime = self.animationBeginTime {
|
||||||
|
let fadeInDuration: Double = 0.4
|
||||||
|
alphaProgress = max(0.0, min(1.0, (absoluteTimestamp - animationBeginTime) / fadeInDuration))
|
||||||
|
} else {
|
||||||
|
alphaProgress = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
var progress = min(1.0, CGFloat((absoluteTimestamp - self.beginTime) / self.timeout))
|
var progress = min(1.0, CGFloat((absoluteTimestamp - self.beginTime) / self.timeout))
|
||||||
if self.timeout == 0x7fffffff {
|
if self.timeout == 0x7fffffff {
|
||||||
progress = 0.0
|
progress = 0.0
|
||||||
}
|
}
|
||||||
self.progress = progress
|
self.progress = progress
|
||||||
|
self.alphaProgress = alphaProgress
|
||||||
|
|
||||||
if self.sparks {
|
if self.sparks {
|
||||||
let lineWidth: CGFloat = 1.75
|
let lineWidth: CGFloat = 1.75
|
||||||
@ -193,7 +215,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
||||||
return RadialStatusSecretTimeoutContentNodeParameters(color: self.color, icon: self.icon, progress: self.progress, sparks: self.sparks, particles: self.particles)
|
return RadialStatusSecretTimeoutContentNodeParameters(color: self.color, icon: self.icon, progress: self.progress, sparks: self.sparks, particles: self.particles, alphaProgress: self.alphaProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
@objc override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
||||||
@ -240,6 +262,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
let endAngle: CGFloat = -CGFloat.pi / 2.0 + 2.0 * CGFloat.pi * parameters.progress
|
let endAngle: CGFloat = -CGFloat.pi / 2.0 + 2.0 * CGFloat.pi * parameters.progress
|
||||||
|
|
||||||
if drawArc {
|
if drawArc {
|
||||||
|
context.setAlpha(parameters.alphaProgress)
|
||||||
|
|
||||||
let path = CGMutablePath()
|
let path = CGMutablePath()
|
||||||
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||||
context.addPath(path)
|
context.addPath(path)
|
||||||
@ -248,7 +272,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
|
|
||||||
for particle in parameters.particles {
|
for particle in parameters.particles {
|
||||||
let size: CGFloat = 1.3
|
let size: CGFloat = 1.3
|
||||||
context.setAlpha(particle.alpha)
|
context.setAlpha(particle.alpha * parameters.alphaProgress)
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: particle.position.x - size / 2.0, y: particle.position.y - size / 2.0), size: CGSize(width: size, height: size)))
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: particle.position.x - size / 2.0, y: particle.position.y - size / 2.0), size: CGSize(width: size, height: size)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,9 +280,13 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class FireIconNode: ManagedAnimationNode {
|
final class FireIconNode: ManagedAnimationNode {
|
||||||
init() {
|
init(animate: Bool) {
|
||||||
super.init(size: CGSize(width: 100.0, height: 100.0))
|
super.init(size: CGSize(width: 100.0, height: 100.0))
|
||||||
|
|
||||||
self.trackTo(item: ManagedAnimationItem(source: .local("anim_autoremove_on"), frames: .range(startFrame: 0, endFrame: 120), duration: 2.0))
|
if animate {
|
||||||
|
self.trackTo(item: ManagedAnimationItem(source: .local("anim_autoremove_on"), frames: .range(startFrame: 0, endFrame: 120), duration: 2.0))
|
||||||
|
} else {
|
||||||
|
self.trackTo(item: ManagedAnimationItem(source: .local("anim_autoremove_on"), frames: .range(startFrame: 120, endFrame: 120), duration: 0.001))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: true, isGrouped: isGrouped, passFetchProgress: false, forceNoBigParts: false, peerId: peerId, messageId: messageId, text: text, attributes: attributes, file: file)
|
return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: true, isGrouped: isGrouped, passFetchProgress: false, forceNoBigParts: false, peerId: peerId, messageId: messageId, text: text, attributes: attributes, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, file: file)
|
||||||
} else {
|
} else {
|
||||||
if forceReupload {
|
if forceReupload {
|
||||||
let mediaReference: AnyMediaReference
|
let mediaReference: AnyMediaReference
|
||||||
@ -156,7 +156,7 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
|
|||||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), ttlSeconds: nil, query: emojiSearchQuery), text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), ttlSeconds: nil, query: emojiSearchQuery), text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: isGrouped, passFetchProgress: passFetchProgress, forceNoBigParts: forceNoBigParts, peerId: peerId, messageId: messageId, text: text, attributes: attributes, file: file)
|
return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: isGrouped, passFetchProgress: passFetchProgress, forceNoBigParts: forceNoBigParts, peerId: peerId, messageId: messageId, text: text, attributes: attributes, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, file: file)
|
||||||
}
|
}
|
||||||
} else if let contact = media as? TelegramMediaContact {
|
} else if let contact = media as? TelegramMediaContact {
|
||||||
let input = Api.InputMedia.inputMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName, vcard: contact.vCardData ?? "")
|
let input = Api.InputMedia.inputMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName, vcard: contact.vCardData ?? "")
|
||||||
@ -296,7 +296,7 @@ private func maybePredownloadedFileResource(postbox: Postbox, auxiliaryMethods:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if "".isEmpty {
|
if !"".isEmpty {
|
||||||
return .single(.none)
|
return .single(.none)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -655,7 +655,7 @@ public func statsCategoryForFileWithAttributes(_ attributes: [TelegramMediaFileA
|
|||||||
return .file
|
return .file
|
||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, forceReupload: Bool, isGrouped: Bool, passFetchProgress: Bool, forceNoBigParts: Bool, peerId: PeerId, messageId: MessageId?, text: String, attributes: [MessageAttribute], file: TelegramMediaFile) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> {
|
private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, forceReupload: Bool, isGrouped: Bool, passFetchProgress: Bool, forceNoBigParts: Bool, peerId: PeerId, messageId: MessageId?, text: String, attributes: [MessageAttribute], autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, file: TelegramMediaFile) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> {
|
||||||
return maybePredownloadedFileResource(postbox: postbox, auxiliaryMethods: auxiliaryMethods, peerId: peerId, resource: file.resource, forceRefresh: forceReupload)
|
return maybePredownloadedFileResource(postbox: postbox, auxiliaryMethods: auxiliaryMethods, peerId: peerId, resource: file.resource, forceRefresh: forceReupload)
|
||||||
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||||
var referenceKey: CachedSentMediaReferenceKey?
|
var referenceKey: CachedSentMediaReferenceKey?
|
||||||
@ -663,6 +663,12 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
|||||||
case let .media(media, key):
|
case let .media(media, key):
|
||||||
if !forceReupload, let file = media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference {
|
if !forceReupload, let file = media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference {
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
|
var ttlSeconds: Int32?
|
||||||
|
if let autoclearMessageAttribute = autoclearMessageAttribute {
|
||||||
|
flags |= 1 << 0
|
||||||
|
ttlSeconds = autoclearMessageAttribute.timeout
|
||||||
|
}
|
||||||
|
|
||||||
for attribute in attributes {
|
for attribute in attributes {
|
||||||
if let _ = attribute as? MediaSpoilerMessageAttribute {
|
if let _ = attribute as? MediaSpoilerMessageAttribute {
|
||||||
flags |= 1 << 2
|
flags |= 1 << 2
|
||||||
@ -671,7 +677,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
|||||||
|
|
||||||
return .single(.progress(1.0))
|
return .single(.progress(1.0))
|
||||||
|> then(
|
|> then(
|
||||||
.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: nil, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: ttlSeconds, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
referenceKey = key
|
referenceKey = key
|
||||||
|
@ -18,7 +18,9 @@ public final class AttachMenuBots: Equatable, Codable {
|
|||||||
case `default` = 0
|
case `default` = 0
|
||||||
case iOSStatic
|
case iOSStatic
|
||||||
case iOSAnimated
|
case iOSAnimated
|
||||||
|
case iOSSettingsStatic
|
||||||
case macOSAnimated
|
case macOSAnimated
|
||||||
|
case macOSSettingsStatic
|
||||||
case placeholder
|
case placeholder
|
||||||
|
|
||||||
init?(string: String) {
|
init?(string: String) {
|
||||||
@ -29,6 +31,10 @@ public final class AttachMenuBots: Equatable, Codable {
|
|||||||
self = .iOSStatic
|
self = .iOSStatic
|
||||||
case "ios_animated":
|
case "ios_animated":
|
||||||
self = .iOSAnimated
|
self = .iOSAnimated
|
||||||
|
case "ios_side_menu_static":
|
||||||
|
self = .iOSSettingsStatic
|
||||||
|
case "macos_side_menu_static":
|
||||||
|
self = .macOSSettingsStatic
|
||||||
case "macos_animated":
|
case "macos_animated":
|
||||||
self = .macOSAnimated
|
self = .macOSAnimated
|
||||||
case "placeholder_static":
|
case "placeholder_static":
|
||||||
|
@ -30,7 +30,6 @@ swift_library(
|
|||||||
"//submodules/UndoUI:UndoUI",
|
"//submodules/UndoUI:UndoUI",
|
||||||
"//submodules/ContextUI:ContextUI",
|
"//submodules/ContextUI:ContextUI",
|
||||||
"//submodules/GalleryUI:GalleryUI",
|
"//submodules/GalleryUI:GalleryUI",
|
||||||
"//submodules/AttachmentTextInputPanelNode:AttachmentTextInputPanelNode",
|
|
||||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||||
"//submodules/TelegramNotices:TelegramNotices",
|
"//submodules/TelegramNotices:TelegramNotices",
|
||||||
"//submodules/StickerPeekUI:StickerPeekUI",
|
"//submodules/StickerPeekUI:StickerPeekUI",
|
||||||
@ -40,6 +39,7 @@ swift_library(
|
|||||||
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen",
|
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen",
|
||||||
"//submodules/StickerPackPreviewUI",
|
"//submodules/StickerPackPreviewUI",
|
||||||
"//submodules/TelegramUI/Components/EntityKeyboardGifContent:EntityKeyboardGifContent",
|
"//submodules/TelegramUI/Components/EntityKeyboardGifContent:EntityKeyboardGifContent",
|
||||||
|
"//submodules/TelegramUI/Components/LegacyMessageInputPanelInputView:LegacyMessageInputPanelInputView",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -32,6 +32,7 @@ import FeaturedStickersScreen
|
|||||||
import Pasteboard
|
import Pasteboard
|
||||||
import StickerPackPreviewUI
|
import StickerPackPreviewUI
|
||||||
import EntityKeyboardGifContent
|
import EntityKeyboardGifContent
|
||||||
|
import LegacyMessageInputPanelInputView
|
||||||
|
|
||||||
public final class EmptyInputView: UIView, UIInputViewAudioFeedback {
|
public final class EmptyInputView: UIView, UIInputViewAudioFeedback {
|
||||||
public var enableInputClicksWhenVisible: Bool {
|
public var enableInputClicksWhenVisible: Bool {
|
||||||
@ -2080,7 +2081,7 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class EntityInputView: UIInputView, AttachmentTextInputPanelInputView, UIInputViewAudioFeedback {
|
public final class EntityInputView: UIInputView, LegacyMessageInputPanelInputView, AttachmentTextInputPanelInputView, UIInputViewAudioFeedback {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
|
|
||||||
public var insertText: ((NSAttributedString) -> Void)?
|
public var insertText: ((NSAttributedString) -> Void)?
|
||||||
|
@ -21,7 +21,9 @@ swift_library(
|
|||||||
"//submodules/TelegramPresentationData",
|
"//submodules/TelegramPresentationData",
|
||||||
"//submodules/ContextUI",
|
"//submodules/ContextUI",
|
||||||
"//submodules/TooltipUI",
|
"//submodules/TooltipUI",
|
||||||
|
"//submodules/UndoUI",
|
||||||
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
||||||
|
"//submodules/TelegramUI/Components/LegacyMessageInputPanelInputView",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -13,6 +13,8 @@ import MessageInputPanelComponent
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import ContextUI
|
import ContextUI
|
||||||
import TooltipUI
|
import TooltipUI
|
||||||
|
import LegacyMessageInputPanelInputView
|
||||||
|
import UndoUI
|
||||||
|
|
||||||
public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
@ -20,7 +22,8 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
private let isScheduledMessages: Bool
|
private let isScheduledMessages: Bool
|
||||||
private let present: (ViewController) -> Void
|
private let present: (ViewController) -> Void
|
||||||
private let presentInGlobalOverlay: (ViewController) -> Void
|
private let presentInGlobalOverlay: (ViewController) -> Void
|
||||||
|
private let makeEntityInputView: () -> LegacyMessageInputPanelInputView?
|
||||||
|
|
||||||
private let state = ComponentState()
|
private let state = ComponentState()
|
||||||
private let inputPanelExternalState = MessageInputPanelComponent.ExternalState()
|
private let inputPanelExternalState = MessageInputPanelComponent.ExternalState()
|
||||||
private let inputPanel = ComponentView<Empty>()
|
private let inputPanel = ComponentView<Empty>()
|
||||||
@ -31,6 +34,9 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
|
|
||||||
private let hapticFeedback = HapticFeedback()
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
|
private var inputView: LegacyMessageInputPanelInputView?
|
||||||
|
private var isEmojiKeyboardActive = false
|
||||||
|
|
||||||
private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, keyboardHeight: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, metrics: LayoutMetrics)?
|
private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, keyboardHeight: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, metrics: LayoutMetrics)?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
@ -38,13 +44,15 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
chatLocation: ChatLocation,
|
chatLocation: ChatLocation,
|
||||||
isScheduledMessages: Bool,
|
isScheduledMessages: Bool,
|
||||||
present: @escaping (ViewController) -> Void,
|
present: @escaping (ViewController) -> Void,
|
||||||
presentInGlobalOverlay: @escaping (ViewController) -> Void
|
presentInGlobalOverlay: @escaping (ViewController) -> Void,
|
||||||
|
makeEntityInputView: @escaping () -> LegacyMessageInputPanelInputView?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
self.isScheduledMessages = isScheduledMessages
|
self.isScheduledMessages = isScheduledMessages
|
||||||
self.present = present
|
self.present = present
|
||||||
self.presentInGlobalOverlay = presentInGlobalOverlay
|
self.presentInGlobalOverlay = presentInGlobalOverlay
|
||||||
|
self.makeEntityInputView = makeEntityInputView
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -98,6 +106,8 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
|
|
||||||
public func dismissInput() {
|
public func dismissInput() {
|
||||||
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||||
|
self.isEmojiKeyboardActive = false
|
||||||
|
self.inputView = nil
|
||||||
view.deactivateInput()
|
view.deactivateInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,8 +181,12 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
queryTypes: [.mention],
|
queryTypes: [.mention],
|
||||||
alwaysDarkWhenHasText: false,
|
alwaysDarkWhenHasText: false,
|
||||||
resetInputContents: resetInputContents,
|
resetInputContents: resetInputContents,
|
||||||
nextInputMode: { _ in
|
nextInputMode: { [weak self] _ in
|
||||||
return .emoji
|
if self?.isEmojiKeyboardActive == true {
|
||||||
|
return .text
|
||||||
|
} else {
|
||||||
|
return .emoji
|
||||||
|
}
|
||||||
},
|
},
|
||||||
areVoiceMessagesAvailable: false,
|
areVoiceMessagesAvailable: false,
|
||||||
presentController: self.present,
|
presentController: self.present,
|
||||||
@ -193,7 +207,11 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
myReaction: nil,
|
myReaction: nil,
|
||||||
likeAction: nil,
|
likeAction: nil,
|
||||||
likeOptionsAction: nil,
|
likeOptionsAction: nil,
|
||||||
inputModeAction: nil,
|
inputModeAction: { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.toggleInputMode()
|
||||||
|
}
|
||||||
|
},
|
||||||
timeoutAction: self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudUser && !self.isScheduledMessages ? { [weak self] sourceView, gesture in
|
timeoutAction: self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudUser && !self.isScheduledMessages ? { [weak self] sourceView, gesture in
|
||||||
if let self {
|
if let self {
|
||||||
self.presentTimeoutSetup(sourceView: sourceView, gesture: gesture)
|
self.presentTimeoutSetup(sourceView: sourceView, gesture: gesture)
|
||||||
@ -217,6 +235,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
bottomInset: 0.0,
|
bottomInset: 0.0,
|
||||||
isFormattingLocked: false,
|
isFormattingLocked: false,
|
||||||
hideKeyboard: false,
|
hideKeyboard: false,
|
||||||
|
customInputView: self.inputView,
|
||||||
forceIsEditing: false,
|
forceIsEditing: false,
|
||||||
disabledPlaceholder: nil,
|
disabledPlaceholder: nil,
|
||||||
isChannel: false,
|
isChannel: false,
|
||||||
@ -248,6 +267,47 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
return inputPanelSize.height - 8.0
|
return inputPanelSize.height - 8.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func toggleInputMode() {
|
||||||
|
self.isEmojiKeyboardActive = !self.isEmojiKeyboardActive
|
||||||
|
|
||||||
|
if self.isEmojiKeyboardActive {
|
||||||
|
let inputView = self.makeEntityInputView()
|
||||||
|
inputView?.insertText = { [weak self] text in
|
||||||
|
if let self {
|
||||||
|
self.inputPanelExternalState.insertText(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputView?.deleteBackwards = { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.inputPanelExternalState.deleteBackward()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputView?.switchToKeyboard = { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.isEmojiKeyboardActive = false
|
||||||
|
self.inputView = nil
|
||||||
|
self.update(transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputView?.presentController = { [weak self] c in
|
||||||
|
if let self {
|
||||||
|
if !(c is UndoOverlayController) {
|
||||||
|
self.isEmojiKeyboardActive = false
|
||||||
|
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||||
|
view.deactivateInput(force: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.present(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.inputView = inputView
|
||||||
|
self.update(transition: .immediate)
|
||||||
|
} else {
|
||||||
|
self.inputView = nil
|
||||||
|
self.update(transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func presentTimeoutSetup(sourceView: UIView, gesture: ContextGesture?) {
|
private func presentTimeoutSetup(sourceView: UIView, gesture: ContextGesture?) {
|
||||||
self.hapticFeedback.impact(.light)
|
self.hapticFeedback.impact(.light)
|
||||||
|
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "LegacyMessageInputPanelInputView",
|
||||||
|
module_name = "LegacyMessageInputPanelInputView",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||||
|
"//submodules/Display",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
@ -0,0 +1,11 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
|
||||||
|
public protocol LegacyMessageInputPanelInputView: UIView {
|
||||||
|
var insertText: ((NSAttributedString) -> Void)? { get set }
|
||||||
|
var deleteBackwards: (() -> Void)? { get set }
|
||||||
|
var switchToKeyboard: (() -> Void)? { get set }
|
||||||
|
var presentController: ((ViewController) -> Void)? { get set }
|
||||||
|
}
|
@ -1188,6 +1188,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
bottomInset: 0.0,
|
bottomInset: 0.0,
|
||||||
isFormattingLocked: !state.isPremium,
|
isFormattingLocked: !state.isPremium,
|
||||||
hideKeyboard: self.currentInputMode == .emoji,
|
hideKeyboard: self.currentInputMode == .emoji,
|
||||||
|
customInputView: nil,
|
||||||
forceIsEditing: self.currentInputMode == .emoji,
|
forceIsEditing: self.currentInputMode == .emoji,
|
||||||
disabledPlaceholder: nil,
|
disabledPlaceholder: nil,
|
||||||
isChannel: false,
|
isChannel: false,
|
||||||
|
@ -290,6 +290,7 @@ final class StoryPreviewComponent: Component {
|
|||||||
bottomInset: 0.0,
|
bottomInset: 0.0,
|
||||||
isFormattingLocked: false,
|
isFormattingLocked: false,
|
||||||
hideKeyboard: false,
|
hideKeyboard: false,
|
||||||
|
customInputView: nil,
|
||||||
forceIsEditing: false,
|
forceIsEditing: false,
|
||||||
disabledPlaceholder: nil,
|
disabledPlaceholder: nil,
|
||||||
isChannel: false,
|
isChannel: false,
|
||||||
|
@ -142,6 +142,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
public let bottomInset: CGFloat
|
public let bottomInset: CGFloat
|
||||||
public let isFormattingLocked: Bool
|
public let isFormattingLocked: Bool
|
||||||
public let hideKeyboard: Bool
|
public let hideKeyboard: Bool
|
||||||
|
public let customInputView: UIView?
|
||||||
public let forceIsEditing: Bool
|
public let forceIsEditing: Bool
|
||||||
public let disabledPlaceholder: String?
|
public let disabledPlaceholder: String?
|
||||||
public let isChannel: Bool
|
public let isChannel: Bool
|
||||||
@ -194,6 +195,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
bottomInset: CGFloat,
|
bottomInset: CGFloat,
|
||||||
isFormattingLocked: Bool,
|
isFormattingLocked: Bool,
|
||||||
hideKeyboard: Bool,
|
hideKeyboard: Bool,
|
||||||
|
customInputView: UIView?,
|
||||||
forceIsEditing: Bool,
|
forceIsEditing: Bool,
|
||||||
disabledPlaceholder: String?,
|
disabledPlaceholder: String?,
|
||||||
isChannel: Bool,
|
isChannel: Bool,
|
||||||
@ -245,6 +247,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
self.bottomInset = bottomInset
|
self.bottomInset = bottomInset
|
||||||
self.isFormattingLocked = isFormattingLocked
|
self.isFormattingLocked = isFormattingLocked
|
||||||
self.hideKeyboard = hideKeyboard
|
self.hideKeyboard = hideKeyboard
|
||||||
|
self.customInputView = customInputView
|
||||||
self.forceIsEditing = forceIsEditing
|
self.forceIsEditing = forceIsEditing
|
||||||
self.disabledPlaceholder = disabledPlaceholder
|
self.disabledPlaceholder = disabledPlaceholder
|
||||||
self.isChannel = isChannel
|
self.isChannel = isChannel
|
||||||
@ -328,6 +331,9 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
if lhs.hideKeyboard != rhs.hideKeyboard {
|
if lhs.hideKeyboard != rhs.hideKeyboard {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.customInputView !== rhs.customInputView {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.forceIsEditing != rhs.forceIsEditing {
|
if lhs.forceIsEditing != rhs.forceIsEditing {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -713,6 +719,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
textColor: UIColor(rgb: 0xffffff),
|
textColor: UIColor(rgb: 0xffffff),
|
||||||
insets: UIEdgeInsets(top: 9.0, left: 8.0, bottom: 10.0, right: 48.0),
|
insets: UIEdgeInsets(top: 9.0, left: 8.0, bottom: 10.0, right: 48.0),
|
||||||
hideKeyboard: component.hideKeyboard,
|
hideKeyboard: component.hideKeyboard,
|
||||||
|
customInputView: component.customInputView,
|
||||||
resetText: component.resetInputContents.flatMap { resetInputContents in
|
resetText: component.resetInputContents.flatMap { resetInputContents in
|
||||||
switch resetInputContents {
|
switch resetInputContents {
|
||||||
case let .text(value):
|
case let .text(value):
|
||||||
|
@ -2893,6 +2893,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
bottomInset: component.inputHeight != 0.0 || inputNodeVisible ? 0.0 : bottomContentInset,
|
bottomInset: component.inputHeight != 0.0 || inputNodeVisible ? 0.0 : bottomContentInset,
|
||||||
isFormattingLocked: false,
|
isFormattingLocked: false,
|
||||||
hideKeyboard: self.sendMessageContext.currentInputMode == .media,
|
hideKeyboard: self.sendMessageContext.currentInputMode == .media,
|
||||||
|
customInputView: nil,
|
||||||
forceIsEditing: self.sendMessageContext.currentInputMode == .media,
|
forceIsEditing: self.sendMessageContext.currentInputMode == .media,
|
||||||
disabledPlaceholder: disabledPlaceholder,
|
disabledPlaceholder: disabledPlaceholder,
|
||||||
isChannel: isChannel,
|
isChannel: isChannel,
|
||||||
|
@ -1412,7 +1412,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
peerType.insert(.sameBot)
|
peerType.insert(.sameBot)
|
||||||
peerType.remove(.bot)
|
peerType.remove(.bot)
|
||||||
}
|
}
|
||||||
let button: AttachmentButtonType = .app(bot.peer, bot.shortName, bot.icons)
|
let button: AttachmentButtonType = .app(bot)
|
||||||
if !bot.peerTypes.intersection(peerType).isEmpty {
|
if !bot.peerTypes.intersection(peerType).isEmpty {
|
||||||
buttons.insert(button, at: 1)
|
buttons.insert(button, at: 1)
|
||||||
|
|
||||||
@ -1784,7 +1784,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
}*/
|
}*/
|
||||||
//TODO:gift controller
|
//TODO:gift controller
|
||||||
break
|
break
|
||||||
case let .app(bot, botName, _):
|
case let .app(bot):
|
||||||
var payload: String?
|
var payload: String?
|
||||||
var fromAttachMenu = true
|
var fromAttachMenu = true
|
||||||
/*if case let .bot(_, botPayload, _) = subject {
|
/*if case let .bot(_, botPayload, _) = subject {
|
||||||
@ -1793,7 +1793,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
}*/
|
}*/
|
||||||
payload = nil
|
payload = nil
|
||||||
fromAttachMenu = true
|
fromAttachMenu = true
|
||||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false, forceHasSettings: false)
|
let params = WebAppParameters(peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false, forceHasSettings: false)
|
||||||
let theme = component.theme
|
let theme = component.theme
|
||||||
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
||||||
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)
|
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)
|
||||||
|
@ -90,6 +90,7 @@ public final class TextFieldComponent: Component {
|
|||||||
public let textColor: UIColor
|
public let textColor: UIColor
|
||||||
public let insets: UIEdgeInsets
|
public let insets: UIEdgeInsets
|
||||||
public let hideKeyboard: Bool
|
public let hideKeyboard: Bool
|
||||||
|
public let customInputView: UIView?
|
||||||
public let resetText: NSAttributedString?
|
public let resetText: NSAttributedString?
|
||||||
public let isOneLineWhenUnfocused: Bool
|
public let isOneLineWhenUnfocused: Bool
|
||||||
public let formatMenuAvailability: FormatMenuAvailability
|
public let formatMenuAvailability: FormatMenuAvailability
|
||||||
@ -105,6 +106,7 @@ public final class TextFieldComponent: Component {
|
|||||||
textColor: UIColor,
|
textColor: UIColor,
|
||||||
insets: UIEdgeInsets,
|
insets: UIEdgeInsets,
|
||||||
hideKeyboard: Bool,
|
hideKeyboard: Bool,
|
||||||
|
customInputView: UIView?,
|
||||||
resetText: NSAttributedString?,
|
resetText: NSAttributedString?,
|
||||||
isOneLineWhenUnfocused: Bool,
|
isOneLineWhenUnfocused: Bool,
|
||||||
formatMenuAvailability: FormatMenuAvailability,
|
formatMenuAvailability: FormatMenuAvailability,
|
||||||
@ -119,6 +121,7 @@ public final class TextFieldComponent: Component {
|
|||||||
self.textColor = textColor
|
self.textColor = textColor
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.hideKeyboard = hideKeyboard
|
self.hideKeyboard = hideKeyboard
|
||||||
|
self.customInputView = customInputView
|
||||||
self.resetText = resetText
|
self.resetText = resetText
|
||||||
self.isOneLineWhenUnfocused = isOneLineWhenUnfocused
|
self.isOneLineWhenUnfocused = isOneLineWhenUnfocused
|
||||||
self.formatMenuAvailability = formatMenuAvailability
|
self.formatMenuAvailability = formatMenuAvailability
|
||||||
@ -146,6 +149,9 @@ public final class TextFieldComponent: Component {
|
|||||||
if lhs.hideKeyboard != rhs.hideKeyboard {
|
if lhs.hideKeyboard != rhs.hideKeyboard {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.customInputView !== rhs.customInputView {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.resetText != rhs.resetText {
|
if lhs.resetText != rhs.resetText {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -816,9 +822,14 @@ public final class TextFieldComponent: Component {
|
|||||||
} while glyphIndexForStringStart < NSMaxRange(glyphRange) && !NSLocationInRange(glyphRange.location, lineRange)
|
} while glyphIndexForStringStart < NSMaxRange(glyphRange) && !NSLocationInRange(glyphRange.location, lineRange)
|
||||||
|
|
||||||
let padding = self.textView.textContainerInset.left
|
let padding = self.textView.textContainerInset.left
|
||||||
let rightmostX = lineRect.maxX + padding
|
var rightmostX = lineRect.maxX + padding
|
||||||
let rightmostY = lineRect.minY + self.textView.textContainerInset.top
|
let rightmostY = lineRect.minY + self.textView.textContainerInset.top
|
||||||
|
|
||||||
|
let stringIndex = self.textView.text.index(self.textView.text.startIndex, offsetBy: lineRange.location + lineRange.length - 1)
|
||||||
|
if self.textView.text[stringIndex] == " " {
|
||||||
|
rightmostX -= 3.0
|
||||||
|
}
|
||||||
|
|
||||||
return CGPoint(x: rightmostX, y: rightmostY)
|
return CGPoint(x: rightmostX, y: rightmostY)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,7 +893,14 @@ public final class TextFieldComponent: Component {
|
|||||||
component.externalState.isEditing = isEditing
|
component.externalState.isEditing = isEditing
|
||||||
component.externalState.textLength = self.textStorage.string.count
|
component.externalState.textLength = self.textStorage.string.count
|
||||||
|
|
||||||
if component.hideKeyboard {
|
if let inputView = component.customInputView {
|
||||||
|
if self.textView.inputView == nil {
|
||||||
|
self.textView.inputView = inputView
|
||||||
|
if self.textView.isFirstResponder {
|
||||||
|
self.textView.reloadInputViews()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if component.hideKeyboard {
|
||||||
if self.textView.inputView == nil {
|
if self.textView.inputView == nil {
|
||||||
self.textView.inputView = EmptyInputView()
|
self.textView.inputView = EmptyInputView()
|
||||||
if self.textView.isFirstResponder {
|
if self.textView.isFirstResponder {
|
||||||
@ -916,7 +934,7 @@ public final class TextFieldComponent: Component {
|
|||||||
view.alpha = 0.0
|
view.alpha = 0.0
|
||||||
self.textView.addSubview(view)
|
self.textView.addSubview(view)
|
||||||
}
|
}
|
||||||
let ellipsisFrame = CGRect(origin: CGPoint(x: position.x - 11.0, y: position.y), size: ellipsisSize)
|
let ellipsisFrame = CGRect(origin: CGPoint(x: position.x - 8.0, y: position.y), size: ellipsisSize)
|
||||||
transition.setFrame(view: view, frame: ellipsisFrame)
|
transition.setFrame(view: view, frame: ellipsisFrame)
|
||||||
|
|
||||||
let hasMoreThanOneLine = ellipsisFrame.maxY < self.textView.contentSize.height - 12.0
|
let hasMoreThanOneLine = ellipsisFrame.maxY < self.textView.contentSize.height - 12.0
|
||||||
|
@ -13367,7 +13367,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
peerType.insert(.sameBot)
|
peerType.insert(.sameBot)
|
||||||
peerType.remove(.bot)
|
peerType.remove(.bot)
|
||||||
}
|
}
|
||||||
let button: AttachmentButtonType = .app(bot.peer, bot.shortName, bot.icons)
|
let button: AttachmentButtonType = .app(bot)
|
||||||
if !bot.peerTypes.intersection(peerType).isEmpty {
|
if !bot.peerTypes.intersection(peerType).isEmpty {
|
||||||
buttons.insert(button, at: 1)
|
buttons.insert(button, at: 1)
|
||||||
|
|
||||||
@ -13408,17 +13408,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if !premiumGiftOptions.isEmpty {
|
if !premiumGiftOptions.isEmpty {
|
||||||
buttons.insert(.gift, at: 1)
|
buttons.insert(.gift, at: 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let initialButton = initialButton else {
|
guard let initialButton = initialButton else {
|
||||||
if case let .bot(botId, botPayload, botJustInstalled) = subject {
|
if case let .bot(botId, botPayload, botJustInstalled) = subject {
|
||||||
if let button = allButtons.first(where: { button in
|
if let button = allButtons.first(where: { button in
|
||||||
if case let .app(botPeer, _, _) = button, botPeer.id == botId {
|
if case let .app(bot) = button, bot.peer.id == botId {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}), case let .app(_, botName, _) = button {
|
}), case let .app(bot) = button {
|
||||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: botJustInstalled ? strongSelf.presentationData.strings.WebApp_AddToAttachmentSucceeded(botName).string : strongSelf.presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError, timeout: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
|
let content: UndoOverlayContent
|
||||||
|
if botJustInstalled {
|
||||||
|
if bot.flags.contains(.showInSettings) {
|
||||||
|
content = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsSettingsAdded(bot.shortName).string)
|
||||||
|
} else {
|
||||||
|
content = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsAdded(bot.shortName).string)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content = .info(title: nil, text: strongSelf.presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError, timeout: nil)
|
||||||
|
}
|
||||||
|
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||||
} else {
|
} else {
|
||||||
let _ = (context.engine.messages.getAttachMenuBot(botId: botId)
|
let _ = (context.engine.messages.getAttachMenuBot(botId: botId)
|
||||||
|> deliverOnMainQueue).start(next: { bot in
|
|> deliverOnMainQueue).start(next: { bot in
|
||||||
@ -13746,14 +13756,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
let _ = ApplicationSpecificNotice.incrementDismissedPremiumGiftSuggestion(accountManager: context.sharedContext.accountManager, peerId: peer.id).start()
|
let _ = ApplicationSpecificNotice.incrementDismissedPremiumGiftSuggestion(accountManager: context.sharedContext.accountManager, peerId: peer.id).start()
|
||||||
}
|
}
|
||||||
case let .app(bot, botName, _):
|
case let .app(bot):
|
||||||
var payload: String?
|
var payload: String?
|
||||||
var fromAttachMenu = true
|
var fromAttachMenu = true
|
||||||
if case let .bot(_, botPayload, _) = subject {
|
if case let .bot(_, botPayload, _) = subject {
|
||||||
payload = botPayload
|
payload = botPayload
|
||||||
fromAttachMenu = false
|
fromAttachMenu = false
|
||||||
}
|
}
|
||||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false, forceHasSettings: false)
|
let params = WebAppParameters(peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false, forceHasSettings: false)
|
||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId)
|
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId)
|
||||||
controller.openUrl = { [weak self] url, concealed, commit in
|
controller.openUrl = { [weak self] url, concealed, commit in
|
||||||
@ -13780,6 +13790,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
attachmentController.navigationPresentation = .flatModal
|
attachmentController.navigationPresentation = .flatModal
|
||||||
strongSelf.push(attachmentController)
|
strongSelf.push(attachmentController)
|
||||||
strongSelf.attachmentController = attachmentController
|
strongSelf.attachmentController = attachmentController
|
||||||
|
|
||||||
|
if case let .bot(botId, _, botJustInstalled) = subject, botJustInstalled {
|
||||||
|
if let button = allButtons.first(where: { button in
|
||||||
|
if case let .app(bot) = button, bot.peer.id == botId {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}), case let .app(bot) = button {
|
||||||
|
Queue.mainQueue().after(0.3) {
|
||||||
|
let content: UndoOverlayContent
|
||||||
|
if bot.flags.contains(.showInSettings) {
|
||||||
|
content = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsSettingsAdded(bot.shortName).string)
|
||||||
|
} else {
|
||||||
|
content = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsAdded(bot.shortName).string)
|
||||||
|
}
|
||||||
|
attachmentController.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: true, action: { _ in return false }), in: .current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if inputIsActive {
|
if inputIsActive {
|
||||||
|
@ -1483,7 +1483,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuForward, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuForward, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
interfaceInteraction.forwardMessages(selectAll ? messages : [message])
|
interfaceInteraction.forwardMessages(selectAll || isImage ? messages : [message])
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
@ -4192,10 +4192,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
case let .message(message, _, _, _, _):
|
case let .message(message, _, _, _, _):
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let action = media as? TelegramMediaAction {
|
if let action = media as? TelegramMediaAction {
|
||||||
if case .phoneCall = action.action { } else {
|
if case .phoneCall = action.action {
|
||||||
|
} else {
|
||||||
canHaveSelection = false
|
canHaveSelection = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
} else if media is TelegramMediaExpiredContent {
|
||||||
|
canHaveSelection = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if message.adAttribute != nil {
|
if message.adAttribute != nil {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
final class PeerInfoScreenDisclosureItem: PeerInfoScreenItem {
|
final class PeerInfoScreenDisclosureItem: PeerInfoScreenItem {
|
||||||
@ -31,13 +32,15 @@ final class PeerInfoScreenDisclosureItem: PeerInfoScreenItem {
|
|||||||
let label: Label
|
let label: Label
|
||||||
let text: String
|
let text: String
|
||||||
let icon: UIImage?
|
let icon: UIImage?
|
||||||
|
let iconSignal: Signal<UIImage?, NoError>?
|
||||||
let action: (() -> Void)?
|
let action: (() -> Void)?
|
||||||
|
|
||||||
init(id: AnyHashable, label: Label = .none, text: String, icon: UIImage? = nil, action: (() -> Void)?) {
|
init(id: AnyHashable, label: Label = .none, text: String, icon: UIImage? = nil, iconSignal: Signal<UIImage?, NoError>? = nil, action: (() -> Void)?) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.label = label
|
self.label = label
|
||||||
self.text = text
|
self.text = text
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
|
self.iconSignal = iconSignal
|
||||||
self.action = action
|
self.action = action
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +60,8 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode {
|
|||||||
private let bottomSeparatorNode: ASDisplayNode
|
private let bottomSeparatorNode: ASDisplayNode
|
||||||
private let activateArea: AccessibilityAreaNode
|
private let activateArea: AccessibilityAreaNode
|
||||||
|
|
||||||
|
private var iconDisposable: Disposable?
|
||||||
|
|
||||||
private var item: PeerInfoScreenDisclosureItem?
|
private var item: PeerInfoScreenDisclosureItem?
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
@ -109,6 +114,10 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode {
|
|||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.iconDisposable?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
guard let item = item as? PeerInfoScreenDisclosureItem else {
|
guard let item = item as? PeerInfoScreenDisclosureItem else {
|
||||||
return 10.0
|
return 10.0
|
||||||
@ -120,9 +129,9 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode {
|
|||||||
self.selectionNode.pressed = item.action
|
self.selectionNode.pressed = item.action
|
||||||
|
|
||||||
let sideInset: CGFloat = 16.0 + safeInsets.left
|
let sideInset: CGFloat = 16.0 + safeInsets.left
|
||||||
let leftInset = (item.icon == nil ? sideInset : sideInset + 29.0 + 16.0)
|
let leftInset = (item.icon == nil && item.iconSignal == nil ? sideInset : sideInset + 29.0 + 16.0)
|
||||||
let rightInset = sideInset + 18.0
|
let rightInset = sideInset + 18.0
|
||||||
let separatorInset = item.icon == nil ? sideInset : leftInset - 1.0
|
let separatorInset = item.icon == nil && item.iconSignal == nil ? sideInset : leftInset - 1.0
|
||||||
let titleFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize)
|
let titleFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize)
|
||||||
|
|
||||||
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
@ -149,12 +158,28 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode {
|
|||||||
|
|
||||||
let height = textSize.height + 24.0
|
let height = textSize.height + 24.0
|
||||||
|
|
||||||
if let icon = item.icon {
|
if item.icon != nil || item.iconSignal != nil {
|
||||||
if self.iconNode.supernode == nil {
|
if self.iconNode.supernode == nil {
|
||||||
self.addSubnode(self.iconNode)
|
self.addSubnode(self.iconNode)
|
||||||
}
|
}
|
||||||
self.iconNode.image = icon
|
let iconSize: CGSize
|
||||||
let iconFrame = CGRect(origin: CGPoint(x: sideInset, y: floorToScreenPixels((height - icon.size.height) / 2.0)), size: icon.size)
|
if let icon = item.icon {
|
||||||
|
self.iconNode.image = icon
|
||||||
|
iconSize = icon.size
|
||||||
|
} else if let iconSignal = item.iconSignal {
|
||||||
|
if previousItem == nil {
|
||||||
|
self.iconDisposable = (iconSignal
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] icon in
|
||||||
|
if let self {
|
||||||
|
self.iconNode.image = icon
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
iconSize = CGSize(width: 29.0, height: 29.0)
|
||||||
|
} else {
|
||||||
|
iconSize = CGSize(width: 29.0, height: 29.0)
|
||||||
|
}
|
||||||
|
let iconFrame = CGRect(origin: CGPoint(x: sideInset, y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||||
} else if self.iconNode.supernode != nil {
|
} else if self.iconNode.supernode != nil {
|
||||||
self.iconNode.image = nil
|
self.iconNode.image = nil
|
||||||
|
@ -800,7 +800,20 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
|||||||
if let settings = data.globalSettings {
|
if let settings = data.globalSettings {
|
||||||
for bot in settings.bots {
|
for bot in settings.bots {
|
||||||
if bot.flags.contains(.showInSettings) {
|
if bot.flags.contains(.showInSettings) {
|
||||||
items[.apps]!.append(PeerInfoScreenDisclosureItem(id: appIndex, text: bot.peer.compactDisplayTitle, icon: PresentationResourcesSettings.passport, action: {
|
let iconSignal: Signal<UIImage?, NoError>
|
||||||
|
if let peer = PeerReference(bot.peer._asPeer()), let icon = bot.icons[.iOSSettingsStatic] {
|
||||||
|
let fileReference: FileMediaReference = .attachBot(peer: peer, media: icon)
|
||||||
|
iconSignal = instantPageImageFile(account: context.account, userLocation: .other, fileReference: fileReference, fetched: true)
|
||||||
|
|> map { generator -> UIImage? in
|
||||||
|
let size = CGSize(width: 29.0, height: 29.0)
|
||||||
|
let context = generator(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: .zero))
|
||||||
|
return context?.generateImage()
|
||||||
|
}
|
||||||
|
let _ = freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: fileReference).start()
|
||||||
|
} else {
|
||||||
|
iconSignal = .single(UIImage(bundleImageName: "Settings/Menu/Websites")!)
|
||||||
|
}
|
||||||
|
items[.apps]!.append(PeerInfoScreenDisclosureItem(id: appIndex, text: bot.peer.compactDisplayTitle, icon: nil, iconSignal: iconSignal, action: {
|
||||||
interaction.openBotApp(bot)
|
interaction.openBotApp(bot)
|
||||||
}))
|
}))
|
||||||
appIndex += 1
|
appIndex += 1
|
||||||
@ -4636,12 +4649,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let proceed = { [weak self] in
|
let presentationData = self.presentationData
|
||||||
|
let proceed: (Bool) -> Void = { [weak self] installed in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let presentationData = self.presentationData
|
|
||||||
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
|
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
|
||||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||||
self?.controller?.present(controller, in: .window(.root))
|
self?.controller?.present(controller, in: .window(.root))
|
||||||
@ -4676,6 +4689,21 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
})
|
})
|
||||||
controller.navigationPresentation = .flatModal
|
controller.navigationPresentation = .flatModal
|
||||||
self.controller?.push(controller)
|
self.controller?.push(controller)
|
||||||
|
|
||||||
|
if installed {
|
||||||
|
Queue.mainQueue().after(0.3, {
|
||||||
|
let text: String
|
||||||
|
if bot.flags.contains(.showInSettings) {
|
||||||
|
text = presentationData.strings.WebApp_ShortcutsSettingsAdded(bot.peer.compactDisplayTitle).string
|
||||||
|
} else {
|
||||||
|
text = presentationData.strings.WebApp_ShortcutsAdded(bot.peer.compactDisplayTitle).string
|
||||||
|
}
|
||||||
|
controller.present(
|
||||||
|
UndoOverlayController(presentationData: presentationData, content: .succeed(text: text), elevatedLayout: false, action: { _ in return false }),
|
||||||
|
in: .current
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}, error: { [weak self] error in
|
}, error: { [weak self] error in
|
||||||
if let self {
|
if let self {
|
||||||
self.controller?.present(textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: self.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {
|
self.controller?.present(textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: self.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {
|
||||||
@ -4697,15 +4725,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
|> deliverOnMainQueue).start(error: { _ in
|
|> deliverOnMainQueue).start(error: { _ in
|
||||||
|
|
||||||
}, completed: {
|
}, completed: {
|
||||||
proceed()
|
proceed(true)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
proceed()
|
proceed(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
controller.present(alertController, in: .window(.root))
|
controller.present(alertController, in: .window(.root))
|
||||||
} else {
|
} else {
|
||||||
proceed()
|
proceed(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1633,7 +1633,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
chatLocation: chatLocation,
|
chatLocation: chatLocation,
|
||||||
isScheduledMessages: isScheduledMessages,
|
isScheduledMessages: isScheduledMessages,
|
||||||
present: present,
|
present: present,
|
||||||
presentInGlobalOverlay: presentInGlobalOverlay
|
presentInGlobalOverlay: presentInGlobalOverlay,
|
||||||
|
makeEntityInputView: {
|
||||||
|
return EntityInputView(context: context, isDark: true, areCustomEmojiEnabled: customEmojiAvailable)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return inputPanelNode
|
return inputPanelNode
|
||||||
}
|
}
|
||||||
|
@ -117,11 +117,7 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
|||||||
for separatorNode in self.actionVerticalSeparators {
|
for separatorNode in self.actionVerticalSeparators {
|
||||||
self.addSubnode(separatorNode)
|
self.addSubnode(separatorNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let firstAction = self.actionNodes.first {
|
|
||||||
firstAction.actionEnabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
self.acceptTermsCheckNode.valueChanged = { [weak self] value in
|
self.acceptTermsCheckNode.valueChanged = { [weak self] value in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.acceptedTerms = !strongSelf.acceptedTerms
|
strongSelf.acceptedTerms = !strongSelf.acceptedTerms
|
||||||
@ -150,6 +146,10 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
|||||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.acceptTap(_:)))
|
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.acceptTap(_:)))
|
||||||
tapGesture.delegate = self
|
tapGesture.delegate = self
|
||||||
self.view.addGestureRecognizer(tapGesture)
|
self.view.addGestureRecognizer(tapGesture)
|
||||||
|
|
||||||
|
if let firstAction = self.actionNodes.first {
|
||||||
|
firstAction.actionEnabled = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
@ -366,7 +366,7 @@ public func webAppTermsAlertController(
|
|||||||
|
|
||||||
var dismissImpl: ((Bool) -> Void)?
|
var dismissImpl: ((Bool) -> Void)?
|
||||||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_DisclaimerContinue, action: {
|
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_DisclaimerContinue, action: {
|
||||||
completion(false)
|
completion(true)
|
||||||
dismissImpl?(true)
|
dismissImpl?(true)
|
||||||
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||||
dismissImpl?(true)
|
dismissImpl?(true)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user