Attachment menu improvements

This commit is contained in:
Ilya Laktyushin 2022-03-09 01:15:59 +04:00
parent 555c097d07
commit 8332b434a9
8 changed files with 86 additions and 47 deletions

View File

@ -7352,6 +7352,10 @@ Sorry for the inconvenience.";
"Attachment.LocationAccessTitle" = "Access Your Location";
"Attachment.LocationAccessText" = "Share places or your live location.";
"Attachment.CancelSelectionAlertText" = "Cancel selection?";
"Attachment.CancelSelectionAlertYes" = "Yes";
"Attachment.CancelSelectionAlertNo" = "No";
"ChannelInfo.CreateExternalStream" = "Stream With...";
"CreateExternalStream.Title" = "Stream With...";

View File

@ -207,18 +207,24 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
if currentOffset > 0.0, let scrollView = scrollView {
scrollView.panGestureRecognizer.setTranslation(CGPoint(), in: scrollView)
}
var bounds = self.bounds
bounds.origin.y = -translation
bounds.origin.y = min(0.0, bounds.origin.y)
self.bounds = bounds
}
var bounds = self.bounds
if self.isExpanded {
bounds.origin.y = -max(0.0, translation - edgeTopInset)
} else {
bounds.origin.y = -translation
}
bounds.origin.y = min(0.0, bounds.origin.y)
self.bounds = bounds
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .immediate)
case .ended:
guard let (currentTopInset, panOffset, scrollView, listNode) = self.panGestureArguments else {
return
}
self.panGestureArguments = nil
let visibleContentOffset = listNode?.visibleContentOffset()
let contentOffset = scrollView?.contentOffset.y ?? 0.0
@ -236,15 +242,23 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
}
var bounds = self.bounds
bounds.origin.y = -translation
if self.isExpanded {
bounds.origin.y = -max(0.0, translation - edgeTopInset)
} else {
bounds.origin.y = -translation
}
bounds.origin.y = min(0.0, bounds.origin.y)
scrollView?.bounces = true
let offset = currentTopInset + panOffset
let topInset: CGFloat = edgeTopInset
if self.isExpanded {
self.panGestureArguments = nil
var dismissing = false
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 600.0) {
self.interactivelyDismissed?()
dismissing = true
} else if self.isExpanded {
if velocity.y > 300.0 || offset > topInset / 2.0 {
self.isExpanded = false
if let listNode = listNode {
@ -262,42 +276,34 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut))
}
} else if (velocity.y < -300.0 || offset < topInset / 2.0) {
if velocity.y > -2200.0 && velocity.y < -300.0, let listNode = listNode {
DispatchQueue.main.async {
listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
}
}
let initialVelocity: CGFloat = offset.isZero ? 0.0 : abs(velocity.y / offset)
let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
self.isExpanded = true
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: transition)
} else {
self.panGestureArguments = nil
var dismissing = false
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) {
self.interactivelyDismissed?()
dismissing = true
} else if (velocity.y < -300.0 || offset < topInset / 2.0) {
if velocity.y > -2200.0 && velocity.y < -300.0, let listNode = listNode {
DispatchQueue.main.async {
listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
}
}
let initialVelocity: CGFloat = offset.isZero ? 0.0 : abs(velocity.y / offset)
let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
self.isExpanded = true
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: transition)
} else {
if let listNode = listNode {
listNode.scroller.setContentOffset(CGPoint(), animated: false)
} else if let scrollView = scrollView {
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
}
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut))
if let listNode = listNode {
listNode.scroller.setContentOffset(CGPoint(), animated: false)
} else if let scrollView = scrollView {
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
}
if !dismissing {
var bounds = self.bounds
let previousBounds = bounds
bounds.origin.y = 0.0
self.bounds = bounds
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
}
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut))
}
if !dismissing {
var bounds = self.bounds
let previousBounds = bounds
bounds.origin.y = 0.0
self.bounds = bounds
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
}
case .cancelled:
self.panGestureArguments = nil

View File

@ -28,6 +28,8 @@ public protocol AttachmentContainable: ViewController {
func resetForReuse()
func prepareForReuse()
func requestDismiss(completion: @escaping () -> Void)
}
public extension AttachmentContainable {
@ -38,6 +40,10 @@ public extension AttachmentContainable {
func prepareForReuse() {
}
func requestDismiss(completion: @escaping () -> Void) {
completion()
}
}
public enum AttachmentMediaPickerSendMode {
@ -274,7 +280,13 @@ public class AttachmentController: ViewController {
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.controller?.dismiss(animated: true)
if let controller = self.currentControllers.last {
controller.requestDismiss(completion: { [weak self] in
self?.controller?.dismiss(animated: true)
})
} else {
self.controller?.dismiss(animated: true)
}
}
}

View File

@ -519,7 +519,7 @@ public final class ComposedPoll {
private class CreatePollControllerImpl: ItemListController, AttachmentContainable {
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
}

View File

@ -140,6 +140,10 @@
if (strongSelf == nil)
return;
strongSelf->_ignoreSelectionUpdates = true;
[strongSelf->_selectionChangedDisposable dispose];
[strongSelf->_itemSelectedDisposable dispose];
[strongSelf.window endEditing:true];
strongSelf->_portraitToolbarView.doneButton.userInteractionEnabled = false;
strongSelf->_landscapeToolbarView.doneButton.userInteractionEnabled = false;

View File

@ -191,7 +191,6 @@
UIView *contentView = [itemView transitionContentView];
UIView *snapshotView = [contentView snapshotViewAfterScreenUpdates:true];
snapshotView.frame = [contentView convertRect:contentView.bounds toView:nil];
// snapshotView.frame = CGRectOffset([contentView convertRect:contentView.bounds toView:nil], 0.0, -self.view.frame.size.height);
return snapshotView;
}
}

View File

@ -379,12 +379,11 @@ static const CGFloat swipeDistanceThreshold = 128.0f;
completion();
}];
[UIView animateWithDuration:ABS(distance / velocity) animations:^
{
[UIView animateWithDuration:0.15 animations:^{
_interfaceView.alpha = 0.0f;
_overlayContainerView.alpha = 0.0f;
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
} completion:nil];
}];
}
- (void)transitionInWithDuration:(NSTimeInterval)duration

View File

@ -19,6 +19,7 @@ import ContextUI
import WebSearchUI
import SparseItemGrid
import UndoUI
import PresentationDataUtils
let overflowInset: CGFloat = 0.0
@ -1282,8 +1283,22 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.undoOverlayController?.dismissWithCommitAction()
}
public func requestDismiss(completion: @escaping () -> Void) {
if let selectionState = self.interaction?.selectionState, selectionState.count() > 0 {
let controller = textAlertController(context: self.context, title: nil, text: self.presentationData.strings.Attachment_CancelSelectionAlertText, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertNo, action: {
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertYes, action: {
completion()
})])
self.present(controller, in: .window(.root))
} else {
completion()
}
}
@objc private func cancelPressed() {
self.dismissAllTooltips()
self.dismiss()
}