Merge commit '76aacfc03eca5bcd74ba31aca25b5b4ff3c1f86c'

# Conflicts:
#	Telegram/Telegram-iOS/en.lproj/Localizable.strings
This commit is contained in:
Ali 2023-03-20 16:35:01 +04:00
commit fbba4f9f94
23 changed files with 228 additions and 128 deletions

View File

@ -9084,3 +9084,9 @@ Sorry for the inconvenience.";
"Conversation.SendMessageErrorTooFastTitle" = "Not so fast"; "Conversation.SendMessageErrorTooFastTitle" = "Not so fast";
"Conversation.SendMessageErrorTooFast" = "You are sending messages too fast. Please wait a bit."; "Conversation.SendMessageErrorTooFast" = "You are sending messages too fast. Please wait a bit.";
"PeerInfo.CancelSelectionAlertText" = "Cancel selection?";
"PeerInfo.CancelSelectionAlertYes" = "Yes";
"PeerInfo.CancelSelectionAlertNo" = "No";
"StickerPacksSettings.SuggestAnimatedEmojiInfo" = "Each time you enter an emoji you can replace it with an animated emoji.";

View File

@ -115,7 +115,7 @@ final class BotCheckoutNativeCardEntryControllerNode: ViewControllerTracingNode,
sectionItems.append(BotPaymentHeaderItemNode(text: strings.Checkout_NewCard_CardholderNameTitle)) sectionItems.append(BotPaymentHeaderItemNode(text: strings.Checkout_NewCard_CardholderNameTitle))
let cardholderItem = BotPaymentFieldItemNode(title: "", placeholder: strings.Checkout_NewCard_CardholderNamePlaceholder, contentType: .name) let cardholderItem = BotPaymentFieldItemNode(title: "", placeholder: strings.Checkout_NewCard_CardholderNamePlaceholder, contentType: .asciiName)
self.cardholderItem = cardholderItem self.cardholderItem = cardholderItem
sectionItems.append(cardholderItem) sectionItems.append(cardholderItem)

View File

