Attachment menu improvements

This commit is contained in:
Ilya Laktyushin 2022-02-26 22:06:43 +04:00
parent 970203e0dc
commit b8e0fe64f2
10 changed files with 157 additions and 15 deletions

View File

@ -96,6 +96,14 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
self.wrappingNode.view.addGestureRecognizer(panRecognizer)
}
func cancelPanGesture() {
if let panGestureRecognizer = self.panGestureRecognizer, panGestureRecognizer.isEnabled {
self.panGestureArguments = nil
panGestureRecognizer.isEnabled = false
panGestureRecognizer.isEnabled = true
}
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let (layout, _, _) = self.validLayout {
if case .regular = layout.metrics.widthClass {

View File

@ -24,6 +24,7 @@ public protocol AttachmentContainable: ViewController {
var requestAttachmentMenuExpansion: () -> Void { get set }
var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void { get set }
var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void { get set }
var cancelPanGesture: () -> Void { get set }
func resetForReuse()
func prepareForReuse()
@ -283,6 +284,11 @@ public class AttachmentController: ViewController {
strongSelf.panel.updateBackgroundAlpha(alpha, transition: transition)
}
}
controller.cancelPanGesture = { [weak self] in
if let strongSelf = self {
strongSelf.container.cancelPanGesture()
}
}
let previousController = strongSelf.currentControllers.last
let animateTransition = previousType != nil
strongSelf.currentControllers = [controller]

View File

@ -520,6 +520,7 @@ private class CreatePollControllerImpl: ItemListController, AttachmentContainabl
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
}
public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> AttachmentContainable {

View File

@ -408,6 +408,7 @@ open class LegacyController: ViewController, PresentableController, AttachmentCo
open var requestAttachmentMenuExpansion: () -> Void = {}
open var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
open var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
open var cancelPanGesture: () -> Void = { }
public init(presentation: LegacyControllerPresentation, theme: PresentationTheme? = nil, strings: PresentationStrings? = nil, initialLayout: ContainerViewLayout? = nil) {
self.sizeClass.set(SSignal.single(UIUserInterfaceSizeClass.compact.rawValue as NSNumber))

View File

@ -74,6 +74,7 @@ public final class LocationPickerController: ViewController, AttachmentContainab
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: LocationPickerMode, completion: @escaping (TelegramMediaMap, String?) -> Void) {
self.context = context

View File

@ -105,7 +105,7 @@ final class MediaPickerGridItemNode: GridItemNode {
return self.asset?.localIdentifier ?? ""
}
private var asset: PHAsset? {
var asset: PHAsset? {
if let (fetchResult, index) = self.currentState {
return fetchResult[index]
} else {
@ -113,7 +113,7 @@ final class MediaPickerGridItemNode: GridItemNode {
}
}
func updateSelectionState() {
func updateSelectionState(animated: Bool = false) {
if self.checkNode == nil, let _ = self.interaction?.selectionState, let theme = self.theme {
let checkNode = InteractiveCheckNode(theme: CheckNodeTheme(theme: theme, style: .overlay))
checkNode.valueChanged = { [weak self] value in
@ -136,7 +136,7 @@ final class MediaPickerGridItemNode: GridItemNode {
self.checkNode?.content = .counter(Int(index))
}
}
self.checkNode?.setSelected(selected, animated: false)
self.checkNode?.setSelected(selected, animated: animated)
}
}

View File

@ -101,8 +101,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
public var requestAttachmentMenuExpansion: () -> Void = { }
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
private class Node: ViewControllerTracingNode {
private class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
enum DisplayMode {
case all
case selected
@ -165,8 +166,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
super.init()
// self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.backgroundNode)
self.containerNode.addSubnode(self.gridNode)
@ -226,10 +225,12 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
})
if let selectionState = self.controller?.interaction?.selectionState {
func selectionChangedSignal(selectionState: TGMediaSelectionContext) -> Signal<Void, NoError> {
func selectionChangedSignal(selectionState: TGMediaSelectionContext) -> Signal<Bool, NoError> {
return Signal { subscriber in
let disposable = selectionState.selectionChangedSignal()?.start(next: { next in
subscriber.putNext(Void())
if let next = next as? TGMediaSelectionChange {
subscriber.putNext(next.animated)
}
}, completed: {})
return ActionDisposable {
disposable?.dispose()
@ -238,9 +239,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
self.selectionChangedDisposable = (selectionChangedSignal(selectionState: selectionState)
|> deliverOnMainQueue).start(next: { [weak self] _ in
|> deliverOnMainQueue).start(next: { [weak self] animated in
if let strongSelf = self {
strongSelf.updateSelectionState()
strongSelf.updateSelectionState(animated: animated)
}
})
}
@ -273,6 +274,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.itemsDimensionsUpdatedDisposable?.dispose()
}
private var selectionGesture: MediaPickerGridSelectionGesture?
override func didLoad() {
super.didLoad()
@ -296,7 +298,31 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.containerNode.clipsToBounds = true
}
// self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
self.selectionGesture = MediaPickerGridSelectionGesture(target: nil, action: nil, gridNode: self.gridNode)
self.selectionGesture?.delegate = self
self.selectionGesture?.began = { [weak self] in
self?.controller?.cancelPanGesture()
}
self.selectionGesture?.itemAt = { [weak self] point in
if let strongSelf = self, let itemNode = strongSelf.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let asset = itemNode.asset.flatMap({ TGMediaAsset(phAsset: $0) }) {
return (asset, strongSelf.controller?.interaction?.selectionState?.isItemSelected(asset) ?? false)
} else {
return nil
}
}
self.selectionGesture?.updateSelection = { [weak self] asset, selected in
if let strongSelf = self {
strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil)
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if otherGestureRecognizer.view is UIScrollView || otherGestureRecognizer is UIPanGestureRecognizer {
return true
} else {
return false
}
}
fileprivate func dismissInput() {
@ -363,10 +389,10 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.updateNavigation(transition: .immediate)
}
private func updateSelectionState() {
private func updateSelectionState(animated: Bool = false) {
self.gridNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? MediaPickerGridItemNode {
itemNode.updateSelectionState()
itemNode.updateSelectionState(animated: animated)
}
}
self.selectionNode?.updateSelectionState()
@ -1165,3 +1191,98 @@ private final class MediaPickerContextReferenceContentSource: ContextReferenceCo
return ContextControllerReferenceViewInfo(referenceNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
}
}
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?
private var processing = false
private var selecting = false
private var initialLocation: CGPoint?
init(target: Any?, action: Selector?, gridNode: GridNode) {
self.gridNode = gridNode
super.init(target: target, action: action)
gridNode.view.addGestureRecognizer(self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
guard let touch = touches.first, let gridNode = self.gridNode else {
return
}
let location = touch.location(in: gridNode.view)
self.initialLocation = location
}
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 {
self.state = .failed
return
}
let location = touch.location(in: gridNode.view)
let translation = CGPoint(x: location.x - initialLocation.x, y: location.y - initialLocation.y)
var additionalLocation: CGPoint?
if !self.processing {
if abs(translation.y) > 5.0 {
self.state = .failed
} else if abs(translation.x) > 4.0 {
self.processing = true
self.gridNode?.scrollView.isScrollEnabled = false
self.began()
if let (_, selected) = self.itemAt(location) {
self.selecting = !selected
}
additionalLocation = self.initialLocation
}
}
if self.processing {
if let additionalLocation = additionalLocation {
if let (item, selected) = self.itemAt(additionalLocation), selected != self.selecting {
self.updateSelection(item, self.selecting)
}
}
if let (item, selected) = self.itemAt(location), selected != self.selecting {
self.updateSelection(item, self.selecting)
}
}
}
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) {
super.touchesCancelled(touches, with: event)
self.state = .failed
self.reset()
}
override func reset() {
super.reset()
self.processing = false
self.initialLocation = nil
self.gridNode?.scrollView.isScrollEnabled = true
}
}

View File

@ -167,6 +167,7 @@ private class AttachmentFileControllerImpl: ItemListController, AttachmentContai
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
var resetForReuseImpl: () -> Void = {}
public func resetForReuse() {

View File

@ -78,6 +78,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
var requestAttachmentMenuExpansion: () -> Void = {}
var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
var cancelPanGesture: () -> Void = { }
init(_ params: ContactSelectionControllerParams) {
self.context = params.context

View File

@ -1902,6 +1902,7 @@ webrtc_sources = [
"modules/audio_coding/neteq/timestamp_scaler.h",
"modules/audio_device/audio_device_buffer.h",
"modules/audio_device/audio_device_generic.h",
"modules/audio_device/audio_device_impl.h",
"modules/audio_device/dummy/audio_device_dummy.h",
"modules/audio_device/dummy/file_audio_device.h",
"modules/audio_device/dummy/file_audio_device_factory.h",
@ -2973,6 +2974,7 @@ ios_objc_sources = [
]
ios_sources = [
"objc/native/api/audio_device_module.h",
"objc/native/src/audio/audio_session_observer.h",
"objc/native/src/audio/helpers.h",
"objc/native/src/audio/helpers.mm",