mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Web app improvements
This commit is contained in:
parent
fdfe56f50a
commit
cfbacc23a6
@ -63,6 +63,11 @@ public protocol AttachmentMediaPickerContext {
|
|||||||
var selectionCount: Signal<Int, NoError> { get }
|
var selectionCount: Signal<Int, NoError> { get }
|
||||||
var caption: Signal<NSAttributedString?, NoError> { get }
|
var caption: Signal<NSAttributedString?, NoError> { get }
|
||||||
|
|
||||||
|
var loadingProgress: Signal<CGFloat?, NoError> { get }
|
||||||
|
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||||
|
|
||||||
|
func mainButtonAction()
|
||||||
|
|
||||||
func setCaption(_ caption: NSAttributedString)
|
func setCaption(_ caption: NSAttributedString)
|
||||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode)
|
func send(silently: Bool, mode: AttachmentMediaPickerSendMode)
|
||||||
func schedule()
|
func schedule()
|
||||||
@ -139,6 +144,9 @@ public class AttachmentController: ViewController {
|
|||||||
private let captionDisposable = MetaDisposable()
|
private let captionDisposable = MetaDisposable()
|
||||||
private let mediaSelectionCountDisposable = MetaDisposable()
|
private let mediaSelectionCountDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private let loadingProgressDisposable = MetaDisposable()
|
||||||
|
private let mainButtonStateDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var selectionCount: Int = 0
|
private var selectionCount: Int = 0
|
||||||
|
|
||||||
fileprivate var mediaPickerContext: AttachmentMediaPickerContext? {
|
fileprivate var mediaPickerContext: AttachmentMediaPickerContext? {
|
||||||
@ -156,9 +164,30 @@ public class AttachmentController: ViewController {
|
|||||||
strongSelf.updateSelectionCount(count)
|
strongSelf.updateSelectionCount(count)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
self.loadingProgressDisposable.set((mediaPickerContext.loadingProgress
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] progress in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.panel.updateLoadingProgress(progress)
|
||||||
|
if let layout = strongSelf.validLayout {
|
||||||
|
print(progress ?? 0)
|
||||||
|
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
self.mainButtonStateDisposable.set((mediaPickerContext.mainButtonState
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] mainButtonState in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.panel.updateMainButtonState(mainButtonState)
|
||||||
|
if let layout = strongSelf.validLayout {
|
||||||
|
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
self.updateSelectionCount(0)
|
self.updateSelectionCount(0)
|
||||||
self.mediaSelectionCountDisposable.set(nil)
|
self.mediaSelectionCountDisposable.set(nil)
|
||||||
|
self.loadingProgressDisposable.set(nil)
|
||||||
|
self.mainButtonStateDisposable.set(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,6 +283,12 @@ public class AttachmentController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.panel.mainButtonPressed = { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.mediaPickerContext?.mainButtonAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.panel.requestLayout = { [weak self] in
|
self.panel.requestLayout = { [weak self] in
|
||||||
if let strongSelf = self, let layout = strongSelf.validLayout {
|
if let strongSelf = self, let layout = strongSelf.validLayout {
|
||||||
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||||
@ -553,13 +588,28 @@ public class AttachmentController: ViewController {
|
|||||||
self.wrapperNode.view.mask = nil
|
self.wrapperNode.view.mask = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var containerInsets = containerLayout.intrinsicInsets
|
||||||
|
var hasPanel = false
|
||||||
|
let hasButton = self.panel.isButtonVisible
|
||||||
|
if let controller = self.controller, controller.buttons.count > 1 {
|
||||||
|
hasPanel = true
|
||||||
|
}
|
||||||
|
|
||||||
let isEffecitvelyCollapsedUpdated = (self.selectionCount > 0) != (self.panel.isSelecting)
|
let isEffecitvelyCollapsedUpdated = (self.selectionCount > 0) != (self.panel.isSelecting)
|
||||||
let panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isSelecting: self.selectionCount > 0, transition: transition)
|
let panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isSelecting: self.selectionCount > 0, transition: !hasPanel && hasButton ? .immediate : transition)
|
||||||
|
if hasPanel || hasButton {
|
||||||
|
containerInsets.bottom = panelHeight
|
||||||
|
}
|
||||||
|
|
||||||
var panelTransition = transition
|
var panelTransition = transition
|
||||||
if isEffecitvelyCollapsedUpdated {
|
if isEffecitvelyCollapsedUpdated {
|
||||||
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
}
|
}
|
||||||
panelTransition.updateFrame(node: self.panel, frame: CGRect(origin: CGPoint(x: 0.0, y: containerRect.height - panelHeight), size: CGSize(width: containerRect.width, height: panelHeight)))
|
var panelY = containerRect.height - panelHeight
|
||||||
|
if !hasPanel && !hasButton {
|
||||||
|
panelY = containerRect.height
|
||||||
|
}
|
||||||
|
panelTransition.updateFrame(node: self.panel, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: containerRect.width, height: panelHeight)))
|
||||||
|
|
||||||
var shadowFrame = containerRect.insetBy(dx: -60.0, dy: -60.0)
|
var shadowFrame = containerRect.insetBy(dx: -60.0, dy: -60.0)
|
||||||
shadowFrame.size.height -= 12.0
|
shadowFrame.size.height -= 12.0
|
||||||
@ -579,22 +629,13 @@ public class AttachmentController: ViewController {
|
|||||||
let controllers = self.currentControllers
|
let controllers = self.currentControllers
|
||||||
containerTransition.updateFrame(node: self.container, frame: CGRect(origin: CGPoint(), size: containerRect.size))
|
containerTransition.updateFrame(node: self.container, frame: CGRect(origin: CGPoint(), size: containerRect.size))
|
||||||
|
|
||||||
var containerInsets = containerLayout.intrinsicInsets
|
|
||||||
var hasPanel = false
|
|
||||||
if let controller = self.controller, controller.buttons.count > 1 {
|
|
||||||
hasPanel = true
|
|
||||||
containerInsets.bottom = panelHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
let containerLayout = containerLayout.withUpdatedIntrinsicInsets(containerInsets)
|
let containerLayout = containerLayout.withUpdatedIntrinsicInsets(containerInsets)
|
||||||
|
|
||||||
self.container.update(layout: containerLayout, controllers: controllers, coveredByModalTransition: 0.0, transition: self.switchingController ? .immediate : transition)
|
self.container.update(layout: containerLayout, controllers: controllers, coveredByModalTransition: 0.0, transition: self.switchingController ? .immediate : transition)
|
||||||
|
|
||||||
if self.container.supernode == nil, !controllers.isEmpty && self.container.isReady {
|
if self.container.supernode == nil, !controllers.isEmpty && self.container.isReady {
|
||||||
self.wrapperNode.addSubnode(self.container)
|
self.wrapperNode.addSubnode(self.container)
|
||||||
if hasPanel {
|
|
||||||
self.container.addSubnode(self.panel)
|
self.container.addSubnode(self.panel)
|
||||||
}
|
|
||||||
|
|
||||||
self.animateIn()
|
self.animateIn()
|
||||||
}
|
}
|
||||||
|
@ -284,6 +284,153 @@ private final class AttachButtonComponent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class LoadingProgressNode: ASDisplayNode {
|
||||||
|
var color: UIColor {
|
||||||
|
didSet {
|
||||||
|
self.foregroundNode.backgroundColor = self.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let foregroundNode: ASDisplayNode
|
||||||
|
|
||||||
|
init(color: UIColor) {
|
||||||
|
self.color = color
|
||||||
|
|
||||||
|
self.foregroundNode = ASDisplayNode()
|
||||||
|
self.foregroundNode.backgroundColor = color
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.foregroundNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _progress: CGFloat = 0.0
|
||||||
|
func updateProgress(_ progress: CGFloat, animated: Bool = false) {
|
||||||
|
if self._progress == progress && animated {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var animated = animated
|
||||||
|
if (progress < self._progress && animated) {
|
||||||
|
animated = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = self.bounds.size
|
||||||
|
|
||||||
|
self._progress = progress
|
||||||
|
|
||||||
|
let transition: ContainedViewLayoutTransition
|
||||||
|
if animated && progress > 0.0 {
|
||||||
|
transition = .animated(duration: 0.7, curve: .spring)
|
||||||
|
} else {
|
||||||
|
transition = .immediate
|
||||||
|
}
|
||||||
|
|
||||||
|
let alpaTransition: ContainedViewLayoutTransition
|
||||||
|
if animated {
|
||||||
|
alpaTransition = .animated(duration: 0.3, curve: .easeInOut)
|
||||||
|
} else {
|
||||||
|
alpaTransition = .immediate
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.foregroundNode, frame: CGRect(x: -2.0, y: 0.0, width: (size.width + 4.0) * progress, height: size.height))
|
||||||
|
|
||||||
|
let alpha: CGFloat = progress < 0.001 || progress > 0.999 ? 0.0 : 1.0
|
||||||
|
alpaTransition.updateAlpha(node: self.foregroundNode, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layout() {
|
||||||
|
super.layout()
|
||||||
|
|
||||||
|
self.foregroundNode.cornerRadius = self.frame.height / 2.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AttachmentMainButtonState {
|
||||||
|
let text: String?
|
||||||
|
let backgroundColor: UIColor
|
||||||
|
let textColor: UIColor
|
||||||
|
let isEnabled: Bool
|
||||||
|
let isVisible: Bool
|
||||||
|
|
||||||
|
public init(
|
||||||
|
text: String?,
|
||||||
|
backgroundColor: UIColor,
|
||||||
|
textColor: UIColor,
|
||||||
|
isEnabled: Bool,
|
||||||
|
isVisible: Bool
|
||||||
|
) {
|
||||||
|
self.text = text
|
||||||
|
self.backgroundColor = backgroundColor
|
||||||
|
self.textColor = textColor
|
||||||
|
self.isEnabled = isEnabled
|
||||||
|
self.isVisible = isVisible
|
||||||
|
}
|
||||||
|
|
||||||
|
static var initial: AttachmentMainButtonState {
|
||||||
|
return AttachmentMainButtonState(text: nil, backgroundColor: .clear, textColor: .clear, isEnabled: false, isVisible: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class MainButtonNode: HighlightTrackingButtonNode {
|
||||||
|
private var state: AttachmentMainButtonState
|
||||||
|
|
||||||
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let textNode: ImmediateTextNode
|
||||||
|
|
||||||
|
override init(pointerStyle: PointerStyle? = nil) {
|
||||||
|
self.state = AttachmentMainButtonState.initial
|
||||||
|
|
||||||
|
self.backgroundNode = ASDisplayNode()
|
||||||
|
self.backgroundNode.allowsGroupOpacity = true
|
||||||
|
self.backgroundNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.textNode = ImmediateTextNode()
|
||||||
|
self.textNode.textAlignment = .center
|
||||||
|
|
||||||
|
super.init(pointerStyle: pointerStyle)
|
||||||
|
|
||||||
|
self.addSubnode(self.backgroundNode)
|
||||||
|
self.backgroundNode.addSubnode(self.textNode)
|
||||||
|
|
||||||
|
self.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self, strongSelf.state.isEnabled {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.backgroundNode.alpha = 0.65
|
||||||
|
} else {
|
||||||
|
strongSelf.backgroundNode.alpha = 1.0
|
||||||
|
strongSelf.backgroundNode.layer.animateAlpha(from: 0.65, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLayout(layout: ContainerViewLayout, state: AttachmentMainButtonState, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
self.isUserInteractionEnabled = state.isVisible
|
||||||
|
self.isEnabled = state.isEnabled
|
||||||
|
transition.updateAlpha(node: self, alpha: state.isEnabled ? 1.0 : 0.4)
|
||||||
|
|
||||||
|
let buttonHeight = 50.0
|
||||||
|
if let text = state.text {
|
||||||
|
self.textNode.attributedText = NSAttributedString(string: text, font: Font.semibold(16.0), textColor: state.textColor)
|
||||||
|
|
||||||
|
let textSize = self.textNode.updateLayout(layout.size)
|
||||||
|
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - textSize.width) / 2.0), y: floorToScreenPixels((buttonHeight - textSize.height) / 2.0)), size: textSize)
|
||||||
|
|
||||||
|
self.backgroundNode.backgroundColor = state.backgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
let totalButtonHeight = buttonHeight + layout.intrinsicInsets.bottom
|
||||||
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: totalButtonHeight)))
|
||||||
|
transition.updateSublayerTransformOffset(layer: self.layer, offset: CGPoint(x: 0.0, y: state.isVisible ? 0.0 : totalButtonHeight))
|
||||||
|
|
||||||
|
return totalButtonHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
@ -301,10 +448,16 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
private var buttonViews: [Int: ComponentHostView<Empty>] = [:]
|
private var buttonViews: [Int: ComponentHostView<Empty>] = [:]
|
||||||
|
|
||||||
private var textInputPanelNode: AttachmentTextInputPanelNode?
|
private var textInputPanelNode: AttachmentTextInputPanelNode?
|
||||||
|
private var progressNode: LoadingProgressNode?
|
||||||
|
private var mainButtonNode: MainButtonNode
|
||||||
|
|
||||||
|
private var loadingProgress: CGFloat?
|
||||||
|
private var mainButtonState: AttachmentMainButtonState = .initial
|
||||||
|
|
||||||
private var buttons: [AttachmentButtonType] = []
|
private var buttons: [AttachmentButtonType] = []
|
||||||
private var selectedIndex: Int = 0
|
private var selectedIndex: Int = 0
|
||||||
private(set) var isSelecting: Bool = false
|
private(set) var isSelecting: Bool = false
|
||||||
|
private(set) var isButtonVisible: Bool = false
|
||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
private var scrollLayout: (width: CGFloat, contentSize: CGSize)?
|
private var scrollLayout: (width: CGFloat, contentSize: CGSize)?
|
||||||
@ -317,6 +470,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
var present: (ViewController) -> Void = { _ in }
|
var present: (ViewController) -> Void = { _ in }
|
||||||
var presentInGlobalOverlay: (ViewController) -> Void = { _ in }
|
var presentInGlobalOverlay: (ViewController) -> Void = { _ in }
|
||||||
|
|
||||||
|
var mainButtonPressed: () -> Void = { }
|
||||||
|
|
||||||
init(context: AccountContext, chatLocation: ChatLocation, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?) {
|
init(context: AccountContext, chatLocation: ChatLocation, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
@ -332,6 +487,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.separatorNode = ASDisplayNode()
|
self.separatorNode = ASDisplayNode()
|
||||||
self.separatorNode.backgroundColor = self.presentationData.theme.rootController.tabBar.separatorColor
|
self.separatorNode.backgroundColor = self.presentationData.theme.rootController.tabBar.separatorColor
|
||||||
|
|
||||||
|
self.mainButtonNode = MainButtonNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.containerNode)
|
self.addSubnode(self.containerNode)
|
||||||
@ -339,6 +496,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.containerNode.addSubnode(self.separatorNode)
|
self.containerNode.addSubnode(self.separatorNode)
|
||||||
self.containerNode.addSubnode(self.scrollNode)
|
self.containerNode.addSubnode(self.scrollNode)
|
||||||
|
|
||||||
|
self.addSubnode(self.mainButtonNode)
|
||||||
|
|
||||||
|
self.mainButtonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
|
self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
|
||||||
}, setupEditMessage: { _, _ in
|
}, setupEditMessage: { _, _ in
|
||||||
}, beginMessageSelection: { _, _ in
|
}, beginMessageSelection: { _, _ in
|
||||||
@ -543,6 +704,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.scrollNode.view.showsVerticalScrollIndicator = false
|
self.scrollNode.view.showsVerticalScrollIndicator = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func buttonPressed() {
|
||||||
|
self.mainButtonPressed()
|
||||||
|
}
|
||||||
|
|
||||||
func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
|
func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
transition.updateAlpha(node: self.separatorNode, alpha: alpha)
|
transition.updateAlpha(node: self.separatorNode, alpha: alpha)
|
||||||
transition.updateAlpha(node: self.backgroundNode, alpha: alpha)
|
transition.updateAlpha(node: self.backgroundNode, alpha: alpha)
|
||||||
@ -669,7 +834,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
self.scrollLayout = (layout.size.width, contentSize)
|
self.scrollLayout = (layout.size.width, contentSize)
|
||||||
|
|
||||||
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isSelecting ? -buttonSize.height : 0.0), size: CGSize(width: layout.size.width, height: buttonSize.height)))
|
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isSelecting || self.isButtonVisible ? -buttonSize.height : 0.0), size: CGSize(width: layout.size.width, height: buttonSize.height)))
|
||||||
self.scrollNode.view.contentSize = contentSize
|
self.scrollNode.view.contentSize = contentSize
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -707,10 +872,25 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateLoadingProgress(_ progress: CGFloat?) {
|
||||||
|
self.loadingProgress = progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateMainButtonState(_ mainButtonState: AttachmentMainButtonState?) {
|
||||||
|
var currentButtonState = self.mainButtonState
|
||||||
|
if mainButtonState == nil {
|
||||||
|
currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, backgroundColor: currentButtonState.backgroundColor, textColor: currentButtonState.textColor, isEnabled: currentButtonState.isEnabled, isVisible: false)
|
||||||
|
}
|
||||||
|
self.mainButtonState = mainButtonState ?? currentButtonState
|
||||||
|
}
|
||||||
|
|
||||||
func update(layout: ContainerViewLayout, buttons: [AttachmentButtonType], isSelecting: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
func update(layout: ContainerViewLayout, buttons: [AttachmentButtonType], isSelecting: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
self.validLayout = layout
|
self.validLayout = layout
|
||||||
self.buttons = buttons
|
self.buttons = buttons
|
||||||
|
|
||||||
|
let isButtonVisibleUpdated = self.isButtonVisible != self.mainButtonState.isVisible
|
||||||
|
self.isButtonVisible = self.mainButtonState.isVisible
|
||||||
|
|
||||||
let isSelectingUpdated = self.isSelecting != isSelecting
|
let isSelectingUpdated = self.isSelecting != isSelecting
|
||||||
self.isSelecting = isSelecting
|
self.isSelecting = isSelecting
|
||||||
|
|
||||||
@ -723,6 +903,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
insets.bottom = layout.intrinsicInsets.bottom
|
insets.bottom = layout.intrinsicInsets.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isButtonVisible = self.mainButtonState.isVisible
|
||||||
|
|
||||||
if isSelecting {
|
if isSelecting {
|
||||||
self.loadTextNodeIfNeeded()
|
self.loadTextNodeIfNeeded()
|
||||||
} else {
|
} else {
|
||||||
@ -758,12 +940,12 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
containerFrame = bounds
|
containerFrame = bounds
|
||||||
}
|
}
|
||||||
let containerBounds = CGRect(origin: CGPoint(), size: containerFrame.size)
|
let containerBounds = CGRect(origin: CGPoint(), size: containerFrame.size)
|
||||||
if isSelectingUpdated {
|
if isSelectingUpdated || isButtonVisibleUpdated {
|
||||||
containerTransition = .animated(duration: 0.25, curve: .easeInOut)
|
containerTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
} else {
|
} else {
|
||||||
containerTransition = transition
|
containerTransition = transition
|
||||||
}
|
}
|
||||||
containerTransition.updateAlpha(node: self.scrollNode, alpha: isSelecting ? 0.0 : 1.0)
|
containerTransition.updateAlpha(node: self.scrollNode, alpha: isSelecting || isButtonVisible ? 0.0 : 1.0)
|
||||||
|
|
||||||
if isSelectingUpdated {
|
if isSelectingUpdated {
|
||||||
if isSelecting {
|
if isSelecting {
|
||||||
@ -788,10 +970,33 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.backgroundNode.update(size: containerBounds.size, transition: transition)
|
self.backgroundNode.update(size: containerBounds.size, transition: transition)
|
||||||
containerTransition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: UIScreenPixel)))
|
containerTransition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
let _ = self.updateScrollLayoutIfNeeded(force: isSelectingUpdated, transition: containerTransition)
|
let _ = self.updateScrollLayoutIfNeeded(force: isSelectingUpdated || isButtonVisibleUpdated, transition: containerTransition)
|
||||||
|
|
||||||
self.updateViews(transition: .immediate)
|
self.updateViews(transition: .immediate)
|
||||||
|
|
||||||
|
if let progress = self.loadingProgress {
|
||||||
|
let loadingProgressNode: LoadingProgressNode
|
||||||
|
if let current = self.progressNode {
|
||||||
|
loadingProgressNode = current
|
||||||
|
} else {
|
||||||
|
loadingProgressNode = LoadingProgressNode(color: self.presentationData.theme.rootController.tabBar.selectedIconColor)
|
||||||
|
self.addSubnode(loadingProgressNode)
|
||||||
|
self.progressNode = loadingProgressNode
|
||||||
|
}
|
||||||
|
let loadingProgressHeight: CGFloat = 2.0
|
||||||
|
transition.updateFrame(node: loadingProgressNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: loadingProgressHeight)))
|
||||||
|
|
||||||
|
loadingProgressNode.updateProgress(progress, animated: true)
|
||||||
|
} else if let progressNode = self.progressNode {
|
||||||
|
self.progressNode = nil
|
||||||
|
progressNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak progressNode] _ in
|
||||||
|
progressNode?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let mainButtonHeight = self.mainButtonNode.updateLayout(layout: layout, state: self.mainButtonState, transition: transition)
|
||||||
|
transition.updateFrame(node: self.mainButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: mainButtonHeight)))
|
||||||
|
|
||||||
return containerFrame.height
|
return containerFrame.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,14 @@ public class LegacyAssetPickerContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var loadingProgress: Signal<CGFloat?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
public init(controller: TGMediaAssetsController) {
|
public init(controller: TGMediaAssetsController) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
}
|
}
|
||||||
@ -111,6 +119,10 @@ public class LegacyAssetPickerContext: AttachmentMediaPickerContext {
|
|||||||
public func schedule() {
|
public func schedule() {
|
||||||
self.controller?.schedule(false)
|
self.controller?.schedule(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func mainButtonAction() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func legacyAssetPicker(context: AccountContext, presentationData: PresentationData, editingMedia: Bool, fileMode: Bool, peer: Peer?, saveEditedPhotos: Bool, allowGrouping: Bool, selectionLimit: Int) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> {
|
public func legacyAssetPicker(context: AccountContext, presentationData: PresentationData, editingMedia: Bool, fileMode: Bool, peer: Peer?, saveEditedPhotos: Bool, allowGrouping: Bool, selectionLimit: Int) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> {
|
||||||
|
@ -1473,6 +1473,14 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var loadingProgress: Signal<CGFloat?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
init(interaction: MediaPickerInteraction) {
|
init(interaction: MediaPickerInteraction) {
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
}
|
}
|
||||||
@ -1488,6 +1496,10 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
|
|||||||
func schedule() {
|
func schedule() {
|
||||||
self.interaction?.schedule()
|
self.interaction?.schedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mainButtonAction() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class MediaPickerContextReferenceContentSource: ContextReferenceContentSource {
|
private final class MediaPickerContextReferenceContentSource: ContextReferenceContentSource {
|
||||||
|
@ -10904,7 +10904,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
completion(controller, nil)
|
completion(controller, controller.mediaPickerContext)
|
||||||
strongSelf.controllerNavigationDisposable.set(nil)
|
strongSelf.controllerNavigationDisposable.set(nil)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -427,6 +427,14 @@ final class ContactsPickerContext: AttachmentMediaPickerContext {
|
|||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var loadingProgress: Signal<CGFloat?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
init(controller: ContactSelectionControllerImpl) {
|
init(controller: ContactSelectionControllerImpl) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
}
|
}
|
||||||
@ -444,4 +452,7 @@ final class ContactsPickerContext: AttachmentMediaPickerContext {
|
|||||||
self.controller?.contactsNode.requestMultipleAction?(false, time)
|
self.controller?.contactsNode.requestMultipleAction?(false, time)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mainButtonAction() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,6 +593,14 @@ public class WebSearchPickerContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var loadingProgress: Signal<CGFloat?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
init(interaction: WebSearchControllerInteraction) {
|
init(interaction: WebSearchControllerInteraction) {
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
}
|
}
|
||||||
@ -608,4 +616,8 @@ public class WebSearchPickerContext: AttachmentMediaPickerContext {
|
|||||||
public func schedule() {
|
public func schedule() {
|
||||||
self.interaction?.schedule()
|
self.interaction?.schedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func mainButtonAction() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,134 +33,6 @@ public func generateWebAppThemeParams(_ presentationTheme: PresentationTheme) ->
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class LoadingProgressNode: ASDisplayNode {
|
|
||||||
var color: UIColor {
|
|
||||||
didSet {
|
|
||||||
self.foregroundNode.backgroundColor = self.color
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private let foregroundNode: ASDisplayNode
|
|
||||||
|
|
||||||
init(color: UIColor) {
|
|
||||||
self.color = color
|
|
||||||
|
|
||||||
self.foregroundNode = ASDisplayNode()
|
|
||||||
self.foregroundNode.backgroundColor = color
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.addSubnode(self.foregroundNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _progress: CGFloat = 0.0
|
|
||||||
func updateProgress(_ progress: CGFloat, animated: Bool = false) {
|
|
||||||
if self._progress == progress && animated {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var animated = animated
|
|
||||||
if (progress < self._progress && animated) {
|
|
||||||
animated = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let size = self.bounds.size
|
|
||||||
|
|
||||||
self._progress = progress
|
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition
|
|
||||||
if animated && progress > 0.0 {
|
|
||||||
transition = .animated(duration: 0.7, curve: .spring)
|
|
||||||
} else {
|
|
||||||
transition = .immediate
|
|
||||||
}
|
|
||||||
|
|
||||||
let alpaTransition: ContainedViewLayoutTransition
|
|
||||||
if animated {
|
|
||||||
alpaTransition = .animated(duration: 0.3, curve: .easeInOut)
|
|
||||||
} else {
|
|
||||||
alpaTransition = .immediate
|
|
||||||
}
|
|
||||||
|
|
||||||
transition.updateFrame(node: self.foregroundNode, frame: CGRect(x: -2.0, y: 0.0, width: (size.width + 4.0) * progress, height: size.height))
|
|
||||||
|
|
||||||
let alpha: CGFloat = progress < 0.001 || progress > 0.999 ? 0.0 : 1.0
|
|
||||||
alpaTransition.updateAlpha(node: self.foregroundNode, alpha: alpha)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func layout() {
|
|
||||||
super.layout()
|
|
||||||
|
|
||||||
self.foregroundNode.cornerRadius = self.frame.height / 2.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class MainButtonNode: HighlightTrackingButtonNode {
|
|
||||||
struct State {
|
|
||||||
let text: String?
|
|
||||||
let backgroundColor: UIColor
|
|
||||||
let textColor: UIColor
|
|
||||||
let isEnabled: Bool
|
|
||||||
let isVisible: Bool
|
|
||||||
}
|
|
||||||
private var state: State
|
|
||||||
|
|
||||||
private let backgroundNode: ASDisplayNode
|
|
||||||
private let textNode: ImmediateTextNode
|
|
||||||
|
|
||||||
override init(pointerStyle: PointerStyle? = nil) {
|
|
||||||
self.state = State(text: nil, backgroundColor: .clear, textColor: .clear, isEnabled: false, isVisible: false)
|
|
||||||
|
|
||||||
self.backgroundNode = ASDisplayNode()
|
|
||||||
self.backgroundNode.allowsGroupOpacity = true
|
|
||||||
self.backgroundNode.isUserInteractionEnabled = false
|
|
||||||
|
|
||||||
self.textNode = ImmediateTextNode()
|
|
||||||
self.textNode.textAlignment = .center
|
|
||||||
|
|
||||||
super.init(pointerStyle: pointerStyle)
|
|
||||||
|
|
||||||
self.addSubnode(self.backgroundNode)
|
|
||||||
self.backgroundNode.addSubnode(self.titleNode)
|
|
||||||
|
|
||||||
self.highligthedChanged = { [weak self] highlighted in
|
|
||||||
if let strongSelf = self, strongSelf.state.isEnabled {
|
|
||||||
if highlighted {
|
|
||||||
strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity")
|
|
||||||
strongSelf.backgroundNode.alpha = 0.65
|
|
||||||
} else {
|
|
||||||
strongSelf.backgroundNode.alpha = 1.0
|
|
||||||
strongSelf.backgroundNode.layer.animateAlpha(from: 0.65, to: 1.0, duration: 0.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateLayout(layout: ContainerViewLayout, state: State, transition: ContainedViewLayoutTransition) -> CGFloat {
|
|
||||||
self.state = state
|
|
||||||
|
|
||||||
self.isUserInteractionEnabled = state.isVisible
|
|
||||||
self.isEnabled = state.isEnabled
|
|
||||||
transition.updateAlpha(node: self, alpha: state.isEnabled ? 1.0 : 0.4)
|
|
||||||
|
|
||||||
let buttonHeight = 50.0
|
|
||||||
if let text = state.text {
|
|
||||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.semibold(16.0), textColor: state.textColor)
|
|
||||||
|
|
||||||
let textSize = self.textNode.updateLayout(layout.size)
|
|
||||||
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - textSize.width) / 2.0), y: floorToScreenPixels((buttonHeight - textSize.height) / 2.0)), size: textSize)
|
|
||||||
|
|
||||||
self.backgroundNode.backgroundColor = state.backgroundColor
|
|
||||||
}
|
|
||||||
|
|
||||||
let totalButtonHeight = buttonHeight + layout.intrinsicInsets.bottom
|
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: totalButtonHeight)))
|
|
||||||
transition.updateSublayerTransformOffset(layer: self.layer, offset: CGPoint(x: 0.0, y: state.isVisible ? 0.0 : totalButtonHeight))
|
|
||||||
|
|
||||||
return totalButtonHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class WebAppController: ViewController, AttachmentContainable {
|
public final class WebAppController: ViewController, AttachmentContainable {
|
||||||
public var requestAttachmentMenuExpansion: () -> Void = { }
|
public var requestAttachmentMenuExpansion: () -> Void = { }
|
||||||
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
|
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
|
||||||
@ -168,16 +40,15 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
public var cancelPanGesture: () -> Void = { }
|
public var cancelPanGesture: () -> Void = { }
|
||||||
public var isContainerPanning: () -> Bool = { return false }
|
public var isContainerPanning: () -> Bool = { return false }
|
||||||
|
|
||||||
private class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate {
|
fileprivate class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate {
|
||||||
private weak var controller: WebAppController?
|
private weak var controller: WebAppController?
|
||||||
|
|
||||||
fileprivate var webView: WebAppWebView?
|
fileprivate var webView: WebAppWebView?
|
||||||
|
|
||||||
private var placeholderIcon: UIImage?
|
private var placeholderIcon: UIImage?
|
||||||
private var placeholderNode: ShimmerEffectNode?
|
private var placeholderNode: ShimmerEffectNode?
|
||||||
private let loadingProgressNode: LoadingProgressNode
|
|
||||||
private let mainButtonNode: MainButtonNode
|
fileprivate let loadingProgressPromise = Promise<CGFloat?>(nil)
|
||||||
private var mainButtonState: MainButtonNode.State?
|
fileprivate let mainButtonStatePromise = Promise<AttachmentMainButtonState?>(nil)
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
var presentationData: PresentationData
|
var presentationData: PresentationData
|
||||||
@ -193,9 +64,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.presentationData = controller.presentationData
|
self.presentationData = controller.presentationData
|
||||||
self.present = present
|
self.present = present
|
||||||
|
|
||||||
self.loadingProgressNode = LoadingProgressNode(color: presentationData.theme.rootController.tabBar.selectedIconColor)
|
|
||||||
self.mainButtonNode = MainButtonNode()
|
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if self.presentationData.theme.list.plainBackgroundColor.rgb == 0x000000 {
|
if self.presentationData.theme.list.plainBackgroundColor.rgb == 0x000000 {
|
||||||
@ -219,8 +87,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
let placeholderNode = ShimmerEffectNode()
|
let placeholderNode = ShimmerEffectNode()
|
||||||
self.addSubnode(placeholderNode)
|
self.addSubnode(placeholderNode)
|
||||||
self.placeholderNode = placeholderNode
|
self.placeholderNode = placeholderNode
|
||||||
self.addSubnode(self.loadingProgressNode)
|
|
||||||
self.addSubnode(self.mainButtonNode)
|
|
||||||
|
|
||||||
if let iconFile = controller.iconFile {
|
if let iconFile = controller.iconFile {
|
||||||
let _ = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .standalone(media: iconFile)).start()
|
let _ = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .standalone(media: iconFile)).start()
|
||||||
@ -299,6 +165,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.view.addSubview(webView)
|
self.view.addSubview(webView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc fileprivate func mainButtonPressed() {
|
||||||
|
self.webView?.sendEvent(name: "main_button_pressed", data: nil)
|
||||||
|
}
|
||||||
|
|
||||||
private func updatePlaceholder() {
|
private func updatePlaceholder() {
|
||||||
guard let image = self.placeholderIcon else {
|
guard let image = self.placeholderIcon else {
|
||||||
return
|
return
|
||||||
@ -360,7 +230,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
let previous = self.validLayout?.0
|
let previousLayout = self.validLayout?.0
|
||||||
self.validLayout = (layout, navigationBarHeight)
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
if let webView = self.webView {
|
if let webView = self.webView {
|
||||||
@ -384,24 +254,16 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
let placeholderFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - iconSize.width) / 2.0), y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize)
|
let placeholderFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - iconSize.width) / 2.0), y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
transition.updateFrame(node: placeholderNode, frame: placeholderFrame)
|
transition.updateFrame(node: placeholderNode, frame: placeholderFrame)
|
||||||
placeholderNode.updateAbsoluteRect(placeholderFrame, within: layout.size)
|
placeholderNode.updateAbsoluteRect(placeholderFrame, within: layout.size)
|
||||||
|
|
||||||
let loadingProgressHeight: CGFloat = 2.0
|
|
||||||
transition.updateFrame(node: self.loadingProgressNode, frame: CGRect(origin: CGPoint(x: 0.0, y: height - loadingProgressHeight), size: CGSize(width: layout.size.width, height: loadingProgressHeight)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let previous = previous, (previous.inputHeight ?? 0.0).isZero, let inputHeight = layout.inputHeight, inputHeight > 44.0 {
|
if let previousLayout = previousLayout, (previousLayout.inputHeight ?? 0.0).isZero, let inputHeight = layout.inputHeight, inputHeight > 44.0 {
|
||||||
self.controller?.requestAttachmentMenuExpansion()
|
self.controller?.requestAttachmentMenuExpansion()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let mainButtonState = self.mainButtonState {
|
|
||||||
let mainButtonHeight = self.mainButtonNode.updateLayout(layout: layout, state: mainButtonState, transition: transition)
|
|
||||||
transition.updateFrame(node: self.mainButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - mainButtonHeight - layout.additionalInsets.bottom), size: CGSize(width: layout.size.width, height: mainButtonHeight)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
if keyPath == "estimatedProgress", let webView = self.webView {
|
if keyPath == "estimatedProgress", let webView = self.webView {
|
||||||
self.loadingProgressNode.updateProgress(webView.estimatedProgress, animated: true)
|
self.loadingProgressPromise.set(.single(CGFloat(webView.estimatedProgress)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,12 +282,15 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.handleSendData(data: eventData)
|
self.handleSendData(data: eventData)
|
||||||
}
|
}
|
||||||
case "web_app_setup_main_button":
|
case "web_app_setup_main_button":
|
||||||
if let eventData = body["eventData"] as? String {
|
if let eventData = (body["eventData"] as? String)?.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: eventData, options: []) as? [String: Any] {
|
||||||
print(eventData)
|
if let backgroundColorString = json["color"] as? String, let backgroundColor = UIColor(hexString: backgroundColorString),
|
||||||
|
let textColorString = json["text_color"] as? String, let textColor = UIColor(hexString: textColorString),
|
||||||
// self.mainButtonState = MainButtonNode.State(text: <#T##String?#>, backgroundColor: <#T##UIColor#>, textColor: <#T##UIColor#>, isEnabled: <#T##Bool#>, isVisible: <#T##Bool#>)
|
let text = json["text"] as? String,
|
||||||
if let (layout, navigationBarHeight) = self.validLayout {
|
let isEnabled = json["is_active"] as? Bool,
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.2, curve: .easeInOut))
|
let isVisible = json["is_visible"] as? Bool
|
||||||
|
{
|
||||||
|
let state = AttachmentMainButtonState(text: text, backgroundColor: backgroundColor, textColor: textColor, isEnabled: isEnabled, isVisible: isVisible)
|
||||||
|
self.mainButtonStatePromise.set(.single(state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "web_app_close":
|
case "web_app_close":
|
||||||
@ -482,7 +347,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var controllerNode: Node {
|
fileprivate var controllerNode: Node {
|
||||||
return self.displayNode as! Node
|
return self.displayNode as! Node
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,8 +525,50 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
} set(value) {
|
} set(value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var mediaPickerContext: AttachmentMediaPickerContext? {
|
||||||
|
return WebAppPickerContext(controller: self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class WebAppPickerContext: AttachmentMediaPickerContext {
|
||||||
|
private weak var controller: WebAppController?
|
||||||
|
|
||||||
|
var selectionCount: Signal<Int, NoError> {
|
||||||
|
return .single(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var caption: Signal<NSAttributedString?, NoError> {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var loadingProgress: Signal<CGFloat?, NoError> {
|
||||||
|
return self.controller?.controllerNode.loadingProgressPromise.get() ?? .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||||
|
return self.controller?.controllerNode.mainButtonStatePromise.get() ?? .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(controller: WebAppController) {
|
||||||
|
self.controller = controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCaption(_ caption: NSAttributedString) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func schedule() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func mainButtonAction() {
|
||||||
|
self.controller?.controllerNode.mainButtonPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private final class WebAppContextReferenceContentSource: ContextReferenceContentSource {
|
private final class WebAppContextReferenceContentSource: ContextReferenceContentSource {
|
||||||
private let controller: ViewController
|
private let controller: ViewController
|
||||||
private let sourceNode: ContextReferenceContentNode
|
private let sourceNode: ContextReferenceContentNode
|
||||||
@ -682,7 +589,7 @@ public func standaloneWebAppController(context: AccountContext, updatedPresentat
|
|||||||
let webAppController = WebAppController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, botId: botId, botName: botName, url: url, queryId: queryId, buttonText: buttonText, keepAliveSignal: keepAliveSignal, replyToMessageId: nil, iconFile: nil)
|
let webAppController = WebAppController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, botId: botId, botName: botName, url: url, queryId: queryId, buttonText: buttonText, keepAliveSignal: keepAliveSignal, replyToMessageId: nil, iconFile: nil)
|
||||||
webAppController.openUrl = openUrl
|
webAppController.openUrl = openUrl
|
||||||
webAppController.completion = completion
|
webAppController.completion = completion
|
||||||
present(webAppController, nil)
|
present(webAppController, webAppController.mediaPickerContext)
|
||||||
}
|
}
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,8 @@ final class WebAppWebView: WKWebView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendEvent(name: String, data: String) {
|
func sendEvent(name: String, data: String?) {
|
||||||
let script = "window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data))"
|
let script = "window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data ?? "null"))"
|
||||||
self.evaluateJavaScript(script, completionHandler: { _, _ in
|
self.evaluateJavaScript(script, completionHandler: { _, _ in
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user