@ -9,6 +9,7 @@ private let titleFont = Font.regular(17.0)
enum BotPaymentFieldContentType { enum BotPaymentFieldContentType {
case generic case generic
case name case name
case asciiName
case phoneNumber case phoneNumber
case email case email
case address case address
@ -51,6 +52,9 @@ final class BotPaymentFieldItemNode: BotPaymentItemNode, UITextFieldDelegate {
case .generic: case .generic:
break break
case .name: case .name:
self.textField.textField.autocorrectionType = .no
self.textField.textField.keyboardType = .default
case .asciiName:
self.textField.textField.autocorrectionType = .no self.textField.textField.autocorrectionType = .no
self.textField.textField.keyboardType = .asciiCapable self.textField.textField.keyboardType = .asciiCapable
case .address: case .address:

View File

@ -2561,10 +2561,6 @@ public final class ChatListNode: ListView {
return strongSelf.isSelectionGestureEnabled return strongSelf.isSelectionGestureEnabled
} }
self.view.addGestureRecognizer(selectionRecognizer) self.view.addGestureRecognizer(selectionRecognizer)
// if case .forum = location {
// self.isSelectionGestureEnabled = false
// }
} }
deinit { deinit {

View File

@ -139,6 +139,11 @@ open class ViewControllerComponentContainer: ViewController {
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: Transition) { func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: Transition) {
self.currentLayout = (layout, navigationHeight) self.currentLayout = (layout, navigationHeight)
var theme = self.theme ?? self.presentationData.theme
if theme.list.blocksBackgroundColor.rgb == theme.list.plainBackgroundColor.rgb {
theme = theme.withModalBlocksBackground()
}
let environment = ViewControllerComponentContainer.Environment( let environment = ViewControllerComponentContainer.Environment(
statusBarHeight: layout.statusBarHeight ?? 0.0, statusBarHeight: layout.statusBarHeight ?? 0.0,
navigationHeight: navigationHeight, navigationHeight: navigationHeight,
@ -147,7 +152,7 @@ open class ViewControllerComponentContainer: ViewController {
metrics: layout.metrics, metrics: layout.metrics,
deviceMetrics: layout.deviceMetrics, deviceMetrics: layout.deviceMetrics,
isVisible: self.currentIsVisible, isVisible: self.currentIsVisible,
theme: self.theme ?? self.presentationData.theme, theme: theme,
strings: self.presentationData.strings, strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat, dateTimeFormat: self.presentationData.dateTimeFormat,
controller: { [weak self] in controller: { [weak self] in

View File

@ -359,30 +359,36 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.itemsDimensionsUpdatedDisposable?.dispose() self.itemsDimensionsUpdatedDisposable?.dispose()
} }
private var selectionGesture: MediaPickerGridSelectionGesture? private var selectionGesture: MediaPickerGridSelectionGesture<TGMediaSelectableItem>?
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
self.gridNode.scrollView.alwaysBounceVertical = true self.gridNode.scrollView.alwaysBounceVertical = true
self.gridNode.scrollView.showsVerticalScrollIndicator = false self.gridNode.scrollView.showsVerticalScrollIndicator = false
self.selectionGesture = MediaPickerGridSelectionGesture(target: nil, action: nil, gridNode: self.gridNode) let selectionGesture = MediaPickerGridSelectionGesture<TGMediaSelectableItem>()
self.selectionGesture?.delegate = self selectionGesture.delegate = self
self.selectionGesture?.began = { [weak self] in selectionGesture.began = { [weak self] in
self?.controller?.cancelPanGesture() self?.controller?.cancelPanGesture()
} }
self.selectionGesture?.itemAt = { [weak self] point in selectionGesture.updateIsScrollEnabled = { [weak self] isEnabled in
self?.gridNode.scrollView.isScrollEnabled = isEnabled
}
selectionGesture.itemAt = { [weak self] point in
if let strongSelf = self, let itemNode = strongSelf.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let selectableItem = itemNode.selectableItem { if let strongSelf = self, let itemNode = strongSelf.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let selectableItem = itemNode.selectableItem {
return (selectableItem, strongSelf.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false) return (selectableItem, strongSelf.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false)
} else { } else {
return nil return nil
} }
} }
self.selectionGesture?.updateSelection = { [weak self] asset, selected in selectionGesture.updateSelection = { [weak self] asset, selected in
if let strongSelf = self { if let strongSelf = self {
strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil) strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil)
} }
} }
selectionGesture.sideInset = 44.0
self.gridNode.view.addGestureRecognizer(selectionGesture)
self.selectionGesture = selectionGesture
if let controller = self.controller, case let .assets(collection) = controller.subject, collection != nil { if let controller = self.controller, case let .assets(collection) = controller.subject, collection != nil {
self.gridNode.view.interactiveTransitionGestureRecognizerTest = { point -> Bool in self.gridNode.view.interactiveTransitionGestureRecognizerTest = { point -> Bool in
@ -1546,7 +1552,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
} }
let controller = textAlertController(context: self.context, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertNo, action: { let controller = textAlertController(context: self.context, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertNo, action: {
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertYes, action: { [weak self] in }), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertYes, action: { [weak self] in
self?.dismissAllTooltips() self?.dismissAllTooltips()
completion() completion()
@ -1794,37 +1799,31 @@ private final class MediaPickerContextReferenceContentSource: ContextReferenceCo
} }
} }
private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer { public class MediaPickerGridSelectionGesture<T> : UIPanGestureRecognizer {
var itemAt: (CGPoint) -> (TGMediaSelectableItem, Bool)? = { _ in return nil } public var itemAt: (CGPoint) -> (T, Bool)? = { _ in return nil }
var updateSelection: (TGMediaSelectableItem, Bool) -> Void = { _, _ in} public var updateSelection: (T, Bool) -> Void = { _, _ in}
var began: () -> Void = {} public var updateIsScrollEnabled: (Bool) -> Void = { _ in}
public var began: () -> Void = {}
private weak var gridNode: GridNode?
private var processing = false private var processing = false
private var selecting = false private var selecting = false
private var initialLocation: CGPoint? private var initialLocation: CGPoint?
var sideInset: CGFloat = 0.0 public var sideInset: CGFloat = 0.0
init(target: Any?, action: Selector?, gridNode: GridNode) { public init() {
self.gridNode = gridNode super.init(target: nil, action: nil)
super.init(target: target, action: action)
gridNode.view.addGestureRecognizer(self)
} }
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) { public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
guard let touch = touches.first, self.numberOfTouches == 1, let gridNode = self.gridNode else { guard let touch = touches.first, self.numberOfTouches == 1 else {
return return
} }
let location = touch.location(in: gridNode.view) let location = touch.location(in: self.view)
if location.x > self.sideInset { if location.x > self.sideInset {
self.initialLocation = location self.initialLocation = location
} else { } else {
@ -1832,15 +1831,15 @@ private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
} }
} }
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) { public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event) super.touchesMoved(touches, with: event)
guard let touch = touches.first, let gridNode = self.gridNode, let initialLocation = self.initialLocation else { guard let touch = touches.first, let initialLocation = self.initialLocation else {
self.state = .failed self.state = .failed
return return
} }
let location = touch.location(in: gridNode.view) let location = touch.location(in: self.view)
let translation = CGPoint(x: location.x - initialLocation.x, y: location.y - initialLocation.y) let translation = CGPoint(x: location.x - initialLocation.x, y: location.y - initialLocation.y)
var additionalLocation: CGPoint? var additionalLocation: CGPoint?
@ -1849,7 +1848,7 @@ private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
self.state = .failed self.state = .failed
} else if abs(translation.x) > 8.0 { } else if abs(translation.x) > 8.0 {
self.processing = true self.processing = true
self.gridNode?.scrollView.isScrollEnabled = false self.updateIsScrollEnabled(false)
self.began() self.began()
if let (_, selected) = self.itemAt(location) { if let (_, selected) = self.itemAt(location) {
@ -1873,25 +1872,25 @@ private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
} }
} }
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) { public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
self.state = .failed self.state = .failed
self.reset() self.reset()
} }
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) { public override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
self.state = .failed self.state = .failed
self.reset() self.reset()
} }
override func reset() { public override func reset() {
super.reset() super.reset()
self.processing = false self.processing = false
self.initialLocation = nil self.initialLocation = nil
self.gridNode?.scrollView.isScrollEnabled = true self.updateIsScrollEnabled(true)
} }
} }

