UI improvements
This commit is contained in:
parent
7269255d00
commit
c02f796791
12 changed files with 163 additions and 73 deletions
|
|
@ -9081,3 +9081,9 @@ Sorry for the inconvenience.";
|
|||
|
||||
"CreateGroup.PeersTitleDelimeter" = ", ";
|
||||
"CreateGroup.PeersTitleLastDelimeter" = " and ";
|
||||
|
||||
"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.";
|
||||
|
|
|
|||
|
|
@ -2561,10 +2561,6 @@ public final class ChatListNode: ListView {
|
|||
return strongSelf.isSelectionGestureEnabled
|
||||
}
|
||||
self.view.addGestureRecognizer(selectionRecognizer)
|
||||
|
||||
// if case .forum = location {
|
||||
// self.isSelectionGestureEnabled = false
|
||||
// }
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
|||
|
|
@ -139,6 +139,11 @@ open class ViewControllerComponentContainer: ViewController {
|
|||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: Transition) {
|
||||
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(
|
||||
statusBarHeight: layout.statusBarHeight ?? 0.0,
|
||||
navigationHeight: navigationHeight,
|
||||
|
|
@ -147,7 +152,7 @@ open class ViewControllerComponentContainer: ViewController {
|
|||
metrics: layout.metrics,
|
||||
deviceMetrics: layout.deviceMetrics,
|
||||
isVisible: self.currentIsVisible,
|
||||
theme: self.theme ?? self.presentationData.theme,
|
||||
theme: theme,
|
||||
strings: self.presentationData.strings,
|
||||
dateTimeFormat: self.presentationData.dateTimeFormat,
|
||||
controller: { [weak self] in
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.backgroundNode)
|
||||
self.containerNode.addSubnode(self.gridNode)
|
||||
// self.containerNode.addSubnode(self.scrollingArea)
|
||||
//self.containerNode.addSubnode(self.scrollingArea)
|
||||
|
||||
let preloadPromise = self.preloadPromise
|
||||
let updatedState: Signal<State, NoError>
|
||||
|
|
@ -359,30 +359,36 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||
self.itemsDimensionsUpdatedDisposable?.dispose()
|
||||
}
|
||||
|
||||
private var selectionGesture: MediaPickerGridSelectionGesture?
|
||||
private var selectionGesture: MediaPickerGridSelectionGesture<TGMediaSelectableItem>?
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.gridNode.scrollView.alwaysBounceVertical = true
|
||||
self.gridNode.scrollView.showsVerticalScrollIndicator = false
|
||||
|
||||
self.selectionGesture = MediaPickerGridSelectionGesture(target: nil, action: nil, gridNode: self.gridNode)
|
||||
self.selectionGesture?.delegate = self
|
||||
self.selectionGesture?.began = { [weak self] in
|
||||
let selectionGesture = MediaPickerGridSelectionGesture<TGMediaSelectableItem>()
|
||||
selectionGesture.delegate = self
|
||||
selectionGesture.began = { [weak self] in
|
||||
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 {
|
||||
return (selectableItem, strongSelf.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
self.selectionGesture?.updateSelection = { [weak self] asset, selected in
|
||||
selectionGesture.updateSelection = { [weak self] asset, selected in
|
||||
if let strongSelf = self {
|
||||
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 {
|
||||
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: {
|
||||
|
||||
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertYes, action: { [weak self] in
|
||||
self?.dismissAllTooltips()
|
||||
completion()
|
||||
|
|
@ -1794,37 +1799,31 @@ private final class MediaPickerContextReferenceContentSource: ContextReferenceCo
|
|||
}
|
||||
}
|
||||
|
||||
private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
|
||||
var itemAt: (CGPoint) -> (TGMediaSelectableItem, Bool)? = { _ in return nil }
|
||||
var updateSelection: (TGMediaSelectableItem, Bool) -> Void = { _, _ in}
|
||||
var began: () -> Void = {}
|
||||
|
||||
private weak var gridNode: GridNode?
|
||||
public class MediaPickerGridSelectionGesture<T> : UIPanGestureRecognizer {
|
||||
public var itemAt: (CGPoint) -> (T, Bool)? = { _ in return nil }
|
||||
public var updateSelection: (T, Bool) -> Void = { _, _ in}
|
||||
public var updateIsScrollEnabled: (Bool) -> Void = { _ in}
|
||||
public var began: () -> Void = {}
|
||||
|
||||
private var processing = false
|
||||
private var selecting = false
|
||||
|
||||
private var initialLocation: CGPoint?
|
||||
|
||||
var sideInset: CGFloat = 0.0
|
||||
public var sideInset: CGFloat = 0.0
|
||||
|
||||
init(target: Any?, action: Selector?, gridNode: GridNode) {
|
||||
self.gridNode = gridNode
|
||||
|
||||
super.init(target: target, action: action)
|
||||
|
||||
gridNode.view.addGestureRecognizer(self)
|
||||
public init() {
|
||||
super.init(target: nil, action: nil)
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
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
|
||||
}
|
||||
|
||||
let location = touch.location(in: gridNode.view)
|
||||
|
||||
let location = touch.location(in: self.view)
|
||||
if location.x > self.sideInset {
|
||||
self.initialLocation = location
|
||||
} 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)
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
var additionalLocation: CGPoint?
|
||||
|
|
@ -1849,7 +1848,7 @@ private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
|
|||
self.state = .failed
|
||||
} else if abs(translation.x) > 8.0 {
|
||||
self.processing = true
|
||||
self.gridNode?.scrollView.isScrollEnabled = false
|
||||
self.updateIsScrollEnabled(false)
|
||||
self.began()
|
||||
|
||||
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)
|
||||
|
||||
self.state = .failed
|
||||
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)
|
||||
|
||||
self.state = .failed
|
||||
self.reset()
|
||||
}
|
||||
|
||||
override func reset() {
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
|
||||
self.processing = false
|
||||
self.initialLocation = nil
|
||||
self.gridNode?.scrollView.isScrollEnabled = true
|
||||
self.updateIsScrollEnabled(true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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 {
|
||||
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 {
|
||||
backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
|||
|
||||
static var body: Body {
|
||||
let overscroll = Child(Rectangle.self)
|
||||
let fade = Child(RoundedRectangle.self)
|
||||
let text = Child(MultilineTextComponent.self)
|
||||
let optionsSection = Child(SectionGroupComponent.self)
|
||||
let perksSection = Child(SectionGroupComponent.self)
|
||||
|
|
@ -195,23 +194,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
|||
context.add(overscroll
|
||||
.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
|
||||
|
||||
let textColor = theme.list.itemPrimaryTextColor
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
async {
|
||||
let node = ItemListReactionItemNode()
|
||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
Queue.mainQueue().async {
|
||||
let node = ItemListReactionItemNode()
|
||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
|
||||
completion(node, {
|
||||
return (nil, { _ in apply() })
|
||||
})
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
|||
case packOrder(PresentationTheme, String, Bool)
|
||||
case packOrderInfo(PresentationTheme, String)
|
||||
case suggestAnimatedEmoji(String, Bool)
|
||||
case suggestAnimatedEmojiInfo(PresentationTheme, String)
|
||||
case packsTitle(PresentationTheme, String)
|
||||
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing, Bool?)
|
||||
case packsInfo(PresentationTheme, String)
|
||||
|
|
@ -100,7 +101,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
|||
switch self {
|
||||
case .trending, .masks, .emoji, .quickReaction, .archived:
|
||||
return InstalledStickerPacksSection.categories.rawValue
|
||||
case .suggestOptions, .largeEmoji, .suggestAnimatedEmoji, .packOrder, .packOrderInfo:
|
||||
case .suggestOptions, .largeEmoji, .suggestAnimatedEmoji, .suggestAnimatedEmojiInfo, .packOrder, .packOrderInfo:
|
||||
return InstalledStickerPacksSection.settings.rawValue
|
||||
case .packsTitle, .pack, .packsInfo:
|
||||
return InstalledStickerPacksSection.stickers.rawValue
|
||||
|
|
@ -125,16 +126,18 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
|||
return .index(6)
|
||||
case .suggestAnimatedEmoji:
|
||||
return .index(7)
|
||||
case .packOrder:
|
||||
case .suggestAnimatedEmojiInfo:
|
||||
return .index(8)
|
||||
case .packOrderInfo:
|
||||
case .packOrder:
|
||||
return .index(9)
|
||||
case .packsTitle:
|
||||
case .packOrderInfo:
|
||||
return .index(10)
|
||||
case .packsTitle:
|
||||
return .index(11)
|
||||
case let .pack(_, _, _, info, _, _, _, _, _, _):
|
||||
return .pack(info.id)
|
||||
case .packsInfo:
|
||||
return .index(11)
|
||||
return .index(12)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,6 +203,12 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
|||
} else {
|
||||
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):
|
||||
if case let .packsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
|
|
@ -323,9 +332,16 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
|||
default:
|
||||
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:
|
||||
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
|
||||
default:
|
||||
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
|
||||
arguments.toggleSuggestAnimatedEmoji(value)
|
||||
})
|
||||
case let .suggestAnimatedEmojiInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .packsTitle(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
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(.suggestAnimatedEmojiInfo(presentationData.theme, presentationData.strings.StickerPacksSettings_SuggestAnimatedEmojiInfo))
|
||||
}
|
||||
|
||||
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [namespaceForMode(mode)])] as? ItemCollectionInfosView {
|
||||
|
|
|
|||
|
|
@ -1344,6 +1344,12 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||
self.pinchRecognizer?.isEnabled = self.pinchEnabled
|
||||
}
|
||||
}
|
||||
|
||||
public var isScrollEnabled: Bool = true {
|
||||
didSet {
|
||||
self.currentViewport?.scrollView.isScrollEnabled = self.isScrollEnabled
|
||||
}
|
||||
}
|
||||
|
||||
public init(theme: PresentationTheme, initialZoomLevel: ZoomLevel? = nil) {
|
||||
self.theme = theme
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import CheckNode
|
|||
import AppBundle
|
||||
import ChatControllerInteraction
|
||||
import InvisibleInkDustNode
|
||||
import MediaPickerUI
|
||||
|
||||
private final class FrameSequenceThumbnailNode: ASDisplayNode {
|
||||
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 {
|
||||
case photoOrVideo
|
||||
case photo
|
||||
|
|
@ -2445,6 +2446,27 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||
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) {
|
||||
switch self.contentType {
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
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()))
|
||||
|
||||
var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0
|
||||
|
|
|
|||
|
|
@ -9313,6 +9313,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||
}
|
||||
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 {
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue