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
5941becc33
commit
0f597d457e
@ -5,6 +5,13 @@ public struct AttachmentMainButtonState {
|
||||
public enum Background {
|
||||
case color(UIColor)
|
||||
case premium
|
||||
|
||||
public var colorValue: UIColor? {
|
||||
if case let .color(color) = self {
|
||||
return color
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public enum Progress: Equatable {
|
||||
@ -18,6 +25,13 @@ public struct AttachmentMainButtonState {
|
||||
case bold
|
||||
}
|
||||
|
||||
public enum Position: String, Equatable {
|
||||
case top
|
||||
case bottom
|
||||
case left
|
||||
case right
|
||||
}
|
||||
|
||||
public let text: String?
|
||||
public let font: Font
|
||||
public let background: Background
|
||||
@ -25,6 +39,8 @@ public struct AttachmentMainButtonState {
|
||||
public let isVisible: Bool
|
||||
public let progress: Progress
|
||||
public let isEnabled: Bool
|
||||
public let hasShimmer: Bool
|
||||
public let position: Position?
|
||||
|
||||
public init(
|
||||
text: String?,
|
||||
@ -33,7 +49,9 @@ public struct AttachmentMainButtonState {
|
||||
textColor: UIColor,
|
||||
isVisible: Bool,
|
||||
progress: Progress,
|
||||
isEnabled: Bool
|
||||
isEnabled: Bool,
|
||||
hasShimmer: Bool,
|
||||
position: Position? = nil
|
||||
) {
|
||||
self.text = text
|
||||
self.font = font
|
||||
@ -42,9 +60,11 @@ public struct AttachmentMainButtonState {
|
||||
self.isVisible = isVisible
|
||||
self.progress = progress
|
||||
self.isEnabled = isEnabled
|
||||
self.hasShimmer = hasShimmer
|
||||
self.position = position
|
||||
}
|
||||
|
||||
public static var initial: AttachmentMainButtonState {
|
||||
return AttachmentMainButtonState(text: nil, font: .bold, background: .color(.clear), textColor: .clear, isVisible: false, progress: .none, isEnabled: false)
|
||||
return AttachmentMainButtonState(text: nil, font: .bold, background: .color(.clear), textColor: .clear, isVisible: false, progress: .none, isEnabled: false, hasShimmer: false)
|
||||
}
|
||||
}
|
||||
|
@ -215,8 +215,11 @@ public protocol AttachmentMediaPickerContext {
|
||||
|
||||
var loadingProgress: Signal<CGFloat?, NoError> { get }
|
||||
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||
var secondaryButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||
var bottomPanelBackgroundColor: Signal<UIColor?, NoError> { get }
|
||||
|
||||
func mainButtonAction()
|
||||
func secondaryButtonAction()
|
||||
|
||||
func setCaption(_ caption: NSAttributedString)
|
||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?)
|
||||
@ -261,6 +264,14 @@ public extension AttachmentMediaPickerContext {
|
||||
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
var secondaryButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
var bottomPanelBackgroundColor: Signal<UIColor?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
}
|
||||
@ -273,6 +284,9 @@ public extension AttachmentMediaPickerContext {
|
||||
|
||||
func mainButtonAction() {
|
||||
}
|
||||
|
||||
func secondaryButtonAction() {
|
||||
}
|
||||
}
|
||||
|
||||
private func generateShadowImage() -> UIImage? {
|
||||
@ -364,6 +378,8 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
|
||||
private let loadingProgressDisposable = MetaDisposable()
|
||||
private let mainButtonStateDisposable = MetaDisposable()
|
||||
private let secondaryButtonStateDisposable = MetaDisposable()
|
||||
private let bottomPanelBackgroundColorDisposable = MetaDisposable()
|
||||
|
||||
private var selectionCount: Int = 0
|
||||
|
||||
@ -408,11 +424,44 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
})
|
||||
}
|
||||
}))
|
||||
self.secondaryButtonStateDisposable.set((mediaPickerContext.secondaryButtonState
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] mainButtonState in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.panel.animatingTransitionPromise.get()
|
||||
|> filter { value in
|
||||
return !value
|
||||
}
|
||||
|> take(1)).startStandalone(next: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.panel.updateSecondaryButtonState(mainButtonState)
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
self.bottomPanelBackgroundColorDisposable.set((mediaPickerContext.bottomPanelBackgroundColor
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] color in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.panel.animatingTransitionPromise.get()
|
||||
|> filter { value in
|
||||
return !value
|
||||
}
|
||||
|> take(1)).startStandalone(next: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.panel.updateCustomBottomPanelBackgroundColor(color)
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
self.updateSelectionCount(0)
|
||||
self.mediaSelectionCountDisposable.set(nil)
|
||||
self.loadingProgressDisposable.set(nil)
|
||||
self.mainButtonStateDisposable.set(nil)
|
||||
self.secondaryButtonStateDisposable.set(nil)
|
||||
self.bottomPanelBackgroundColorDisposable.set(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -590,12 +639,18 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
}
|
||||
}
|
||||
|
||||
self.panel.mainButtonPressed = { [weak self] in
|
||||
self.panel.onMainButtonPressed = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.mediaPickerContext?.mainButtonAction()
|
||||
}
|
||||
}
|
||||
|
||||
self.panel.onSecondaryButtonPressed = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.mediaPickerContext?.secondaryButtonAction()
|
||||
}
|
||||
}
|
||||
|
||||
self.panel.requestLayout = { [weak self] in
|
||||
if let strongSelf = self, let layout = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
@ -628,6 +683,8 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
self.mediaSelectionCountDisposable.dispose()
|
||||
self.loadingProgressDisposable.dispose()
|
||||
self.mainButtonStateDisposable.dispose()
|
||||
self.secondaryButtonStateDisposable.dispose()
|
||||
self.bottomPanelBackgroundColorDisposable.dispose()
|
||||
}
|
||||
|
||||
private var inputContainerHeight: CGFloat?
|
||||
@ -985,10 +1042,7 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
|
||||
var containerLayout = layout
|
||||
let containerRect: CGRect
|
||||
var isCompact = true
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
isCompact = false
|
||||
|
||||
let availableHeight = layout.size.height - (layout.inputHeight ?? 0.0) - 60.0
|
||||
|
||||
let size = CGSize(width: 390.0, height: min(620.0, availableHeight))
|
||||
@ -1055,7 +1109,7 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
|
||||
var containerInsets = containerLayout.intrinsicInsets
|
||||
var hasPanel = false
|
||||
let previousHasButton = self.hasButton
|
||||
// let previousHasButton = self.hasButton
|
||||
let hasButton = self.panel.isButtonVisible && !self.isDismissing
|
||||
self.hasButton = hasButton
|
||||
if let controller = self.controller, controller.buttons.count > 1 || controller.hasTextInput {
|
||||
@ -1066,53 +1120,21 @@ public class AttachmentController: ViewController, MinimizableController {
|
||||
}
|
||||
|
||||
let isEffecitvelyCollapsedUpdated = (self.selectionCount > 0) != (self.panel.isSelecting)
|
||||
var panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isSelecting: self.selectionCount > 0, elevateProgress: !hasPanel && !hasButton, transition: transition)
|
||||
if fromMenu && !hasButton, let inputContainerHeight = self.inputContainerHeight {
|
||||
panelHeight = inputContainerHeight
|
||||
}
|
||||
let panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isSelecting: self.selectionCount > 0, elevateProgress: !hasPanel && !hasButton, transition: transition)
|
||||
if hasPanel || hasButton {
|
||||
containerInsets.bottom = panelHeight
|
||||
}
|
||||
|
||||
var transitioning = false
|
||||
if fromMenu && previousHasButton != hasButton, let (_, _, getTransition) = controller.getInputContainerNode(), let inputTransition = getTransition() {
|
||||
if hasButton {
|
||||
self.panel.animateTransitionIn(inputTransition: inputTransition, transition: transition)
|
||||
} else {
|
||||
self.panel.animateTransitionOut(inputTransition: inputTransition, dismissed: false, transition: transition)
|
||||
}
|
||||
transitioning = true
|
||||
}
|
||||
|
||||
var panelTransition = transition
|
||||
if isEffecitvelyCollapsedUpdated {
|
||||
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||
}
|
||||
var panelY = containerRect.height - panelHeight
|
||||
if fromMenu && isCompact {
|
||||
panelY = layout.size.height - panelHeight
|
||||
} else if !hasPanel && !hasButton {
|
||||
if !hasPanel && !hasButton {
|
||||
panelY = containerRect.height
|
||||
}
|
||||
|
||||
if fromMenu && isCompact {
|
||||
if hasButton {
|
||||
self.panel.isHidden = false
|
||||
self.inputContainerNode?.isHidden = true
|
||||
} else if !transitioning {
|
||||
if !self.panel.animatingTransition {
|
||||
self.panel.isHidden = true
|
||||
self.inputContainerNode?.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panelTransition.updateFrame(node: self.panel, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: containerRect.width, height: panelHeight)), completion: { [weak self] finished in
|
||||
if transitioning && finished, isCompact {
|
||||
self?.panel.isHidden = !hasButton
|
||||
self?.inputContainerNode?.isHidden = hasButton
|
||||
}
|
||||
})
|
||||
|
||||
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)
|
||||
shadowFrame.size.height -= 12.0
|
||||
|
@ -463,7 +463,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
|
||||
let diameter: CGFloat = size.height - 22.0
|
||||
let progressFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(buttonOffset + (buttonWidth - diameter) / 2.0), y: floorToScreenPixels((size.height - diameter) / 2.0)), size: CGSize(width: diameter, height: diameter))
|
||||
progressNode.frame = progressFrame
|
||||
progressNode.image = generateIndefiniteActivityIndicatorImage(color: .white, diameter: diameter, lineWidth: 3.0)
|
||||
progressNode.image = generateIndefiniteActivityIndicatorImage(color: self.state.textColor, diameter: diameter, lineWidth: 3.0)
|
||||
|
||||
self.addSubnode(progressNode)
|
||||
|
||||
@ -499,7 +499,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
|
||||
}
|
||||
|
||||
private func setupShimmering() {
|
||||
if case .premium = self.state.background {
|
||||
if self.state.hasShimmer {
|
||||
if self.shimmerView == nil {
|
||||
let shimmerView = ShimmerEffectForegroundView()
|
||||
shimmerView.isUserInteractionEnabled = false
|
||||
@ -601,7 +601,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, state: AttachmentMainButtonState, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, state: AttachmentMainButtonState, animateBackground: Bool = false, transition: ContainedViewLayoutTransition) {
|
||||
let previousState = self.state
|
||||
self.state = state
|
||||
self.size = size
|
||||
@ -621,13 +621,23 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: font, textColor: state.textColor)
|
||||
|
||||
let textSize = self.textNode.updateLayout(size)
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize)
|
||||
let textFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize)
|
||||
if self.textNode.frame.width.isZero {
|
||||
self.textNode.frame = textFrame
|
||||
} else {
|
||||
self.textNode.bounds = CGRect(origin: .zero, size: textSize)
|
||||
transition.updatePosition(node: self.textNode, position: textFrame.center)
|
||||
}
|
||||
|
||||
switch state.background {
|
||||
case let .color(backgroundColor):
|
||||
self.backgroundAnimationNode.image = nil
|
||||
self.backgroundAnimationNode.layer.removeAllAnimations()
|
||||
self.backgroundColor = backgroundColor
|
||||
if animateBackground {
|
||||
ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear).updateBackgroundColor(node: self, color: backgroundColor)
|
||||
} else {
|
||||
self.backgroundColor = backgroundColor
|
||||
}
|
||||
case .premium:
|
||||
if self.backgroundAnimationNode.image == nil {
|
||||
let backgroundColors = [
|
||||
@ -706,9 +716,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
private var textInputPanelNode: AttachmentTextInputPanelNode?
|
||||
private var progressNode: LoadingProgressNode?
|
||||
private var mainButtonNode: MainButtonNode
|
||||
private var secondaryButtonNode: MainButtonNode
|
||||
|
||||
private var loadingProgress: CGFloat?
|
||||
private var mainButtonState: AttachmentMainButtonState = .initial
|
||||
private var secondaryButtonState: AttachmentMainButtonState = .initial
|
||||
private var customBottomPanelBackgroundColor: UIColor?
|
||||
|
||||
private var elevateProgress: Bool = false
|
||||
private var buttons: [AttachmentButtonType] = []
|
||||
@ -716,7 +729,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
private(set) var isSelecting: Bool = false
|
||||
private var _isButtonVisible: Bool = false
|
||||
var isButtonVisible: Bool {
|
||||
return self.mainButtonState.isVisible
|
||||
return self.mainButtonState.isVisible || self.secondaryButtonState.isVisible
|
||||
}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
@ -737,7 +750,8 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)?
|
||||
|
||||
var mainButtonPressed: () -> Void = { }
|
||||
var onMainButtonPressed: () -> Void = { }
|
||||
var onSecondaryButtonPressed: () -> Void = { }
|
||||
|
||||
init(controller: AttachmentController, context: AccountContext, chatLocation: ChatLocation?, isScheduledMessages: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
|
||||
self.controller = controller
|
||||
@ -760,6 +774,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
self.separatorNode.backgroundColor = self.presentationData.theme.rootController.tabBar.separatorColor
|
||||
|
||||
self.mainButtonNode = MainButtonNode()
|
||||
self.secondaryButtonNode = MainButtonNode()
|
||||
|
||||
super.init()
|
||||
|
||||
@ -768,9 +783,11 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
self.containerNode.addSubnode(self.separatorNode)
|
||||
self.containerNode.addSubnode(self.scrollNode)
|
||||
|
||||
self.addSubnode(self.secondaryButtonNode)
|
||||
self.addSubnode(self.mainButtonNode)
|
||||
|
||||
self.mainButtonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
self.mainButtonNode.addTarget(self, action: #selector(self.mainButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.secondaryButtonNode.addTarget(self, action: #selector(self.secondaryButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
|
||||
}, setupEditMessage: { _, _ in
|
||||
@ -1105,7 +1122,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentationData = presentationData
|
||||
|
||||
strongSelf.backgroundNode.updateColor(color: presentationData.theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
||||
strongSelf.backgroundNode.updateColor(color: strongSelf.customBottomPanelBackgroundColor ?? presentationData.theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
||||
strongSelf.separatorNode.backgroundColor = presentationData.theme.rootController.tabBar.separatorColor
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState({ $0.updatedTheme(presentationData.theme) })
|
||||
@ -1137,8 +1154,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
self.view.accessibilityTraits = .tabBar
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
self.mainButtonPressed()
|
||||
@objc private func mainButtonPressed() {
|
||||
self.onMainButtonPressed()
|
||||
}
|
||||
|
||||
@objc private func secondaryButtonPressed() {
|
||||
self.onSecondaryButtonPressed()
|
||||
}
|
||||
|
||||
func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
@ -1372,11 +1393,24 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
func updateMainButtonState(_ mainButtonState: AttachmentMainButtonState?) {
|
||||
var currentButtonState = self.mainButtonState
|
||||
if mainButtonState == nil {
|
||||
currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, font: currentButtonState.font, background: currentButtonState.background, textColor: currentButtonState.textColor, isVisible: false, progress: .none, isEnabled: currentButtonState.isEnabled)
|
||||
currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, font: currentButtonState.font, background: currentButtonState.background, textColor: currentButtonState.textColor, isVisible: false, progress: .none, isEnabled: currentButtonState.isEnabled, hasShimmer: currentButtonState.hasShimmer)
|
||||
}
|
||||
self.mainButtonState = mainButtonState ?? currentButtonState
|
||||
}
|
||||
|
||||
func updateSecondaryButtonState(_ secondaryButtonState: AttachmentMainButtonState?) {
|
||||
var currentButtonState = self.secondaryButtonState
|
||||
if secondaryButtonState == nil {
|
||||
currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, font: currentButtonState.font, background: currentButtonState.background, textColor: currentButtonState.textColor, isVisible: false, progress: .none, isEnabled: currentButtonState.isEnabled, hasShimmer: currentButtonState.hasShimmer)
|
||||
}
|
||||
self.secondaryButtonState = secondaryButtonState ?? currentButtonState
|
||||
}
|
||||
|
||||
func updateCustomBottomPanelBackgroundColor(_ color: UIColor?) {
|
||||
self.customBottomPanelBackgroundColor = color
|
||||
self.backgroundNode.updateColor(color: self.customBottomPanelBackgroundColor ?? presentationData.theme.rootController.tabBar.backgroundColor, transition: .animated(duration: 0.2, curve: .linear))
|
||||
}
|
||||
|
||||
let animatingTransitionPromise = ValuePromise<Bool>(false)
|
||||
private(set) var animatingTransition = false {
|
||||
didSet {
|
||||
@ -1521,11 +1555,14 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
self.scrollNode.isUserInteractionEnabled = !isSelecting
|
||||
|
||||
let isButtonVisible = self.mainButtonState.isVisible
|
||||
let isNarrowButton = isButtonVisible && self.mainButtonState.font == .regular
|
||||
let isAnyButtonVisible = self.mainButtonState.isVisible || self.secondaryButtonState.isVisible
|
||||
let isNarrowButton = isAnyButtonVisible && self.mainButtonState.font == .regular
|
||||
|
||||
let isTwoVerticalButtons = self.mainButtonState.isVisible && self.secondaryButtonState.isVisible && [.top, .bottom].contains(self.secondaryButtonState.position)
|
||||
let isTwoHorizontalButtons = self.mainButtonState.isVisible && self.secondaryButtonState.isVisible && [.left, .right].contains(self.secondaryButtonState.position)
|
||||
|
||||
var insets = layout.insets(options: [])
|
||||
if let inputHeight = layout.inputHeight, inputHeight > 0.0 && (isSelecting || isButtonVisible) {
|
||||
if let inputHeight = layout.inputHeight, inputHeight > 0.0 && (isSelecting || isAnyButtonVisible) {
|
||||
insets.bottom = inputHeight
|
||||
} else if layout.intrinsicInsets.bottom > 0.0 {
|
||||
insets.bottom = layout.intrinsicInsets.bottom
|
||||
@ -1560,7 +1597,11 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: buttonSize.height + insets.bottom))
|
||||
var containerTransition: ContainedViewLayoutTransition
|
||||
let containerFrame: CGRect
|
||||
if isButtonVisible {
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
|
||||
if isAnyButtonVisible {
|
||||
var height: CGFloat
|
||||
if layout.intrinsicInsets.bottom > 0.0 && (layout.inputHeight ?? 0.0).isZero {
|
||||
height = bounds.height
|
||||
@ -1577,6 +1618,9 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
if !isNarrowButton {
|
||||
height += 9.0
|
||||
}
|
||||
if isTwoVerticalButtons {
|
||||
height += buttonHeight + sideInset
|
||||
}
|
||||
containerFrame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: height))
|
||||
} else if isSelecting {
|
||||
containerFrame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: textPanelHeight + insets.bottom))
|
||||
@ -1589,8 +1633,8 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
} else {
|
||||
containerTransition = transition
|
||||
}
|
||||
containerTransition.updateAlpha(node: self.scrollNode, alpha: isSelecting || isButtonVisible ? 0.0 : 1.0)
|
||||
containerTransition.updateTransformScale(node: self.scrollNode, scale: isSelecting || isButtonVisible ? 0.85 : 1.0)
|
||||
containerTransition.updateAlpha(node: self.scrollNode, alpha: isSelecting || isAnyButtonVisible ? 0.0 : 1.0)
|
||||
containerTransition.updateTransformScale(node: self.scrollNode, scale: isSelecting || isAnyButtonVisible ? 0.85 : 1.0)
|
||||
|
||||
if isSelectingUpdated {
|
||||
if isSelecting {
|
||||
@ -1642,16 +1686,68 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
progressNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
let buttonSize = CGSize(width: layout.size.width - (sideInset + layout.safeInsets.left) * 2.0, height: 50.0)
|
||||
let buttonTopInset: CGFloat = isNarrowButton ? 2.0 : 8.0
|
||||
|
||||
if !self.dismissed {
|
||||
self.mainButtonNode.updateLayout(size: buttonSize, state: self.mainButtonState, transition: transition)
|
||||
var buttonSize = CGSize(width: layout.size.width - (sideInset + layout.safeInsets.left) * 2.0, height: buttonHeight)
|
||||
if isTwoHorizontalButtons {
|
||||
buttonSize = CGSize(width: (buttonSize.width - sideInset) / 2.0, height: buttonSize.height)
|
||||
}
|
||||
let buttonTopInset: CGFloat = isNarrowButton ? 2.0 : 8.0
|
||||
|
||||
if !self.animatingTransition {
|
||||
transition.updateFrame(node: self.mainButtonNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + sideInset, y: isButtonVisible || self.fromMenu ? buttonTopInset : containerFrame.height), size: buttonSize))
|
||||
let buttonOriginX = layout.safeInsets.left + sideInset
|
||||
let buttonOriginY = isAnyButtonVisible || self.fromMenu ? buttonTopInset : containerFrame.height
|
||||
var mainButtonFrame: CGRect?
|
||||
var secondaryButtonFrame: CGRect?
|
||||
if self.secondaryButtonState.isVisible && self.mainButtonState.isVisible, let position = self.secondaryButtonState.position {
|
||||
switch position {
|
||||
case .top:
|
||||
secondaryButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY), size: buttonSize)
|
||||
mainButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY + sideInset + buttonSize.height), size: buttonSize)
|
||||
case .bottom:
|
||||
mainButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY), size: buttonSize)
|
||||
secondaryButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY + sideInset + buttonSize.height), size: buttonSize)
|
||||
case .left:
|
||||
secondaryButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY), size: buttonSize)
|
||||
mainButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX + buttonSize.width + sideInset, y: buttonOriginY), size: buttonSize)
|
||||
case .right:
|
||||
mainButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY), size: buttonSize)
|
||||
secondaryButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX + buttonSize.width + sideInset, y: buttonOriginY), size: buttonSize)
|
||||
}
|
||||
} else {
|
||||
if self.mainButtonState.isVisible {
|
||||
mainButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY), size: buttonSize)
|
||||
}
|
||||
if self.secondaryButtonState.isVisible {
|
||||
secondaryButtonFrame = CGRect(origin: CGPoint(x: buttonOriginX, y: buttonOriginY), size: buttonSize)
|
||||
}
|
||||
}
|
||||
|
||||
if let mainButtonFrame {
|
||||
if !self.dismissed {
|
||||
self.mainButtonNode.updateLayout(size: buttonSize, state: self.mainButtonState, animateBackground: self.mainButtonState.background.colorValue == self.backgroundNode.color && transition.isAnimated, transition: transition)
|
||||
}
|
||||
if self.mainButtonNode.frame.width.isZero {
|
||||
self.mainButtonNode.frame = mainButtonFrame
|
||||
} else {
|
||||
transition.updateFrame(node: self.mainButtonNode, frame: mainButtonFrame)
|
||||
}
|
||||
transition.updateAlpha(node: self.mainButtonNode, alpha: 1.0)
|
||||
} else {
|
||||
transition.updateAlpha(node: self.mainButtonNode, alpha: 0.0)
|
||||
}
|
||||
if let secondaryButtonFrame {
|
||||
if !self.dismissed {
|
||||
self.secondaryButtonNode.updateLayout(size: buttonSize, state: self.secondaryButtonState, animateBackground: self.secondaryButtonState.background.colorValue == self.backgroundNode.color && transition.isAnimated, transition: transition)
|
||||
}
|
||||
if self.secondaryButtonNode.frame.width.isZero {
|
||||
self.secondaryButtonNode.frame = secondaryButtonFrame
|
||||
} else {
|
||||
transition.updateFrame(node: self.secondaryButtonNode, frame: secondaryButtonFrame)
|
||||
}
|
||||
transition.updateAlpha(node: self.secondaryButtonNode, alpha: 1.0)
|
||||
} else {
|
||||
transition.updateAlpha(node: self.secondaryButtonNode, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
return containerFrame.height
|
||||
|
@ -140,6 +140,10 @@ private var sharedIsReduceTransparencyEnabled = UIAccessibility.isReduceTranspar
|
||||
public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
private var _color: UIColor
|
||||
|
||||
public var color: UIColor {
|
||||
return self._color
|
||||
}
|
||||
|
||||
private var enableBlur: Bool
|
||||
private var enableSaturation: Bool
|
||||
|
||||
|
@ -2949,7 +2949,7 @@ public func wallpaperMediaPickerController(
|
||||
controller.animateAppearance = animateAppearance
|
||||
controller.requestController = { [weak controller] _, present in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let mediaPickerController = MediaPickerScreen(context: context, updatedPresentationData: updatedPresentationData, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_SetColorWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true), mainButtonAction: {
|
||||
let mediaPickerController = MediaPickerScreen(context: context, updatedPresentationData: updatedPresentationData, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_SetColorWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false), mainButtonAction: {
|
||||
controller?.dismiss(animated: true)
|
||||
openColors()
|
||||
})
|
||||
|
@ -879,7 +879,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
||||
price = nil
|
||||
}
|
||||
let buttonText = presentationData.strings.Premium_Gift_GiftSubscription(price ?? "—").string
|
||||
self.buttonStatePromise.set(.single(AttachmentMainButtonState(text: buttonText, font: .bold, background: .premium, textColor: .white, isVisible: true, progress: self.inProgress ? .center : .none, isEnabled: true, hasShimmer: false)))
|
||||
self.buttonStatePromise.set(.single(AttachmentMainButtonState(text: buttonText, font: .bold, background: .premium, textColor: .white, isVisible: true, progress: self.inProgress ? .center : .none, isEnabled: true, hasShimmer: true)))
|
||||
}
|
||||
|
||||
func buy() {
|
||||
|
@ -194,7 +194,7 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
|
||||
self?.push(controller)
|
||||
}
|
||||
|
||||
self.mainButtonState = AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true)
|
||||
self.mainButtonState = AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false)
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
|
@ -645,8 +645,8 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
|
||||
if let giveawayMessageId {
|
||||
tableItems.append(.init(
|
||||
id: "gift",
|
||||
title: "Gift",
|
||||
id: "prize",
|
||||
title: "Prize",
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: "\(count) Stars", font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
|
@ -104,6 +104,7 @@ public func generateWebAppThemeParams(_ theme: PresentationTheme) -> [String: An
|
||||
"button_color": Int32(bitPattern: theme.list.itemCheckColors.fillColor.rgb),
|
||||
"button_text_color": Int32(bitPattern: theme.list.itemCheckColors.foregroundColor.rgb),
|
||||
"header_bg_color": Int32(bitPattern: theme.rootController.navigationBar.opaqueBackgroundColor.rgb),
|
||||
"bottom_bar_bg_color": Int32(bitPattern: theme.rootController.tabBar.backgroundColor.rgb),
|
||||
"accent_text_color": Int32(bitPattern: theme.list.itemAccentColor.rgb),
|
||||
"section_bg_color": Int32(bitPattern: theme.list.itemBlocksBackgroundColor.rgb),
|
||||
"section_header_text_color": Int32(bitPattern: theme.list.freeTextColor.rgb),
|
||||
@ -145,6 +146,13 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
fileprivate let mainButtonStatePromise = Promise<AttachmentMainButtonState?>(nil)
|
||||
|
||||
fileprivate var secondaryButtonState: AttachmentMainButtonState? {
|
||||
didSet {
|
||||
self.secondaryButtonStatePromise.set(.single(self.secondaryButtonState))
|
||||
}
|
||||
}
|
||||
fileprivate let secondaryButtonStatePromise = Promise<AttachmentMainButtonState?>(nil)
|
||||
|
||||
private let context: AccountContext
|
||||
var presentationData: PresentationData
|
||||
private var queryId: Int64?
|
||||
@ -192,9 +200,12 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
self?.handleScriptMessage(message)
|
||||
}
|
||||
webView.onFirstTouch = { [weak self] in
|
||||
if let strongSelf = self, let delayedScriptMessage = strongSelf.delayedScriptMessage {
|
||||
strongSelf.delayedScriptMessage = nil
|
||||
strongSelf.handleScriptMessage(delayedScriptMessage)
|
||||
if let self, !self.delayedScriptMessages.isEmpty {
|
||||
let delayedScriptMessages = self.delayedScriptMessages
|
||||
self.delayedScriptMessages.removeAll()
|
||||
for message in delayedScriptMessages {
|
||||
self.handleScriptMessage(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
if #available(iOS 13.0, *) {
|
||||
@ -414,6 +425,14 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
self.webView?.sendEvent(name: "main_button_pressed", data: nil)
|
||||
}
|
||||
|
||||
@objc fileprivate func secondaryButtonPressed() {
|
||||
if let secondaryButtonState = self.secondaryButtonState, !secondaryButtonState.isVisible || !secondaryButtonState.isEnabled {
|
||||
return
|
||||
}
|
||||
self.webView?.lastTouchTimestamp = CACurrentMediaTime()
|
||||
self.webView?.sendEvent(name: "secondary_button_pressed", data: nil)
|
||||
}
|
||||
|
||||
private func updatePlaceholder(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var shapes: [ShimmerEffect.ShimmerEffectNode.Shape] = []
|
||||
var placeholderSize: CGSize = CGSize()
|
||||
@ -656,7 +675,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
|
||||
private weak var currentQrCodeScannerScreen: QrCodeScanScreen?
|
||||
|
||||
private var delayedScriptMessage: WKScriptMessage?
|
||||
private var delayedScriptMessages: [WKScriptMessage] = []
|
||||
private func handleScriptMessage(_ message: WKScriptMessage) {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
@ -706,7 +725,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
case "web_app_setup_main_button":
|
||||
if let webView = self.webView, !webView.didTouchOnce && controller.url == nil && controller.source == .attachMenu {
|
||||
self.delayedScriptMessage = message
|
||||
self.delayedScriptMessages.append(message)
|
||||
} else if let json = json {
|
||||
if var isVisible = json["is_visible"] as? Bool {
|
||||
let text = json["text"] as? String
|
||||
@ -721,10 +740,35 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
|
||||
let isLoading = json["is_progress_visible"] as? Bool
|
||||
let isEnabled = json["is_active"] as? Bool
|
||||
let state = AttachmentMainButtonState(text: text, font: .bold, background: .color(backgroundColor), textColor: textColor, isVisible: isVisible, progress: (isLoading ?? false) ? .side : .none, isEnabled: isEnabled ?? true)
|
||||
let hasShimmer = json["has_shine_effect"] as? Bool
|
||||
let state = AttachmentMainButtonState(text: text, font: .bold, background: .color(backgroundColor), textColor: textColor, isVisible: isVisible, progress: (isLoading ?? false) ? .center : .none, isEnabled: isEnabled ?? true, hasShimmer: hasShimmer ?? false)
|
||||
self.mainButtonState = state
|
||||
}
|
||||
}
|
||||
case "web_app_setup_secondary_button":
|
||||
if let webView = self.webView, !webView.didTouchOnce && controller.url == nil && controller.source == .attachMenu {
|
||||
self.delayedScriptMessages.append(message)
|
||||
} else if let json = json {
|
||||
if var isVisible = json["is_visible"] as? Bool {
|
||||
let text = json["text"] as? String
|
||||
if (text ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
let backgroundColorString = json["color"] as? String
|
||||
let backgroundColor = backgroundColorString.flatMap({ UIColor(hexString: $0) }) ?? self.presentationData.theme.list.itemCheckColors.fillColor
|
||||
let textColorString = json["text_color"] as? String
|
||||
let textColor = textColorString.flatMap({ UIColor(hexString: $0) }) ?? self.presentationData.theme.list.itemCheckColors.foregroundColor
|
||||
|
||||
let isLoading = json["is_progress_visible"] as? Bool
|
||||
let isEnabled = json["is_active"] as? Bool
|
||||
let hasShimmer = json["has_shine_effect"] as? Bool
|
||||
let position = json["position"] as? String
|
||||
|
||||
let state = AttachmentMainButtonState(text: text, font: .bold, background: .color(backgroundColor), textColor: textColor, isVisible: isVisible, progress: (isLoading ?? false) ? .center : .none, isEnabled: isEnabled ?? true, hasShimmer: hasShimmer ?? false, position: position.flatMap { AttachmentMainButtonState.Position(rawValue: $0) })
|
||||
self.secondaryButtonState = state
|
||||
}
|
||||
}
|
||||
case "web_app_request_viewport":
|
||||
if let (layout, navigationBarHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
@ -935,6 +979,12 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
self.updateHeaderBackgroundColor(transition: .animated(duration: 0.2, curve: .linear))
|
||||
}
|
||||
case "web_app_set_bottom_bar_color":
|
||||
if let json = json {
|
||||
if let hexColor = json["color"] as? String, let color = UIColor(hexString: hexColor) {
|
||||
self.bottomPanelColor = color
|
||||
}
|
||||
}
|
||||
case "web_app_open_popup":
|
||||
if let json = json, let message = json["message"] as? String, let buttons = json["buttons"] as? [Any] {
|
||||
let presentationData = self.presentationData
|
||||
@ -1172,11 +1222,18 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
fileprivate var needDismissConfirmation = false
|
||||
|
||||
|
||||
fileprivate var headerColor: UIColor?
|
||||
fileprivate var headerPrimaryTextColor: UIColor?
|
||||
private var headerColorKey: String?
|
||||
|
||||
fileprivate var bottomPanelColor: UIColor? {
|
||||
didSet {
|
||||
self.bottomPanelColorPromise.set(.single(self.bottomPanelColor))
|
||||
}
|
||||
}
|
||||
fileprivate let bottomPanelColorPromise = Promise<UIColor?>(nil)
|
||||
|
||||
private func updateHeaderBackgroundColor(transition: ContainedViewLayoutTransition) {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
@ -2253,7 +2310,15 @@ final class WebAppPickerContext: AttachmentMediaPickerContext {
|
||||
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||
return self.controller?.controllerNode.mainButtonStatePromise.get() ?? .single(nil)
|
||||
}
|
||||
|
||||
public var secondaryButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||
return self.controller?.controllerNode.secondaryButtonStatePromise.get() ?? .single(nil)
|
||||
}
|
||||
|
||||
public var bottomPanelBackgroundColor: Signal<UIColor?, NoError> {
|
||||
return self.controller?.controllerNode.bottomPanelColorPromise.get() ?? .single(nil)
|
||||
}
|
||||
|
||||
init(controller: WebAppController) {
|
||||
self.controller = controller
|
||||
}
|
||||
@ -2261,6 +2326,10 @@ final class WebAppPickerContext: AttachmentMediaPickerContext {
|
||||
func mainButtonAction() {
|
||||
self.controller?.controllerNode.mainButtonPressed()
|
||||
}
|
||||
|
||||
func secondaryButtonAction() {
|
||||
self.controller?.controllerNode.secondaryButtonPressed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user