View File

@ -593,7 +593,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
strongSelf.wallpaperBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { _ in strongSelf.wallpaperBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { _ in
completion() completion()
}) })
strongSelf.wallpaperBackgroundNode.layer.animateScale(from: 1.2, to: 1.0, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring) strongSelf.wallpaperBackgroundNode.layer.animateScale(from: 1.2, to: 1.0, duration: 0.33, timingFunction: kCAMediaTimingFunctionSpring)
for (_, backgroundNode) in strongSelf.backgroundNodes { for (_, backgroundNode) in strongSelf.backgroundNodes {
backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1) backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
@ -641,7 +641,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
} }
}) })
self.wallpaperBackgroundNode.layer.animateScale(from: 1.0, to: 1.2, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring) self.wallpaperBackgroundNode.layer.animateScale(from: 1.0, to: 1.2, duration: 0.33, timingFunction: kCAMediaTimingFunctionSpring)
for (_, backgroundNode) in self.backgroundNodes { for (_, backgroundNode) in self.backgroundNodes {
backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false) backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false)

View File

@ -167,7 +167,6 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
static var body: Body { static var body: Body {
let overscroll = Child(Rectangle.self) let overscroll = Child(Rectangle.self)
let fade = Child(RoundedRectangle.self)
let text = Child(MultilineTextComponent.self) let text = Child(MultilineTextComponent.self)
let optionsSection = Child(SectionGroupComponent.self) let optionsSection = Child(SectionGroupComponent.self)
let perksSection = Child(SectionGroupComponent.self) let perksSection = Child(SectionGroupComponent.self)
@ -196,22 +195,6 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
.position(CGPoint(x: overscroll.size.width / 2.0, y: -overscroll.size.height / 2.0)) .position(CGPoint(x: overscroll.size.width / 2.0, y: -overscroll.size.height / 2.0))
) )
let fade = fade.update(
component: RoundedRectangle(
colors: [
theme.list.plainBackgroundColor,
theme.list.blocksBackgroundColor
],
cornerRadius: 0.0,
gradientDirection: .vertical
),
availableSize: CGSize(width: availableWidth, height: 300),
transition: context.transition
)
context.add(fade
.position(CGPoint(x: fade.size.width / 2.0, y: fade.size.height / 2.0))
)
size.height += 183.0 + 10.0 + environment.navigationHeight - 56.0 size.height += 183.0 + 10.0 + environment.navigationHeight - 56.0
let textColor = theme.list.itemPrimaryTextColor let textColor = theme.list.itemPrimaryTextColor

View File

