mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
237f86f7ca
commit
e1b4af1461
@ -322,7 +322,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||||||
|
|
||||||
private var spoilersRevealed = false
|
private var spoilersRevealed = false
|
||||||
|
|
||||||
private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||||
private let animationCache: AnimationCache
|
private let animationCache: AnimationCache
|
||||||
private let animationRenderer: MultiAnimationRenderer
|
private let animationRenderer: MultiAnimationRenderer
|
||||||
|
|
||||||
|
@ -675,6 +675,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}, schedule: { [weak textInputPanelNode] in
|
}, schedule: { [weak textInputPanelNode] in
|
||||||
textInputPanelNode?.sendMessage(.schedule)
|
textInputPanelNode?.sendMessage(.schedule)
|
||||||
})
|
})
|
||||||
|
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
|
||||||
strongSelf.presentInGlobalOverlay(controller)
|
strongSelf.presentInGlobalOverlay(controller)
|
||||||
}, openScheduledMessages: {
|
}, openScheduledMessages: {
|
||||||
}, openPeersNearby: {
|
}, openPeersNearby: {
|
||||||
|
@ -489,6 +489,9 @@ private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutP
|
|||||||
methods.append(.savedCredentials(savedCredentials))
|
methods.append(.savedCredentials(savedCredentials))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !form.additionalPaymentMethods.isEmpty {
|
||||||
|
methods.append(contentsOf: form.additionalPaymentMethods.map { .other($0) })
|
||||||
|
}
|
||||||
return methods
|
return methods
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1416,6 +1419,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
case let .other(method):
|
||||||
|
let _ = method
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ enum BotCheckoutPaymentMethod: Equatable {
|
|||||||
case savedCredentials(BotPaymentSavedCredentials)
|
case savedCredentials(BotPaymentSavedCredentials)
|
||||||
case webToken(BotCheckoutPaymentWebToken)
|
case webToken(BotCheckoutPaymentWebToken)
|
||||||
case applePay
|
case applePay
|
||||||
|
case other(BotPaymentMethod)
|
||||||
|
|
||||||
var title: String {
|
var title: String {
|
||||||
switch self {
|
switch self {
|
||||||
@ -29,6 +30,8 @@ enum BotCheckoutPaymentMethod: Equatable {
|
|||||||
return token.title
|
return token.title
|
||||||
case .applePay:
|
case .applePay:
|
||||||
return "Apple Pay"
|
return "Apple Pay"
|
||||||
|
case let .other(method):
|
||||||
|
return method.title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,6 +71,9 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
|
|||||||
case .applePay:
|
case .applePay:
|
||||||
title = "Apple Pay"
|
title = "Apple Pay"
|
||||||
icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed()
|
icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed()
|
||||||
|
case let .other(method):
|
||||||
|
title = method.title
|
||||||
|
icon = nil
|
||||||
}
|
}
|
||||||
let value: Bool?
|
let value: Bool?
|
||||||
if let currentMethod = currentMethod {
|
if let currentMethod = currentMethod {
|
||||||
|
@ -4,18 +4,23 @@ import SwiftSignalKit
|
|||||||
|
|
||||||
public enum ChatTextInputAccessoryItem: Equatable {
|
public enum ChatTextInputAccessoryItem: Equatable {
|
||||||
public enum Key: Hashable {
|
public enum Key: Hashable {
|
||||||
case keyboard
|
case input
|
||||||
case stickers
|
case botInput
|
||||||
case inputButtons
|
|
||||||
case commands
|
case commands
|
||||||
case silentPost
|
case silentPost
|
||||||
case messageAutoremoveTimeout
|
case messageAutoremoveTimeout
|
||||||
case scheduledMessages
|
case scheduledMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
case keyboard
|
public enum InputMode: Hashable {
|
||||||
case stickers(isEnabled: Bool, isEmoji: Bool)
|
case keyboard
|
||||||
case inputButtons
|
case stickers
|
||||||
|
case emoji
|
||||||
|
case bot
|
||||||
|
}
|
||||||
|
case input(isEnabled: Bool, inputMode: InputMode)
|
||||||
|
case botInput(isEnabled: Bool, inputMode: InputMode)
|
||||||
|
|
||||||
case commands
|
case commands
|
||||||
case silentPost(Bool)
|
case silentPost(Bool)
|
||||||
case messageAutoremoveTimeout(Int32?)
|
case messageAutoremoveTimeout(Int32?)
|
||||||
@ -23,12 +28,10 @@ public enum ChatTextInputAccessoryItem: Equatable {
|
|||||||
|
|
||||||
public var key: Key {
|
public var key: Key {
|
||||||
switch self {
|
switch self {
|
||||||
case .keyboard:
|
case .input:
|
||||||
return .keyboard
|
return .input
|
||||||
case .stickers:
|
case .botInput:
|
||||||
return .stickers
|
return .botInput
|
||||||
case .inputButtons:
|
|
||||||
return .inputButtons
|
|
||||||
case .commands:
|
case .commands:
|
||||||
return .commands
|
return .commands
|
||||||
case .silentPost:
|
case .silentPost:
|
||||||
|
@ -19,6 +19,7 @@ swift_library(
|
|||||||
"//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState",
|
"//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState",
|
||||||
"//submodules/ContextUI:ContextUI",
|
"//submodules/ContextUI:ContextUI",
|
||||||
"//submodules/AppBundle:AppBundle",
|
"//submodules/AppBundle:AppBundle",
|
||||||
|
"//submodules/TextFormat:TextFormat",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -8,6 +8,7 @@ import AccountContext
|
|||||||
import ContextUI
|
import ContextUI
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
public final class ChatSendMessageActionSheetController: ViewController {
|
public final class ChatSendMessageActionSheetController: ViewController {
|
||||||
private var controllerNode: ChatSendMessageActionSheetControllerNode {
|
private var controllerNode: ChatSendMessageActionSheetControllerNode {
|
||||||
@ -32,6 +33,8 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
|||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
private let hapticFeedback = HapticFeedback()
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
|
public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, interfaceState: ChatPresentationInterfaceState, 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, interfaceState: ChatPresentationInterfaceState, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, completion: @escaping () -> Void, sendMessage: @escaping (Bool) -> Void, schedule: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -79,13 +82,18 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
|||||||
var reminders = false
|
var reminders = false
|
||||||
var isSecret = false
|
var isSecret = false
|
||||||
var canSchedule = false
|
var canSchedule = false
|
||||||
|
var hasEntityKeyboard = false
|
||||||
if case let .peer(peerId) = self.interfaceState.chatLocation {
|
if case let .peer(peerId) = self.interfaceState.chatLocation {
|
||||||
reminders = peerId == context.account.peerId
|
reminders = peerId == context.account.peerId
|
||||||
isSecret = peerId.namespace == Namespaces.Peer.SecretChat
|
isSecret = peerId.namespace == Namespaces.Peer.SecretChat
|
||||||
canSchedule = !isSecret
|
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, send: { [weak self] in
|
if case .media = self.interfaceState.inputMode {
|
||||||
|
hasEntityKeyboard = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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: hasEntityKeyboard, send: { [weak self] in
|
||||||
self?.sendMessage(false)
|
self?.sendMessage(false)
|
||||||
self?.dismiss(cancel: false)
|
self?.dismiss(cancel: false)
|
||||||
}, sendSilently: { [weak self] in
|
}, sendSilently: { [weak self] in
|
||||||
|
@ -9,6 +9,7 @@ import TelegramPresentationData
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import ContextUI
|
import ContextUI
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
private let leftInset: CGFloat = 16.0
|
private let leftInset: CGFloat = 16.0
|
||||||
private let rightInset: CGFloat = 16.0
|
private let rightInset: CGFloat = 16.0
|
||||||
@ -158,6 +159,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||||||
private let textInputNode: EditableTextNode
|
private let textInputNode: EditableTextNode
|
||||||
private let attachment: Bool
|
private let attachment: Bool
|
||||||
private let forwardedCount: Int?
|
private let forwardedCount: Int?
|
||||||
|
private let hasEntityKeyboard: Bool
|
||||||
|
|
||||||
private let send: (() -> Void)?
|
private let send: (() -> Void)?
|
||||||
private let cancel: (() -> Void)?
|
private let cancel: (() -> Void)?
|
||||||
@ -183,7 +185,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||||||
|
|
||||||
private var animateInputField = false
|
private var animateInputField = false
|
||||||
|
|
||||||
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
|
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, hasEntityKeyboard: Bool, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.sourceSendButton = sourceSendButton
|
self.sourceSendButton = sourceSendButton
|
||||||
@ -191,6 +193,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||||||
self.textInputNode = textInputNode
|
self.textInputNode = textInputNode
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
self.forwardedCount = forwardedCount
|
self.forwardedCount = forwardedCount
|
||||||
|
self.hasEntityKeyboard = hasEntityKeyboard
|
||||||
|
|
||||||
self.send = send
|
self.send = send
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
@ -422,7 +425,11 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||||||
let fromFrame = CGRect(origin: CGPoint(), size: CGSize(width: initialWidth, height: self.textFieldFrame.height + 2.0))
|
let fromFrame = CGRect(origin: CGPoint(), size: CGSize(width: initialWidth, height: self.textFieldFrame.height + 2.0))
|
||||||
let delta = (fromFrame.height - self.messageClipNode.bounds.height) / 2.0
|
let delta = (fromFrame.height - self.messageClipNode.bounds.height) / 2.0
|
||||||
|
|
||||||
let inputHeight = layout.inputHeight ?? 0.0
|
var inputHeight = layout.inputHeight ?? 0.0
|
||||||
|
if self.hasEntityKeyboard {
|
||||||
|
inputHeight = layout.standardInputHeight
|
||||||
|
}
|
||||||
|
|
||||||
var clipDelta = delta
|
var clipDelta = delta
|
||||||
if inputHeight.isZero || layout.isNonExclusive {
|
if inputHeight.isZero || layout.isNonExclusive {
|
||||||
clipDelta -= self.contentContainerNode.frame.height + 16.0
|
clipDelta -= self.contentContainerNode.frame.height + 16.0
|
||||||
@ -531,7 +538,11 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||||||
let delta = (toFrame.height - self.messageClipNode.bounds.height) / 2.0
|
let delta = (toFrame.height - self.messageClipNode.bounds.height) / 2.0
|
||||||
|
|
||||||
if cancel && self.animateInputField {
|
if cancel && self.animateInputField {
|
||||||
let inputHeight = layout.inputHeight ?? 0.0
|
var inputHeight = layout.inputHeight ?? 0.0
|
||||||
|
if self.hasEntityKeyboard {
|
||||||
|
inputHeight = layout.standardInputHeight
|
||||||
|
}
|
||||||
|
|
||||||
var clipDelta = delta
|
var clipDelta = delta
|
||||||
if inputHeight.isZero || layout.isNonExclusive {
|
if inputHeight.isZero || layout.isNonExclusive {
|
||||||
clipDelta -= self.contentContainerNode.frame.height + 16.0
|
clipDelta -= self.contentContainerNode.frame.height + 16.0
|
||||||
@ -589,8 +600,12 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
|||||||
|
|
||||||
let menuHeightWithInset = contentSize.height + 16.0
|
let menuHeightWithInset = contentSize.height + 16.0
|
||||||
|
|
||||||
let insets = layout.insets(options: [.statusBar, .input])
|
var insets = layout.insets(options: [.statusBar, .input])
|
||||||
let inputHeight = layout.inputHeight ?? 0.0
|
var inputHeight = layout.inputHeight ?? 0.0
|
||||||
|
if self.hasEntityKeyboard {
|
||||||
|
insets.bottom = max(insets.bottom, layout.standardInputHeight)
|
||||||
|
inputHeight = layout.standardInputHeight
|
||||||
|
}
|
||||||
|
|
||||||
let contentOffset = self.scrollNode.view.contentOffset.y
|
let contentOffset = self.scrollNode.view.contentOffset.y
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ public final class LottieAnimationComponent: Component {
|
|||||||
}
|
}
|
||||||
strongSelf.didPlayToCompletion = true
|
strongSelf.didPlayToCompletion = true
|
||||||
let _ = strongSelf.update(component: component, availableSize: availableSize, transition: transition)
|
let _ = strongSelf.update(component: component, availableSize: availableSize, transition: transition)
|
||||||
|
strongSelf.currentCompletion = nil
|
||||||
}
|
}
|
||||||
animationView.loopMode = .playOnce
|
animationView.loopMode = .playOnce
|
||||||
} else {
|
} else {
|
||||||
@ -175,10 +176,10 @@ public final class LottieAnimationComponent: Component {
|
|||||||
updatePlayback = true
|
updatePlayback = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.component = component
|
||||||
}
|
}
|
||||||
|
|
||||||
self.component = component
|
|
||||||
|
|
||||||
if updateColors, let animationView = self.animationView {
|
if updateColors, let animationView = self.animationView {
|
||||||
if let value = component.colors["__allcolors__"] {
|
if let value = component.colors["__allcolors__"] {
|
||||||
for keypath in animationView.allKeypaths(predicate: { $0.keys.last == "Color" }) {
|
for keypath in animationView.allKeypaths(predicate: { $0.keys.last == "Color" }) {
|
||||||
|
@ -122,12 +122,14 @@ open class TooltipController: ViewController, StandalonePresentableController {
|
|||||||
private let dismissImmediatelyOnLayoutUpdate: Bool
|
private let dismissImmediatelyOnLayoutUpdate: Bool
|
||||||
private var timeoutTimer: SwiftSignalKit.Timer?
|
private var timeoutTimer: SwiftSignalKit.Timer?
|
||||||
|
|
||||||
|
private var padding: CGFloat
|
||||||
|
|
||||||
private var layout: ContainerViewLayout?
|
private var layout: ContainerViewLayout?
|
||||||
private var initialArrowOnBottom: Bool
|
private var initialArrowOnBottom: Bool
|
||||||
|
|
||||||
public var dismissed: ((Bool) -> Void)?
|
public var dismissed: ((Bool) -> Void)?
|
||||||
|
|
||||||
public init(content: TooltipControllerContent, baseFontSize: CGFloat, timeout: Double = 2.0, dismissByTapOutside: Bool = false, dismissByTapOutsideSource: Bool = false, dismissImmediatelyOnLayoutUpdate: Bool = false, arrowOnBottom: Bool = true) {
|
public init(content: TooltipControllerContent, baseFontSize: CGFloat, timeout: Double = 2.0, dismissByTapOutside: Bool = false, dismissByTapOutsideSource: Bool = false, dismissImmediatelyOnLayoutUpdate: Bool = false, arrowOnBottom: Bool = true, padding: CGFloat = 8.0) {
|
||||||
self.content = content
|
self.content = content
|
||||||
self.baseFontSize = baseFontSize
|
self.baseFontSize = baseFontSize
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
@ -135,6 +137,7 @@ open class TooltipController: ViewController, StandalonePresentableController {
|
|||||||
self.dismissByTapOutsideSource = dismissByTapOutsideSource
|
self.dismissByTapOutsideSource = dismissByTapOutsideSource
|
||||||
self.dismissImmediatelyOnLayoutUpdate = dismissImmediatelyOnLayoutUpdate
|
self.dismissImmediatelyOnLayoutUpdate = dismissImmediatelyOnLayoutUpdate
|
||||||
self.initialArrowOnBottom = arrowOnBottom
|
self.initialArrowOnBottom = arrowOnBottom
|
||||||
|
self.padding = padding
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
|
|
||||||
@ -153,6 +156,7 @@ open class TooltipController: ViewController, StandalonePresentableController {
|
|||||||
self.displayNode = TooltipControllerNode(content: self.content, baseFontSize: self.baseFontSize, dismiss: { [weak self] tappedInside in
|
self.displayNode = TooltipControllerNode(content: self.content, baseFontSize: self.baseFontSize, dismiss: { [weak self] tappedInside in
|
||||||
self?.dismiss(tappedInside: tappedInside)
|
self?.dismiss(tappedInside: tappedInside)
|
||||||
}, dismissByTapOutside: self.dismissByTapOutside, dismissByTapOutsideSource: self.dismissByTapOutsideSource)
|
}, dismissByTapOutside: self.dismissByTapOutside, dismissByTapOutsideSource: self.dismissByTapOutsideSource)
|
||||||
|
self.controllerNode.padding = self.padding
|
||||||
self.controllerNode.arrowOnBottom = self.initialArrowOnBottom
|
self.controllerNode.arrowOnBottom = self.initialArrowOnBottom
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ final class TooltipControllerNode: ASDisplayNode {
|
|||||||
var sourceRect: CGRect?
|
var sourceRect: CGRect?
|
||||||
var arrowOnBottom: Bool = true
|
var arrowOnBottom: Bool = true
|
||||||
|
|
||||||
|
var padding: CGFloat = 8.0
|
||||||
|
|
||||||
private var dismissedByTouchOutside = false
|
private var dismissedByTouchOutside = false
|
||||||
private var dismissByTapOutsideSource = false
|
private var dismissByTapOutsideSource = false
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ final class TooltipControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.arrowOnBottom = arrowOnBottom
|
self.arrowOnBottom = arrowOnBottom
|
||||||
|
|
||||||
let horizontalOrigin: CGFloat = floor(min(max(8.0, sourceRect.midX - contentSize.width / 2.0), layout.size.width - contentSize.width - 8.0))
|
let horizontalOrigin: CGFloat = floor(min(max(self.padding, sourceRect.midX - contentSize.width / 2.0), layout.size.width - contentSize.width - self.padding))
|
||||||
|
|
||||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin), size: contentSize))
|
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin), size: contentSize))
|
||||||
self.containerNode.relativeArrowPosition = (sourceRect.midX - horizontalOrigin, arrowOnBottom)
|
self.containerNode.relativeArrowPosition = (sourceRect.midX - horizontalOrigin, arrowOnBottom)
|
||||||
|
@ -373,8 +373,17 @@ private final class GiftComponent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
|
|
||||||
let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitle.size.height + insets.bottom)
|
let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitle.size.height + insets.bottom)
|
||||||
|
let distance = context.availableSize.width - insets.left - insets.right - label.size.width - subtitle.size.width - discountSize.width - 7.0
|
||||||
|
|
||||||
|
let labelOriginY: CGFloat
|
||||||
|
if distance > 8.0 {
|
||||||
|
labelOriginY = size.height / 2.0
|
||||||
|
} else {
|
||||||
|
labelOriginY = insets.top + title.size.height / 2.0
|
||||||
|
}
|
||||||
|
|
||||||
context.add(label
|
context.add(label
|
||||||
.position(CGPoint(x: context.availableSize.width - insets.right - label.size.width / 2.0, y: size.height / 2.0))
|
.position(CGPoint(x: context.availableSize.width - insets.right - label.size.width / 2.0, y: labelOriginY))
|
||||||
)
|
)
|
||||||
|
|
||||||
context.add(check
|
context.add(check
|
||||||
|
@ -348,6 +348,12 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
|||||||
self.visibleItemLayers[id] = nil
|
self.visibleItemLayers[id] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for id in self.visibleItemPlaceholderViews.keys {
|
||||||
|
if !validIds.contains(id) {
|
||||||
|
self.visibleItemPlaceholderViews[id]?.removeFromSuperview()
|
||||||
|
self.visibleItemPlaceholderViews[id] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateShimmerIfNeeded() {
|
private func updateShimmerIfNeeded() {
|
||||||
|
@ -120,6 +120,21 @@ public struct BotPaymentForm : Equatable {
|
|||||||
public let nativeProvider: BotPaymentNativeProvider?
|
public let nativeProvider: BotPaymentNativeProvider?
|
||||||
public let savedInfo: BotPaymentRequestedInfo?
|
public let savedInfo: BotPaymentRequestedInfo?
|
||||||
public let savedCredentials: BotPaymentSavedCredentials?
|
public let savedCredentials: BotPaymentSavedCredentials?
|
||||||
|
public let additionalPaymentMethods: [BotPaymentMethod]
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct BotPaymentMethod: Equatable {
|
||||||
|
public let url: String
|
||||||
|
public let title: String
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BotPaymentMethod {
|
||||||
|
init(apiPaymentFormMethod: Api.PaymentFormMethod) {
|
||||||
|
switch apiPaymentFormMethod {
|
||||||
|
case let .paymentFormMethod(url, title):
|
||||||
|
self.init(url: url, title: title)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BotPaymentFormRequestError {
|
public enum BotPaymentFormRequestError {
|
||||||
@ -270,8 +285,7 @@ func _internal_fetchBotPaymentForm(postbox: Postbox, network: Network, source: B
|
|||||||
let _ = title
|
let _ = title
|
||||||
let _ = description
|
let _ = description
|
||||||
let _ = photo
|
let _ = photo
|
||||||
let _ = additionalMethods
|
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
for user in apiUsers {
|
for user in apiUsers {
|
||||||
let parsed = TelegramUser(user: user)
|
let parsed = TelegramUser(user: user)
|
||||||
@ -297,7 +311,9 @@ func _internal_fetchBotPaymentForm(postbox: Postbox, network: Network, source: B
|
|||||||
parsedSavedCredentials = .card(id: id, title: title)
|
parsedSavedCredentials = .card(id: id, title: title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return BotPaymentForm(id: id, canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, paymentBotId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(providerId)), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials)
|
|
||||||
|
let additionalPaymentMethods = additionalMethods?.map({ BotPaymentMethod(apiPaymentFormMethod: $0) }) ?? []
|
||||||
|
return BotPaymentForm(id: id, canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, paymentBotId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(providerId)), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials, additionalPaymentMethods: additionalPaymentMethods)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> mapError { _ -> BotPaymentFormRequestError in }
|
|> mapError { _ -> BotPaymentFormRequestError in }
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1127,6 +1127,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let packReference = packReferences.first, let strongSelf = self else {
|
guard let packReference = packReferences.first, let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
strongSelf.chatDisplayNode.dismissTextInput()
|
||||||
let controller = StickerPackScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(packReferences), parentNavigationController: strongSelf.effectiveNavigationController)
|
let controller = StickerPackScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(packReferences), parentNavigationController: strongSelf.effectiveNavigationController)
|
||||||
strongSelf.present(controller, in: .window(.root))
|
strongSelf.present(controller, in: .window(.root))
|
||||||
}
|
}
|
||||||
@ -8446,6 +8447,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.controllerInteraction?.scheduleCurrentMessage()
|
strongSelf.controllerInteraction?.scheduleCurrentMessage()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
controller.emojiViewProvider = strongSelf.chatDisplayNode.textInputPanelNode?.emojiViewProvider
|
||||||
strongSelf.sendMessageActionsController = controller
|
strongSelf.sendMessageActionsController = controller
|
||||||
if layout.isNonExclusive {
|
if layout.isNonExclusive {
|
||||||
strongSelf.present(controller, in: .window(.root))
|
strongSelf.present(controller, in: .window(.root))
|
||||||
@ -15526,7 +15528,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if let tooltipController = self.mediaRecordingModeTooltipController {
|
if let tooltipController = self.mediaRecordingModeTooltipController {
|
||||||
tooltipController.updateContent(.text(text), animated: true, extendTimer: true)
|
tooltipController.updateContent(.text(text), animated: true, extendTimer: true)
|
||||||
} else if let rect = rect {
|
} else if let rect = rect {
|
||||||
let tooltipController = TooltipController(content: .text(text), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize)
|
let tooltipController = TooltipController(content: .text(text), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, padding: 2.0)
|
||||||
self.mediaRecordingModeTooltipController = tooltipController
|
self.mediaRecordingModeTooltipController = tooltipController
|
||||||
tooltipController.dismissed = { [weak self, weak tooltipController] _ in
|
tooltipController.dismissed = { [weak self, weak tooltipController] _ in
|
||||||
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.mediaRecordingModeTooltipController === tooltipController {
|
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.mediaRecordingModeTooltipController === tooltipController {
|
||||||
@ -15547,7 +15549,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.sendingOptionsTooltipController?.dismiss()
|
self.sendingOptionsTooltipController?.dismiss()
|
||||||
let tooltipController = TooltipController(content: .text(self.presentationData.strings.Conversation_SendingOptionsTooltip), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, timeout: 3.0, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
let tooltipController = TooltipController(content: .text(self.presentationData.strings.Conversation_SendingOptionsTooltip), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, timeout: 3.0, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true, padding: 2.0)
|
||||||
self.sendingOptionsTooltipController = tooltipController
|
self.sendingOptionsTooltipController = tooltipController
|
||||||
tooltipController.dismissed = { [weak self, weak tooltipController] _ in
|
tooltipController.dismissed = { [weak self, weak tooltipController] _ in
|
||||||
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.sendingOptionsTooltipController === tooltipController {
|
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.sendingOptionsTooltipController === tooltipController {
|
||||||
|
@ -314,13 +314,13 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
|
|||||||
|
|
||||||
switch chatPresentationInterfaceState.inputMode {
|
switch chatPresentationInterfaceState.inputMode {
|
||||||
case .media:
|
case .media:
|
||||||
accessoryItems.append(.keyboard)
|
accessoryItems.append(.input(isEnabled: true, inputMode: .keyboard))
|
||||||
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
||||||
case .inputButtons:
|
case .inputButtons:
|
||||||
return ChatTextInputPanelState(accessoryItems: [.keyboard], contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
return ChatTextInputPanelState(accessoryItems: [.botInput(isEnabled: true, inputMode: .keyboard)], contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
||||||
case .none, .text:
|
case .none, .text:
|
||||||
if let _ = chatPresentationInterfaceState.interfaceState.editMessage {
|
if let _ = chatPresentationInterfaceState.interfaceState.editMessage {
|
||||||
accessoryItems.append(.stickers(isEnabled: true, isEmoji: true))
|
accessoryItems.append(.input(isEnabled: true, inputMode: .emoji))
|
||||||
|
|
||||||
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
||||||
} else {
|
} else {
|
||||||
@ -371,13 +371,13 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if stickersEnabled {
|
if stickersEnabled {
|
||||||
accessoryItems.append(.stickers(isEnabled: true, isEmoji: stickersAreEmoji))
|
accessoryItems.append(.input(isEnabled: true, inputMode: stickersAreEmoji ? .emoji : .stickers))
|
||||||
} else {
|
} else {
|
||||||
accessoryItems.append(.stickers(isEnabled: true, isEmoji: true))
|
accessoryItems.append(.input(isEnabled: true, inputMode: .emoji))
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id {
|
if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id {
|
||||||
accessoryItems.append(.inputButtons)
|
accessoryItems.append(.botInput(isEnabled: true, inputMode: .bot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
||||||
|
@ -10,6 +10,8 @@ import AccountContext
|
|||||||
import ChatInterfaceState
|
import ChatInterfaceState
|
||||||
import AudioBlob
|
import AudioBlob
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
|
import ComponentFlow
|
||||||
|
import LottieAnimationComponent
|
||||||
|
|
||||||
private let offsetThreshold: CGFloat = 10.0
|
private let offsetThreshold: CGFloat = 10.0
|
||||||
private let dismissOffsetThreshold: CGFloat = 70.0
|
private let dismissOffsetThreshold: CGFloat = 70.0
|
||||||
@ -185,7 +187,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
|
|
||||||
private var modeTimeoutTimer: SwiftSignalKit.Timer?
|
private var modeTimeoutTimer: SwiftSignalKit.Timer?
|
||||||
|
|
||||||
private let innerIconView: UIImageView
|
private let animationView: ComponentView<Empty>
|
||||||
|
|
||||||
private var recordingOverlay: ChatTextInputAudioRecordingOverlay?
|
private var recordingOverlay: ChatTextInputAudioRecordingOverlay?
|
||||||
private var startTouchLocation: CGPoint?
|
private var startTouchLocation: CGPoint?
|
||||||
@ -288,7 +290,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) {
|
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.innerIconView = UIImageView()
|
self.animationView = ComponentView<Empty>()
|
||||||
self.presentController = presentController
|
self.presentController = presentController
|
||||||
|
|
||||||
super.init(frame: CGRect())
|
super.init(frame: CGRect())
|
||||||
@ -297,8 +299,6 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
|
|
||||||
self.pallete = legacyInputMicPalette(from: theme)
|
self.pallete = legacyInputMicPalette(from: theme)
|
||||||
|
|
||||||
self.insertSubview(self.innerIconView, at: 0)
|
|
||||||
|
|
||||||
self.disablesInteractiveTransitionGestureRecognizer = true
|
self.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
|
|
||||||
self.updateMode(mode: self.mode, animated: false, force: true)
|
self.updateMode(mode: self.mode, animated: false, force: true)
|
||||||
@ -318,51 +318,81 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateMode(mode: ChatTextInputMediaRecordingButtonMode, animated: Bool, force: Bool) {
|
private func updateMode(mode: ChatTextInputMediaRecordingButtonMode, animated: Bool, force: Bool) {
|
||||||
|
let previousMode = self.mode
|
||||||
if mode != self.mode || force {
|
if mode != self.mode || force {
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
|
||||||
if animated {
|
self.updateAnimation(previousMode: previousMode)
|
||||||
let previousView = UIImageView(image: self.innerIconView.image)
|
}
|
||||||
previousView.frame = self.innerIconView.frame
|
}
|
||||||
self.addSubview(previousView)
|
|
||||||
previousView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
private func updateAnimation(previousMode: ChatTextInputMediaRecordingButtonMode) {
|
||||||
previousView.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false, completion: { [weak previousView] _ in
|
let image: UIImage?
|
||||||
previousView?.removeFromSuperview()
|
switch self.mode {
|
||||||
})
|
case .audio:
|
||||||
}
|
self.icon = PresentationResourcesChat.chatInputPanelVoiceActiveButtonImage(self.theme)
|
||||||
|
image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
|
||||||
switch self.mode {
|
case .video:
|
||||||
case .audio:
|
self.icon = PresentationResourcesChat.chatInputPanelVideoActiveButtonImage(self.theme)
|
||||||
self.icon = PresentationResourcesChat.chatInputPanelVoiceActiveButtonImage(self.theme)
|
image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
|
||||||
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
|
}
|
||||||
case .video:
|
|
||||||
self.icon = PresentationResourcesChat.chatInputPanelVideoActiveButtonImage(self.theme)
|
let size = self.bounds.size
|
||||||
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVideoButtonImage(self.theme)
|
let iconSize: CGSize
|
||||||
}
|
if let image = image {
|
||||||
if let image = self.innerIconView.image {
|
iconSize = image.size
|
||||||
let size = self.bounds.size
|
} else {
|
||||||
let iconSize = image.size
|
iconSize = size
|
||||||
self.innerIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
}
|
||||||
}
|
|
||||||
|
let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
if animated {
|
|
||||||
self.innerIconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false)
|
let animationName: String
|
||||||
self.innerIconView.layer.animateSpring(from: 0.4 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
switch self.mode {
|
||||||
|
case .audio:
|
||||||
|
animationName = "anim_videoToMic"
|
||||||
|
case .video:
|
||||||
|
animationName = "anim_micToVideo"
|
||||||
|
}
|
||||||
|
|
||||||
|
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
|
||||||
|
if previousMode != mode {
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
let colorKeys = ["__allcolors__"]
|
||||||
|
var colors: [String: UIColor] = [:]
|
||||||
|
for colorKey in colorKeys {
|
||||||
|
colors[colorKey] = self.theme.chat.inputPanel.panelControlColor
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = animationView.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(LottieAnimationComponent(
|
||||||
|
animation: LottieAnimationComponent.AnimationItem(
|
||||||
|
name: animationName,
|
||||||
|
mode: animationMode
|
||||||
|
),
|
||||||
|
colors: colors,
|
||||||
|
size: animationFrame.size
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: animationFrame.size
|
||||||
|
)
|
||||||
|
// self.innerIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
|
if let view = animationView.view {
|
||||||
|
view.isUserInteractionEnabled = false
|
||||||
|
if view.superview == nil {
|
||||||
|
self.insertSubview(view, at: 0)
|
||||||
}
|
}
|
||||||
|
view.frame = animationFrame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTheme(theme: PresentationTheme) {
|
func updateTheme(theme: PresentationTheme) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
|
||||||
switch self.mode {
|
self.updateAnimation(previousMode: self.mode)
|
||||||
case .audio:
|
|
||||||
self.icon = PresentationResourcesChat.chatInputPanelVoiceActiveButtonImage(self.theme)
|
|
||||||
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
|
|
||||||
case .video:
|
|
||||||
self.icon = PresentationResourcesChat.chatInputPanelVideoActiveButtonImage(self.theme)
|
|
||||||
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVideoButtonImage(self.theme)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pallete = legacyInputMicPalette(from: theme)
|
self.pallete = legacyInputMicPalette(from: theme)
|
||||||
self.micDecorationValue?.setColor(self.theme.chat.inputPanel.actionControlFillColor)
|
self.micDecorationValue?.setColor(self.theme.chat.inputPanel.actionControlFillColor)
|
||||||
@ -467,8 +497,8 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
micDecoration.isHidden = false
|
micDecoration.isHidden = false
|
||||||
micDecoration.startAnimating()
|
micDecoration.startAnimating()
|
||||||
|
|
||||||
innerIconView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.animationView.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
innerIconView.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false)
|
self.animationView.view?.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateOut(_ toSmallSize: Bool) {
|
override func animateOut(_ toSmallSize: Bool) {
|
||||||
@ -480,8 +510,8 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.03, delay: 0.15, removeOnCompletion: false)
|
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.03, delay: 0.15, removeOnCompletion: false)
|
||||||
} else {
|
} else {
|
||||||
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false)
|
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false)
|
||||||
innerIconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false)
|
self.animationView.view?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false)
|
||||||
innerIconView.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, removeOnCompletion: false)
|
self.animationView.view?.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,8 +520,10 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
|||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
if size != self.previousSize {
|
if size != self.previousSize {
|
||||||
self.previousSize = size
|
self.previousSize = size
|
||||||
let iconSize = self.innerIconView.bounds.size
|
if let view = self.animationView.view {
|
||||||
self.innerIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
let iconSize = view.bounds.size
|
||||||
|
view.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,12 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
self.iconImageNode.isUserInteractionEnabled = false
|
self.iconImageNode.isUserInteractionEnabled = false
|
||||||
self.addSubnode(self.iconImageNode)
|
self.addSubnode(self.iconImageNode)
|
||||||
|
|
||||||
if case .stickers = item {
|
switch item {
|
||||||
self.iconImageNode.isHidden = true
|
case .input, .botInput:
|
||||||
self.animationView = ComponentView<Empty>()
|
self.iconImageNode.isHidden = true
|
||||||
|
self.animationView = ComponentView<Empty>()
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if let text = text {
|
if let text = text {
|
||||||
@ -116,12 +119,15 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
|
|
||||||
static func imageAndInsets(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) -> (UIImage?, String?, String, CGFloat, UIEdgeInsets) {
|
static func imageAndInsets(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) -> (UIImage?, String?, String, CGFloat, UIEdgeInsets) {
|
||||||
switch item {
|
switch item {
|
||||||
case .keyboard:
|
case let .input(isEnabled, inputMode), let .botInput(isEnabled, inputMode):
|
||||||
return (PresentationResourcesChat.chatInputTextFieldKeyboardImage(theme), nil, strings.VoiceOver_Keyboard, 1.0, UIEdgeInsets())
|
switch inputMode {
|
||||||
case let .stickers(enabled, _):
|
case .keyboard:
|
||||||
return (PresentationResourcesChat.chatInputTextFieldStickersImage(theme), nil, strings.VoiceOver_Stickers, enabled ? 1.0 : 0.4, UIEdgeInsets())
|
return (PresentationResourcesChat.chatInputTextFieldKeyboardImage(theme), nil, strings.VoiceOver_Keyboard, 1.0, UIEdgeInsets())
|
||||||
case .inputButtons:
|
case .stickers, .emoji:
|
||||||
return (PresentationResourcesChat.chatInputTextFieldInputButtonsImage(theme), nil, strings.VoiceOver_BotKeyboard, 1.0, UIEdgeInsets())
|
return (PresentationResourcesChat.chatInputTextFieldStickersImage(theme), nil, strings.VoiceOver_Stickers, isEnabled ? 1.0 : 0.4, UIEdgeInsets())
|
||||||
|
case .bot:
|
||||||
|
return (PresentationResourcesChat.chatInputTextFieldInputButtonsImage(theme), nil, strings.VoiceOver_BotKeyboard, 1.0, UIEdgeInsets())
|
||||||
|
}
|
||||||
case .commands:
|
case .commands:
|
||||||
return (PresentationResourcesChat.chatInputTextFieldCommandsImage(theme), nil, strings.VoiceOver_BotCommands, 1.0, UIEdgeInsets())
|
return (PresentationResourcesChat.chatInputTextFieldCommandsImage(theme), nil, strings.VoiceOver_BotCommands, 1.0, UIEdgeInsets())
|
||||||
case let .silentPost(value):
|
case let .silentPost(value):
|
||||||
@ -143,7 +149,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
|
|
||||||
static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
||||||
switch item {
|
switch item {
|
||||||
case .keyboard, .stickers, .inputButtons, .silentPost, .commands, .scheduledMessages:
|
case .input, .botInput, .silentPost, .commands, .scheduledMessages:
|
||||||
return 32.0
|
return 32.0
|
||||||
case let .messageAutoremoveTimeout(timeout):
|
case let .messageAutoremoveTimeout(timeout):
|
||||||
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
||||||
@ -156,6 +162,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(item: ChatTextInputAccessoryItem, size: CGSize) {
|
func updateLayout(item: ChatTextInputAccessoryItem, size: CGSize) {
|
||||||
|
let previousItem = self.item
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
if let image = self.iconImageNode.image {
|
if let image = self.iconImageNode.image {
|
||||||
@ -165,26 +172,112 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size)
|
let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size)
|
||||||
self.iconImageNode.frame = imageFrame
|
self.iconImageNode.frame = imageFrame
|
||||||
|
|
||||||
if case let .stickers(_, isEmoji) = item, let animationView = self.animationView {
|
if let animationView = self.animationView {
|
||||||
let animationFrame = imageFrame.insetBy(dx: -4.0, dy: -4.0)
|
let animationFrame = imageFrame.insetBy(dx: -4.0, dy: -4.0)
|
||||||
|
|
||||||
var colors: [String: UIColor] = [:]
|
var previousInputMode: ChatTextInputAccessoryItem.InputMode?
|
||||||
let colorKeys: [String] = [
|
var inputMode: ChatTextInputAccessoryItem.InputMode?
|
||||||
|
|
||||||
|
switch previousItem {
|
||||||
|
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
|
||||||
|
previousInputMode = itemInputMode
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch item {
|
||||||
|
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
|
||||||
|
inputMode = itemInputMode
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let emojiColorKeys = [
|
||||||
"Ellipse 33.Ellipse 33.Stroke 1",
|
"Ellipse 33.Ellipse 33.Stroke 1",
|
||||||
"Ellipse 34.Ellipse 34.Stroke 1",
|
"Ellipse 34.Ellipse 34.Stroke 1",
|
||||||
"Oval.Oval.Fill 1",
|
"Oval.Oval.Fill 1",
|
||||||
"Oval 2.Oval.Fill 1",
|
"Oval 2.Oval.Fill 1",
|
||||||
"Path 85.Path 85.Stroke 1"
|
"Path 85.Path 85.Stroke 1"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
var colorKeys: [String] = ["__allcolors__"]
|
||||||
|
let animationName: String
|
||||||
|
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
|
||||||
|
if let inputMode = inputMode {
|
||||||
|
switch inputMode {
|
||||||
|
case .keyboard:
|
||||||
|
if let previousInputMode = previousInputMode {
|
||||||
|
if case .stickers = previousInputMode {
|
||||||
|
animationName = "anim_stickerToKey"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
} else if case .emoji = previousInputMode {
|
||||||
|
animationName = "anim_smileToKey"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
} else if case .bot = previousInputMode {
|
||||||
|
animationName = "anim_botToKey"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
} else {
|
||||||
|
animationName = "anim_stickerToKey"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
animationName = "anim_stickerToKey"
|
||||||
|
}
|
||||||
|
case .stickers:
|
||||||
|
if let previousInputMode = previousInputMode {
|
||||||
|
if case .keyboard = previousInputMode {
|
||||||
|
animationName = "anim_keyToSticker"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
} else if case .emoji = previousInputMode {
|
||||||
|
animationName = "anim_smileToSticker"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
colorKeys = emojiColorKeys
|
||||||
|
} else {
|
||||||
|
animationName = "anim_keyToSticker"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
animationName = "anim_keyToSticker"
|
||||||
|
}
|
||||||
|
case .emoji:
|
||||||
|
if let previousInputMode = previousInputMode {
|
||||||
|
if case .keyboard = previousInputMode {
|
||||||
|
animationName = "anim_keyToSmile"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
} else if case .stickers = previousInputMode {
|
||||||
|
animationName = "anim_stickerToSmile"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
colorKeys = emojiColorKeys
|
||||||
|
} else {
|
||||||
|
animationName = "anim_keyToSmile"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
animationName = "anim_keyToSmile"
|
||||||
|
}
|
||||||
|
case .bot:
|
||||||
|
if let previousInputMode = previousInputMode {
|
||||||
|
if case .keyboard = previousInputMode {
|
||||||
|
animationName = "anim_keyToBot"
|
||||||
|
animationMode = .animating(loop: false)
|
||||||
|
} else {
|
||||||
|
animationName = "anim_keyToBot"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
animationName = "anim_keyToBot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
animationName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var colors: [String: UIColor] = [:]
|
||||||
for colorKey in colorKeys {
|
for colorKey in colorKeys {
|
||||||
colors[colorKey] = self.theme.chat.inputPanel.inputControlColor
|
colors[colorKey] = self.theme.chat.inputPanel.inputControlColor
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = animationView.update(
|
let _ = animationView.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(LottieAnimationComponent(
|
component: AnyComponent(LottieAnimationComponent(
|
||||||
animation: LottieAnimationComponent.AnimationItem(
|
animation: LottieAnimationComponent.AnimationItem(
|
||||||
name: !isEmoji ? "anim_stickertosmile" : "anim_smiletosticker",
|
name: animationName,
|
||||||
mode: .animateTransitionFromPrevious
|
mode: animationMode
|
||||||
),
|
),
|
||||||
colors: colors,
|
colors: colors,
|
||||||
size: animationFrame.size
|
size: animationFrame.size
|
||||||
@ -193,6 +286,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
containerSize: animationFrame.size
|
containerSize: animationFrame.size
|
||||||
)
|
)
|
||||||
if let view = animationView.view {
|
if let view = animationView.view {
|
||||||
|
view.isUserInteractionEnabled = false
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
self.view.addSubview(view)
|
self.view.addSubview(view)
|
||||||
}
|
}
|
||||||
@ -586,7 +680,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
|
|
||||||
private var touchDownGestureRecognizer: TouchDownGestureRecognizer?
|
private var touchDownGestureRecognizer: TouchDownGestureRecognizer?
|
||||||
|
|
||||||
private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||||
|
|
||||||
init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
|
init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
|
||||||
self.presentationInterfaceState = presentationInterfaceState
|
self.presentationInterfaceState = presentationInterfaceState
|
||||||
@ -2942,20 +3036,23 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
for (item, currentButton) in self.accessoryItemButtons {
|
for (item, currentButton) in self.accessoryItemButtons {
|
||||||
if currentButton === button {
|
if currentButton === button {
|
||||||
switch item {
|
switch item {
|
||||||
case let .stickers(enabled, _):
|
case let .input(isEnabled, inputMode), let .botInput(isEnabled, inputMode):
|
||||||
if enabled {
|
switch inputMode {
|
||||||
self.interfaceInteraction?.openStickers()
|
case .keyboard:
|
||||||
} else {
|
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
|
||||||
self.interfaceInteraction?.displayRestrictedInfo(.stickers, .tooltip)
|
return (.text, state.keyboardButtonsMessage?.id)
|
||||||
|
})
|
||||||
|
case .stickers, .emoji:
|
||||||
|
if isEnabled {
|
||||||
|
self.interfaceInteraction?.openStickers()
|
||||||
|
} else {
|
||||||
|
self.interfaceInteraction?.displayRestrictedInfo(.stickers, .tooltip)
|
||||||
|
}
|
||||||
|
case .bot:
|
||||||
|
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
|
||||||
|
return (.inputButtons, nil)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case .keyboard:
|
|
||||||
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
|
|
||||||
return (.text, state.keyboardButtonsMessage?.id)
|
|
||||||
})
|
|
||||||
case .inputButtons:
|
|
||||||
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
|
|
||||||
return (.inputButtons, nil)
|
|
||||||
})
|
|
||||||
case .commands:
|
case .commands:
|
||||||
self.interfaceInteraction?.updateTextInputStateAndMode { _, inputMode in
|
self.interfaceInteraction?.updateTextInputStateAndMode { _, inputMode in
|
||||||
return (ChatTextInputState(inputText: NSAttributedString(string: "/")), .text)
|
return (ChatTextInputState(inputText: NSAttributedString(string: "/")), .text)
|
||||||
@ -3011,7 +3108,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
|
|
||||||
func frameForStickersButton() -> CGRect? {
|
func frameForStickersButton() -> CGRect? {
|
||||||
for (item, button) in self.accessoryItemButtons {
|
for (item, button) in self.accessoryItemButtons {
|
||||||
if case .stickers = item {
|
if case let .input(_, inputMode) = item, case .stickers = inputMode {
|
||||||
return button.frame.insetBy(dx: 0.0, dy: 6.0)
|
return button.frame.insetBy(dx: 0.0, dy: 6.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,6 +329,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}, schedule: { [weak textInputPanelNode] in
|
}, schedule: { [weak textInputPanelNode] in
|
||||||
textInputPanelNode?.sendMessage(.schedule)
|
textInputPanelNode?.sendMessage(.schedule)
|
||||||
})
|
})
|
||||||
|
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
|
||||||
strongSelf.presentInGlobalOverlay(controller, nil)
|
strongSelf.presentInGlobalOverlay(controller, nil)
|
||||||
}, openScheduledMessages: {
|
}, openScheduledMessages: {
|
||||||
}, openPeersNearby: {
|
}, openPeersNearby: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user