@ -45,13 +45,14 @@ public class ItemListReactionItem: ListViewItem, ItemListItem {
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
async { async {
Queue.mainQueue().async {
let node = ItemListReactionItemNode() let node = ItemListReactionItemNode()
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
node.contentSize = layout.contentSize node.contentSize = layout.contentSize
node.insets = layout.insets node.insets = layout.insets
Queue.mainQueue().async {
completion(node, { completion(node, {
return (nil, { _ in apply() }) return (nil, { _ in apply() })
}) })

View File

@ -92,6 +92,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
case packOrder(PresentationTheme, String, Bool) case packOrder(PresentationTheme, String, Bool)
case packOrderInfo(PresentationTheme, String) case packOrderInfo(PresentationTheme, String)
case suggestAnimatedEmoji(String, Bool) case suggestAnimatedEmoji(String, Bool)
case suggestAnimatedEmojiInfo(PresentationTheme, String)
case packsTitle(PresentationTheme, String) case packsTitle(PresentationTheme, String)
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing, Bool?) case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing, Bool?)
case packsInfo(PresentationTheme, String) case packsInfo(PresentationTheme, String)
@ -100,7 +101,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
switch self { switch self {
case .trending, .masks, .emoji, .quickReaction, .archived: case .trending, .masks, .emoji, .quickReaction, .archived:
return InstalledStickerPacksSection.categories.rawValue return InstalledStickerPacksSection.categories.rawValue
case .suggestOptions, .largeEmoji, .suggestAnimatedEmoji, .packOrder, .packOrderInfo: case .suggestOptions, .largeEmoji, .suggestAnimatedEmoji, .suggestAnimatedEmojiInfo, .packOrder, .packOrderInfo:
return InstalledStickerPacksSection.settings.rawValue return InstalledStickerPacksSection.settings.rawValue
case .packsTitle, .pack, .packsInfo: case .packsTitle, .pack, .packsInfo:
return InstalledStickerPacksSection.stickers.rawValue return InstalledStickerPacksSection.stickers.rawValue
@ -125,16 +126,18 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
return .index(6) return .index(6)
case .suggestAnimatedEmoji: case .suggestAnimatedEmoji:
return .index(7) return .index(7)
case .packOrder: case .suggestAnimatedEmojiInfo:
return .index(8) return .index(8)
case .packOrderInfo: case .packOrder:
return .index(9) return .index(9)
case .packsTitle: case .packOrderInfo:
return .index(10) return .index(10)
case .packsTitle:
return .index(11)
case let .pack(_, _, _, info, _, _, _, _, _, _): case let .pack(_, _, _, info, _, _, _, _, _, _):
return .pack(info.id) return .pack(info.id)
case .packsInfo: case .packsInfo:
return .index(11) return .index(12)
} }
} }
@ -200,6 +203,12 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .suggestAnimatedEmojiInfo(lhsTheme, lhsText):
if case let .suggestAnimatedEmojiInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .packsTitle(lhsTheme, lhsText): case let .packsTitle(lhsTheme, lhsText):
if case let .packsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .packsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
@ -323,9 +332,16 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
default: default:
return true return true
} }
case .suggestAnimatedEmojiInfo:
switch rhs {
case .trending, .archived, .masks, .emoji, .quickReaction, .suggestOptions, .largeEmoji, .packOrder, .packOrderInfo, .suggestAnimatedEmoji, .suggestAnimatedEmojiInfo:
return false
default:
return true
}
case .packsTitle: case .packsTitle:
switch rhs { switch rhs {
case .trending, .archived, .masks, .emoji, .quickReaction, .suggestOptions, .largeEmoji, .packOrder, .packOrderInfo, .suggestAnimatedEmoji, .packsTitle: case .trending, .archived, .masks, .emoji, .quickReaction, .suggestOptions, .largeEmoji, .packOrder, .packOrderInfo, .suggestAnimatedEmoji, .suggestAnimatedEmojiInfo, .packsTitle:
return false return false
default: default:
return true return true
@ -390,6 +406,8 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.toggleSuggestAnimatedEmoji(value) arguments.toggleSuggestAnimatedEmoji(value)
}) })
case let .suggestAnimatedEmojiInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .packsTitle(_, text): case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected): case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected):
@ -531,6 +549,7 @@ private func installedStickerPacksControllerEntries(context: AccountContext, pre
} }
entries.append(.suggestAnimatedEmoji(presentationData.strings.StickerPacksSettings_SuggestAnimatedEmoji, stickerSettings.suggestAnimatedEmoji)) entries.append(.suggestAnimatedEmoji(presentationData.strings.StickerPacksSettings_SuggestAnimatedEmoji, stickerSettings.suggestAnimatedEmoji))
entries.append(.suggestAnimatedEmojiInfo(presentationData.theme, presentationData.strings.StickerPacksSettings_SuggestAnimatedEmojiInfo))
} }
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [namespaceForMode(mode)])] as? ItemCollectionInfosView { if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [namespaceForMode(mode)])] as? ItemCollectionInfosView {

View File

@ -711,7 +711,6 @@ class ThemeCarouselThemeItemNode: ListViewItemNode, ItemListItemNode {
strongSelf.item = item strongSelf.item = item
strongSelf.layoutParams = params strongSelf.layoutParams = params
strongSelf.listNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
@ -828,10 +827,11 @@ class ThemeCarouselThemeItemNode: ListViewItemNode, ItemListItemNode {
self.snapshotView = snapshotView self.snapshotView = snapshotView
} }
self.listNode.forEachVisibleItemNode { node in self.listNode.enumerateItemNodes { node in
if let node = node as? ThemeCarouselThemeItemIconNode { if let node = node as? ThemeCarouselThemeItemIconNode {
node.prepareCrossfadeTransition() node.prepareCrossfadeTransition()
} }
return true
} }
} }
@ -846,13 +846,14 @@ class ThemeCarouselThemeItemNode: ListViewItemNode, ItemListItemNode {
self.snapshotView = nil self.snapshotView = nil
} }
self.listNode.forEachVisibleItemNode { node in self.listNode.enumerateItemNodes { node in
if let node = node as? ThemeCarouselThemeItemIconNode { if let node = node as? ThemeCarouselThemeItemIconNode {
if let snapshotView = node.snapshotView { if let snapshotView = node.snapshotView {
views.append(snapshotView) views.append(snapshotView)
node.snapshotView = nil node.snapshotView = nil
} }
} }
return true
} }
UIView.animate(withDuration: 0.3, animations: { UIView.animate(withDuration: 0.3, animations: {

View File

@ -1292,9 +1292,7 @@ public final class ThemeSettingsCrossfadeController: ViewController {
public init(view: UIView? = nil, topOffset: CGFloat? = nil, bottomOffset: CGFloat? = nil, leftOffset: CGFloat? = nil, sideInset: CGFloat = 0.0) { public init(view: UIView? = nil, topOffset: CGFloat? = nil, bottomOffset: CGFloat? = nil, leftOffset: CGFloat? = nil, sideInset: CGFloat = 0.0) {
if let view = view { if let view = view {
if var leftOffset = leftOffset { if let leftOffset = leftOffset {
leftOffset += UIScreenPixel
if let view = view.snapshotView(afterScreenUpdates: false) { if let view = view.snapshotView(afterScreenUpdates: false) {
let clipView = UIView() let clipView = UIView()
clipView.clipsToBounds = true clipView.clipsToBounds = true
@ -1306,13 +1304,13 @@ public final class ThemeSettingsCrossfadeController: ViewController {
if let topOffset = topOffset, let bottomOffset = bottomOffset { if let topOffset = topOffset, let bottomOffset = bottomOffset {
var frame = view.frame var frame = view.frame
frame.origin.y = topOffset frame.origin.y = topOffset
frame.size.width = leftOffset frame.size.width = leftOffset + sideInset
frame.size.height = bottomOffset - topOffset frame.size.height = bottomOffset - topOffset
clipView.frame = frame clipView.frame = frame
frame = view.frame frame = view.frame
frame.origin.y = -topOffset frame.origin.y = -topOffset
frame.size.width = leftOffset frame.size.width = leftOffset + sideInset
frame.size.height = bottomOffset frame.size.height = bottomOffset
view.frame = frame view.frame = frame
} }
@ -1322,7 +1320,7 @@ public final class ThemeSettingsCrossfadeController: ViewController {
} }
if sideInset > 0.0 { if sideInset > 0.0 {
if let view = view.snapshotView(afterScreenUpdates: false) { if let view = view.snapshotView(afterScreenUpdates: false), leftOffset == nil {
let clipView = UIView() let clipView = UIView()
clipView.clipsToBounds = true clipView.clipsToBounds = true
clipView.addSubview(view) clipView.addSubview(view)

View File

@ -1345,6 +1345,12 @@ public final class SparseItemGrid: ASDisplayNode {
} }
} }
public var isScrollEnabled: Bool = true {
didSet {
self.currentViewport?.scrollView.isScrollEnabled = self.isScrollEnabled
}
}
public init(theme: PresentationTheme, initialZoomLevel: ZoomLevel? = nil) { public init(theme: PresentationTheme, initialZoomLevel: ZoomLevel? = nil) {
self.theme = theme self.theme = theme
self.initialZoomLevel = initialZoomLevel self.initialZoomLevel = initialZoomLevel

View File

@ -10,7 +10,7 @@ func _internal_requestStartBot(account: Account, botPeerId: PeerId, payload: Str
return account.postbox.loadedPeerWithId(botPeerId) return account.postbox.loadedPeerWithId(botPeerId)
|> mapToSignal { botPeer -> Signal<Void, NoError> in |> mapToSignal { botPeer -> Signal<Void, NoError> in
if let inputUser = apiInputUser(botPeer) { if let inputUser = apiInputUser(botPeer) {
let r = account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: .inputPeerEmpty, randomId: Int64.random(in: Int64.min ... Int64.max), startParam: payload)) return account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: .inputPeerEmpty, randomId: Int64.random(in: Int64.min ... Int64.max), startParam: payload))
|> mapToSignal { result -> Signal<Void, MTRpcError> in |> mapToSignal { result -> Signal<Void, MTRpcError> in
account.stateManager.addUpdates(result) account.stateManager.addUpdates(result)
return .complete() return .complete()
@ -18,7 +18,6 @@ func _internal_requestStartBot(account: Account, botPeerId: PeerId, payload: Str
|> `catch` { _ -> Signal<Void, MTRpcError> in |> `catch` { _ -> Signal<Void, MTRpcError> in
return .complete() return .complete()
} }
return r
|> retryRequest |> retryRequest
} else { } else {
return .complete() return .complete()

View File

@ -4104,7 +4104,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true) return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
} }
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, isInline: false, isSimple: false) let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, fromAttachMenu: false, isInline: false, isSimple: false)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true) self?.openUrl(url, concealed: true, forceExternal: true)
}, getInputContainerNode: { [weak self] in }, getInputContainerNode: { [weak self] in
@ -4159,7 +4159,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let params = WebAppParameters(peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, isInline: isInline, isSimple: true) let params = WebAppParameters(peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: isInline, isSimple: true)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true) self?.openUrl(url, concealed: true, forceExternal: true)
}, requestSwitchInline: { [weak self] query, chatTypes, completion in }, requestSwitchInline: { [weak self] query, chatTypes, completion in
@ -4199,7 +4199,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, isInline: false, isSimple: false) let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true) self?.openUrl(url, concealed: true, forceExternal: true)
}, completion: { [weak self] in }, completion: { [weak self] in
@ -12727,7 +12727,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, isInline: false, isSimple: false) let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true) self?.openUrl(url, concealed: true, forceExternal: true)
}, completion: { [weak self] in }, completion: { [weak self] in
@ -13247,10 +13247,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
case let .app(bot, botName, _): case let .app(bot, botName, _):
var payload: String? var payload: String?
var fromAttachMenu = true
if case let .bot(_, botPayload, _) = subject { if case let .bot(_, botPayload, _) = subject {
payload = botPayload payload = botPayload
fromAttachMenu = false
} }
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, isInline: false, isSimple: false) let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false)
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId) let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId)
controller.openUrl = { [weak self] url in controller.openUrl = { [weak self] url in

View File

@ -1597,8 +1597,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
let keyboardAppearance = interfaceState.theme.rootController.keyboardColor.keyboardAppearance let keyboardAppearance = interfaceState.theme.rootController.keyboardColor.keyboardAppearance
if let textInputNode = self.textInputNode, textInputNode.keyboardAppearance != keyboardAppearance, textInputNode.isFirstResponder() { if let textInputNode = self.textInputNode, textInputNode.keyboardAppearance != keyboardAppearance {
if textInputNode.isCurrentlyEmoji() { if textInputNode.isFirstResponder() && textInputNode.isCurrentlyEmoji() {
textInputNode.initialPrimaryLanguage = "emoji" textInputNode.initialPrimaryLanguage = "emoji"
textInputNode.resetInitialPrimaryLanguage() textInputNode.resetInitialPrimaryLanguage()
} }
@ -2268,7 +2268,13 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let _ = placeholderApply() let _ = placeholderApply()
transition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: hideOffset.x + leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size)) let placeholderTransition: ContainedViewLayoutTransition
if placeholderSize.size.width == contextPlaceholderNode.frame.width {
placeholderTransition = transition
} else {
placeholderTransition = .immediate
}
placeholderTransition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: hideOffset.x + leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size))
contextPlaceholderNode.alpha = audioRecordingItemsAlpha contextPlaceholderNode.alpha = audioRecordingItemsAlpha
} else if let contextPlaceholderNode = self.contextPlaceholderNode { } else if let contextPlaceholderNode = self.contextPlaceholderNode {
self.contextPlaceholderNode = nil self.contextPlaceholderNode = nil

View File

@ -210,7 +210,7 @@ final class CommandMenuChatInputPanelItemNode: ListViewItemNode {
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 130.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 130.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (commandLayout, commandApply) = makeCommandLayout(TextNodeLayoutArguments(attributedString: commandString, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: 120.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (commandLayout, commandApply) = makeCommandLayout(TextNodeLayoutArguments(attributedString: commandString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - rightInset - textLayout.size.width - 16.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: max(CommandMenuChatInputPanelItemNode.itemHeight, textLayout.size.height + 14.0)), insets: UIEdgeInsets()) let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: max(CommandMenuChatInputPanelItemNode.itemHeight, textLayout.size.height + 14.0)), insets: UIEdgeInsets())

View File

@ -25,6 +25,7 @@ import CheckNode
import AppBundle import AppBundle
import ChatControllerInteraction import ChatControllerInteraction
import InvisibleInkDustNode import InvisibleInkDustNode
import MediaPickerUI
private final class FrameSequenceThumbnailNode: ASDisplayNode { private final class FrameSequenceThumbnailNode: ASDisplayNode {
private let context: AccountContext private let context: AccountContext
@ -1631,7 +1632,7 @@ private func tagMaskForType(_ type: PeerInfoVisualMediaPaneNode.ContentType) ->
} }
} }
final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDelegate { final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDelegate, UIGestureRecognizerDelegate {
enum ContentType { enum ContentType {
case photoOrVideo case photoOrVideo
case photo case photo
@ -2445,6 +2446,27 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
self.itemGrid.addToTransitionSurface(view: view) self.itemGrid.addToTransitionSurface(view: view)
} }
private var gridSelectionGesture: MediaPickerGridSelectionGesture<EngineMessage.Id>?
private var listSelectionGesture: MediaPickerGridSelectionGesture<EngineMessage.Id>?
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let location = gestureRecognizer.location(in: gestureRecognizer.view)
if location.x < 44.0 {
return false
}
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer.state != .failed, let otherGestureRecognizer = otherGestureRecognizer as? UIPanGestureRecognizer {
otherGestureRecognizer.isEnabled = false
otherGestureRecognizer.isEnabled = true
return true
} else {
return false
}
}
func updateSelectedMessages(animated: Bool) { func updateSelectedMessages(animated: Bool) {
switch self.contentType { switch self.contentType {
case .files, .music, .voiceAndVideoMessages: case .files, .music, .voiceAndVideoMessages:
@ -2473,7 +2495,36 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: self.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id), animated: animated) itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: self.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id), animated: animated)
} }
self.itemGrid.pinchEnabled = self.chatControllerInteraction.selectionState == nil let isSelecting = self.chatControllerInteraction.selectionState != nil
self.itemGrid.pinchEnabled = !isSelecting
if isSelecting {
if self.gridSelectionGesture == nil {
let selectionGesture = MediaPickerGridSelectionGesture<EngineMessage.Id>()
selectionGesture.delegate = self
selectionGesture.sideInset = 44.0
selectionGesture.updateIsScrollEnabled = { [weak self] isEnabled in
self?.itemGrid.isScrollEnabled = isEnabled
}
selectionGesture.itemAt = { [weak self] point in
if let strongSelf = self, let itemLayer = strongSelf.itemGrid.item(at: point)?.layer as? ItemLayer, let messageId = itemLayer.item?.message.id {
return (messageId, strongSelf.chatControllerInteraction.selectionState?.selectedIds.contains(messageId) ?? false)
} else {
return nil
}
}
selectionGesture.updateSelection = { [weak self] messageId, selected in
if let strongSelf = self {
strongSelf.chatControllerInteraction.toggleMessagesSelection([messageId], selected)
}
}
self.itemGrid.view.addGestureRecognizer(selectionGesture)
self.gridSelectionGesture = selectionGesture
}
} else if let gridSelectionGesture = self.gridSelectionGesture {
self.itemGrid.view.removeGestureRecognizer(gridSelectionGesture)
self.gridSelectionGesture = nil
}
} }
} }

View File

@ -2101,7 +2101,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, threadData: MessageHistoryThreadData?, chatLocation: ChatLocation, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, threadData: MessageHistoryThreadData?, chatLocation: ChatLocation, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat {
let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0 let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 13.0), size: CGSize(width: avatarSize, height: avatarSize)) let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 22.0), size: CGSize(width: avatarSize, height: avatarSize))
transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize())) transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize()))
var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0 var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0
@ -3675,14 +3675,18 @@ final class PeerInfoHeaderNode: ASDisplayNode {
} }
private class DynamicIslandMaskNode: ManagedAnimationNode { private class DynamicIslandMaskNode: ManagedAnimationNode {
var frameIndex: Int = 0
func update(_ value: CGFloat) { func update(_ value: CGFloat) {
let lowerBound = 0 let lowerBound = 0
let upperBound = 180 let upperBound = 180
let frameIndex = lowerBound + Int(value * CGFloat(upperBound - lowerBound)) let frameIndex = lowerBound + Int(value * CGFloat(upperBound - lowerBound))
if frameIndex != self.frameIndex {
self.frameIndex = frameIndex
self.trackTo(item: ManagedAnimationItem(source: .local("UserAvatarMask"), frames: .range(startFrame: frameIndex, endFrame: frameIndex), duration: 0.001)) self.trackTo(item: ManagedAnimationItem(source: .local("UserAvatarMask"), frames: .range(startFrame: frameIndex, endFrame: frameIndex), duration: 0.001))
} }
} }
}
private class DynamicIslandBlurNode: ASDisplayNode { private class DynamicIslandBlurNode: ASDisplayNode {
private var effectView: UIVisualEffectView? private var effectView: UIVisualEffectView?
@ -3730,6 +3734,7 @@ private class DynamicIslandBlurNode: ASDisplayNode {
} }
func update(_ value: CGFloat) { func update(_ value: CGFloat) {
let fadeAlpha = min(1.0, max(0.0, -0.25 + value * 1.55))
if value > 0.0 { if value > 0.0 {
self.prepare() self.prepare()
self.effectView?.layer.timeOffset = max(0.0, -0.1 + value * 1.1) self.effectView?.layer.timeOffset = max(0.0, -0.1 + value * 1.1)
@ -3739,8 +3744,7 @@ private class DynamicIslandBlurNode: ASDisplayNode {
self.effectView?.layer.timeOffset = 0.0 self.effectView?.layer.timeOffset = 0.0
self.effectView?.effect = nil self.effectView?.effect = nil
} }
self.fadeNode.alpha = fadeAlpha
self.fadeNode.alpha = min(1.0, max(0.0, -0.25 + value * 1.55))
} }
override func layout() { override func layout() {

View File

@ -9313,6 +9313,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
return result return result
} }
fileprivate func presentSelectionDiscardAlert(action: @escaping () -> Void = {}) -> Bool {
if let selectedIds = self.chatInterfaceInteraction.selectionState?.selectedIds, !selectedIds.isEmpty {
self.controller?.present(textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: self.presentationData.strings.PeerInfo_CancelSelectionAlertText, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.PeerInfo_CancelSelectionAlertNo, action: {}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.PeerInfo_CancelSelectionAlertYes, action: {
action()
})]), in: .window(.root))
return true
}
return false
}
} }
public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortcutResponder { public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortcutResponder {
@ -9666,6 +9676,20 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
} }
} }
}) })
if !isSettings {
self.attemptNavigation = { [weak self] action in
guard let strongSelf = self else {
return true
}
if strongSelf.controllerNode.presentSelectionDiscardAlert(action: action) {
return false
}
return true
}
}
} }
required init(coder aDecoder: NSCoder) { required init(coder aDecoder: NSCoder) {

View File

@ -667,7 +667,7 @@ public class ShareRootControllerImpl {
attemptSelectionImpl?(peer) attemptSelectionImpl?(peer)
}, createNewGroup: { }, createNewGroup: {
createNewGroupImpl?() createNewGroupImpl?()
}, pretendPresentedInModal: true, selectForumThreads: true)) }, pretendPresentedInModal: true, selectForumThreads: false))
controller.customDismiss = { controller.customDismiss = {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil) self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)

View File

@ -154,6 +154,7 @@ private final class EffectImageLayer: SimpleLayer, GradientBackgroundPatternOver
} }
private var isUsingSoftlight: Bool = false private var isUsingSoftlight: Bool = false
private var useFilter: Bool = false
var suspendCompositionUpdates: Bool = false var suspendCompositionUpdates: Bool = false
private var needsCompositionUpdate: Bool = false private var needsCompositionUpdate: Bool = false
@ -172,10 +173,11 @@ private final class EffectImageLayer: SimpleLayer, GradientBackgroundPatternOver
useSoftlight = true useSoftlight = true
useFilter = false useFilter = false
} }
if self.isUsingSoftlight != useSoftlight { if self.isUsingSoftlight != useSoftlight || self.useFilter != useFilter {
self.isUsingSoftlight = useSoftlight self.isUsingSoftlight = useSoftlight
self.useFilter = useFilter
if self.isUsingSoftlight && useFilter { if self.isUsingSoftlight && self.useFilter {
self.compositingFilter = "softLightBlendMode" self.compositingFilter = "softLightBlendMode"
} else { } else {
self.compositingFilter = nil self.compositingFilter = nil
@ -842,10 +844,6 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
} }
private static var cachedSharedPattern: (PatternKey, UIImage)? private static var cachedSharedPattern: (PatternKey, UIImage)?
//private var inlineAnimationNodes: [(AnimatedStickerNode, CGPoint)] = []
//private let hierarchyTrackingLayer = HierarchyTrackingLayer()
//private var activateInlineAnimationTimer: SwiftSignalKit.Timer?
private let _isReady = ValuePromise<Bool>(false, ignoreRepeated: true) private let _isReady = ValuePromise<Bool>(false, ignoreRepeated: true)
var isReady: Signal<Bool, NoError> { var isReady: Signal<Bool, NoError> {
return self._isReady.get() return self._isReady.get()
@ -1309,13 +1307,6 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: transition) self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: transition)
/*for (animationNode, relativePosition) in self.inlineAnimationNodes {
let sizeNorm = CGSize(width: 1440, height: 2960)
let animationSize = CGSize(width: 512.0 / sizeNorm.width * size.width, height: 512.0 / sizeNorm.height * size.height)
animationNode.frame = CGRect(origin: CGPoint(x: relativePosition.x / sizeNorm.width * size.width, y: relativePosition.y / sizeNorm.height * size.height), size: animationSize)
animationNode.updateLayout(size: animationNode.frame.size)
}*/
if isFirstLayout && !self.frame.isEmpty { if isFirstLayout && !self.frame.isEmpty {
self.updateScale() self.updateScale()
} }

View File

@ -134,6 +134,7 @@ public struct WebAppParameters {
let buttonText: String? let buttonText: String?
let keepAliveSignal: Signal<Never, KeepWebViewError>? let keepAliveSignal: Signal<Never, KeepWebViewError>?
let fromMenu: Bool let fromMenu: Bool
let fromAttachMenu: Bool
let isInline: Bool let isInline: Bool
let isSimple: Bool let isSimple: Bool
@ -147,6 +148,7 @@ public struct WebAppParameters {
buttonText: String?, buttonText: String?,
keepAliveSignal: Signal<Never, KeepWebViewError>?, keepAliveSignal: Signal<Never, KeepWebViewError>?,
fromMenu: Bool, fromMenu: Bool,
fromAttachMenu: Bool,
isInline: Bool, isInline: Bool,
isSimple: Bool isSimple: Bool
) { ) {
@ -159,6 +161,7 @@ public struct WebAppParameters {
self.buttonText = buttonText self.buttonText = buttonText
self.keepAliveSignal = keepAliveSignal self.keepAliveSignal = keepAliveSignal
self.fromMenu = fromMenu self.fromMenu = fromMenu
self.fromAttachMenu = fromAttachMenu
self.isInline = isInline self.isInline = isInline
self.isSimple = isSimple self.isSimple = isSimple
} }
@ -656,7 +659,7 @@ 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 webView = self.webView, !webView.didTouchOnce && controller.url == nil { if let webView = self.webView, !webView.didTouchOnce && controller.url == nil && controller.fromAttachMenu {
self.delayedScriptMessage = message self.delayedScriptMessage = message
} else if let json = json { } else if let json = json {
if var isVisible = json["is_visible"] as? Bool { if var isVisible = json["is_visible"] as? Bool {
@ -1058,6 +1061,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
private let payload: String? private let payload: String?
private let buttonText: String? private let buttonText: String?
private let fromMenu: Bool private let fromMenu: Bool
private let fromAttachMenu: Bool
private let isInline: Bool private let isInline: Bool
private let isSimple: Bool private let isSimple: Bool
private let keepAliveSignal: Signal<Never, KeepWebViewError>? private let keepAliveSignal: Signal<Never, KeepWebViewError>?
@ -1083,6 +1087,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.payload = params.payload self.payload = params.payload
self.buttonText = params.buttonText self.buttonText = params.buttonText
self.fromMenu = params.fromMenu self.fromMenu = params.fromMenu
self.fromAttachMenu = params.fromAttachMenu
self.isInline = params.isInline self.isInline = params.isInline
self.isSimple = params.isSimple self.isSimple = params.isSimple
self.keepAliveSignal = params.keepAliveSignal self.keepAliveSignal = params.keepAliveSignal