Skip to content
This repository has been archived by the owner on Aug 1, 2019. It is now read-only.

[unstable] Optimized "to past" scrolling by reversing cells order #179

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4eb5bd5
more brief rect constant
Apr 24, 2017
9a65c71
[128] custom nib for bottom bar
Apr 24, 2017
f910a51
[115] avatar on top of bubble
Apr 24, 2017
40b541e
[122] keyboard in TabBar fix
Apr 24, 2017
3ac432f
minor refactoring
Apr 24, 2017
78ba439
minor refactoring
Apr 24, 2017
8dd6195
[image multiselect] added a protocol for image picker VC
May 17, 2017
ad4b2f6
[image multiselect] added methods to override for multiselection hand…
May 17, 2017
18dd3f2
[image multiselect] replaced inline sendText() instructions with dele…
May 17, 2017
53f360f
[image multiselect] made `cameraAuthStatus` and `photoLibAuthStatus` …
May 18, 2017
00dd63f
[multiselect] added images for multiselection and camera button
May 19, 2017
0450bd8
added a missing include
May 19, 2017
4c9103d
[multiselect] added custom picker based on UICollectionView
May 19, 2017
655ed35
[multiselect] encapsulated push/pop for image picker
May 19, 2017
f8cbc1b
Minor refactoring. Also added a todo about localization.
May 19, 2017
233308b
[multiselect] separate directory for picker
May 19, 2017
6d40c20
[multiselect] added camera image
May 22, 2017
479e53e
[multiselect] extracted "image from picker response" helper class
May 22, 2017
df1b58b
[multiselect] added live camera cell
May 22, 2017
e86a83b
[multiselect] saving newly shot image in camera roll
May 22, 2017
7fa86f6
[multiselect] extended customization options
May 22, 2017
957b39d
[multiselect] added some properties to accomplish the feature
May 22, 2017
90e30b6
[image multiselection] applied lazy to PHCachingImageManager to avoid…
Jun 12, 2017
446e8d2
added an optional symbols count limit
Jun 12, 2017
97cc2f8
[#142] extracted `itemsCount` property to fix the crash
Jul 20, 2017
1b947ac
[refactoring] extracted a few local variables
Jul 20, 2017
b0f83b8
Added "symbolsCounterLabel" and some text input limitations logic
Jul 20, 2017
27adb9f
[#143] Extracted CameraViewDelegate to a separate class
Jul 20, 2017
8430b3a
[#143] added "text + collection" subclass of CollectionViewContentNode
Jul 20, 2017
74722aa
[crash] fixed photo capture issue by replacing force unwrap with `if …
Jul 20, 2017
6a355a3
[#143] added PHAssets delegate methods for multiselect picker
Jul 20, 2017
8d45b77
[#143] added PHAsset getter to MultiselectImagePickerController
Jul 20, 2017
e6db74f
[#143] added `func onAssetsPicked()` to override
Jul 20, 2017
675cd8f
swift4 support fixes
Dec 12, 2017
51edfb7
[timestamp] added mixed content node and timestamp utils class
Dec 12, 2017
c8a5c83
[image] extracted aspect ratio constant to a local variable
Dec 12, 2017
d48b0df
[alerts] added localization for menu entries
Dec 12, 2017
bc26014
swift4 support fixes
Dec 12, 2017
2e2c550
[image picker] added more delegate methods for better flexibility
Dec 12, 2017
864fc12
swift4 support fixes
Dec 12, 2017
d20d642
[optimization] reverse cell order for sooth "scroll backwards" scenario
Dec 12, 2017
693287c
[NMessengerViewController] exposed some constraints for injection pri…
Dec 12, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
332 changes: 325 additions & 7 deletions nMessenger.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Binary file added nMessenger/Source/Images/Checkmark-green.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nMessenger/Source/Images/Icon_add_photo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nMessenger/Source/Images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nMessenger/Source/Images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nMessenger/Source/Images/photo-camera-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// CollectionViewWithTextContentNode.swift
// nMessenger
//
// Created by Alexander Dodatko on 7/18/17.
// Copyright © 2017 Ebay Inc. All rights reserved.
//

import Foundation
import AsyncDisplayKit


open class CollectionViewWithTextContentNode: CollectionViewContentNode
{
public var textMessageNode: ASTextNode?
public var timestampNode : ASTextNode?

override open func layoutSpecThatFits(
_ constrainedSize: ASSizeRange)
-> ASLayoutSpec
{
guard let textMessageNodeUnwrap = self.textMessageNode,
let timestampNodeUnwrap = self.timestampNode
else
{
return super.layoutSpecThatFits(constrainedSize)
}


// ====
//
let cellsLayout = super.layoutSpecThatFits(constrainedSize)

let imagesPaddingInsets =
UIEdgeInsets(
top: 4,
left: 15,
bottom: 15,
right: 4)
let imagesPadding =
ASInsetLayoutSpec(
insets: imagesPaddingInsets,
child: cellsLayout)


// ==== timestampNode
//
let timespampPaddingInsets =
UIEdgeInsets(
top: 10,
left: 15,
bottom: 0,
right: 0)
let timestampPadding =
ASInsetLayoutSpec(
insets: timespampPaddingInsets,
child: timestampNodeUnwrap)

// ==== textMessageNode
//
let labelPaddingInsets =
UIEdgeInsets(
top: 5,
left: 15,
bottom: 0,
right: 0)
let labelPadding =
ASInsetLayoutSpec(
insets: labelPaddingInsets,
child: textMessageNodeUnwrap)


// ====
//
let result =
ASStackLayoutSpec(
direction: .vertical,
spacing: 5,
justifyContent: .start,
alignItems: .start,
children: [timestampPadding, labelPadding, imagesPadding])

return result
}
}

58 changes: 43 additions & 15 deletions nMessenger/Source/MessageNodes/ContentNodes/ContentNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,28 @@ open class ContentNode: ASDisplayNode {
// MARK: Public Parameters
/** Bubble that defines the background for the message*/
open var backgroundBubble: Bubble?


/** UIViewController that holds the cell. Allows the cell the present View Controllers. Generally used for UIMenu or UIAlert Options*/
open weak var currentViewController: UIViewController?


/** MessageConfigurationProtocol hold common definition for all messages. Defaults to **StandardMessageConfiguration***/
open var bubbleConfiguration : BubbleConfigurationProtocol = StandardBubbleConfiguration() {
didSet {
open var bubbleConfiguration : BubbleConfigurationProtocol = StandardBubbleConfiguration()
{
didSet
{
self.updateBubbleConfig(self.bubbleConfiguration)
}
}
/** Bool if the cell is an incoming or out going message.
Set backgroundBubble.bubbleColor when value is changed
*/
open var isIncomingMessage = true {
didSet {
self.backgroundBubble?.bubbleColor = isIncomingMessage ? bubbleConfiguration.getIncomingColor() : bubbleConfiguration.getOutgoingColor()

open var isIncomingMessage = true
{
didSet
{
self.updateBackgroundBubbleColor()
self.setNeedsLayout()
}
}
Expand Down Expand Up @@ -67,14 +74,23 @@ open class ContentNode: ASDisplayNode {
/** Updates the bubble config by setting all necessary properties (background bubble, bubble color, layout)
- parameter newValue: the new BubbleConfigurationProtocol
*/
open func updateBubbleConfig(_ newValue: BubbleConfigurationProtocol) {
open func updateBubbleConfig(_ newValue: BubbleConfigurationProtocol)
{
self.backgroundBubble = self.bubbleConfiguration.getBubble()

self.backgroundBubble?.bubbleColor = isIncomingMessage ? bubbleConfiguration.getIncomingColor() : bubbleConfiguration.getOutgoingColor()
self.updateBackgroundBubbleColor()

self.setNeedsLayout()
}

public func updateBackgroundBubbleColor()
{
self.backgroundBubble?.bubbleColor =
self.isIncomingMessage
? self.bubbleConfiguration.getIncomingColor()
: self.bubbleConfiguration.getOutgoingColor()
}

/**
Called during the initializer and makes sure layers are added on the main thread
*/
Expand All @@ -100,14 +116,21 @@ open class ContentNode: ASDisplayNode {
/**
Draws the content in the bubble. This is called on a background thread.
*/
open func drawRect(_ bounds: CGRect, withParameters parameters: NSObjectProtocol!,
isCancelled isCancelledBlock: asdisplaynode_iscancelled_block_t, isRasterizing: Bool) {
@objc open func drawRect(_ bounds: CGRect,
withParameters parameters: NSObjectProtocol!,
isCancelled isCancelledBlock: asdisplaynode_iscancelled_block_t,
isRasterizing: Bool)
{
// print("[NMessenger] ContentNode.drawRect | isRasterizing=\(isRasterizing)")
self.isOpaque = false
if !isRasterizing {

if !isRasterizing
{
self.calculateLayerPropertiesThatFit(bounds)

//call the main queue
DispatchQueue.main.async {
DispatchQueue.main.async
{
self.layoutLayers()
}
}
Expand Down Expand Up @@ -150,10 +173,15 @@ open class ContentNode: ASDisplayNode {
- parameter closure: Must be an ()->()
*/
open func delay(_ delay: Double, closure: @escaping ()->()) {

let timeIncrement =
Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
let absoluteTimeIncremented =
DispatchTime.now() + timeIncrement

DispatchQueue.main.asyncAfter(
deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC),
execute: closure
)
deadline: absoluteTimeIncremented,
execute: closure)
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import AsyncDisplayKit
*/
open class ImageContentNode: ContentNode {

open var imageAspectRatio: CGFloat = 4.0 / 3.0

// MARK: Public Variables
/** UIImage as the image of the cell*/
open var image: UIImage? {
Expand Down Expand Up @@ -77,7 +79,7 @@ open class ImageContentNode: ContentNode {

let width = constrainedSize.max.width
self.imageMessageNode.style.width = ASDimension(unit: .points, value: width)
self.imageMessageNode.style.height = ASDimension(unit: .points, value: width/4*3)
self.imageMessageNode.style.height = ASDimension(unit: .points, value: width/self.imageAspectRatio)
let absLayout = ASAbsoluteLayoutSpec()
absLayout.sizing = .sizeToFit
absLayout.children = [self.imageMessageNode]
Expand All @@ -99,14 +101,29 @@ open class ImageContentNode: ContentNode {
open override func messageNodeLongPressSelector(_ recognizer: UITapGestureRecognizer) {
if recognizer.state == UIGestureRecognizerState.began {

let touchLocation = recognizer.location(in: view)
let touchLocation = recognizer.location(in: self.view)
if self.imageMessageNode.frame.contains(touchLocation) {

view.becomeFirstResponder()
self.view.becomeFirstResponder()

delay(0.1, closure: {
self.delay(0.1, closure: {
let menuController = UIMenuController.shared
menuController.menuItems = [UIMenuItem(title: "Copy", action: #selector(ImageContentNode.copySelector))]

let localizedCopyTitle = NSLocalizedString(
"NMessenger.ImageContentNode.Menu.Copy",
comment: "Copy")
let copyTitle =
(localizedCopyTitle.isEmpty)
? "Copy"
: localizedCopyTitle

menuController.menuItems =
[
UIMenuItem(
title: copyTitle,
action: #selector(ImageContentNode.copySelector))
]

menuController.setTargetRect(self.imageMessageNode.frame, in: self.view)
menuController.setMenuVisible(true, animated:true)
})
Expand All @@ -118,7 +135,7 @@ open class ImageContentNode: ContentNode {
Copy Selector for UIMenuController
Puts the node's image on UIPasteboard
*/
open func copySelector() {
@objc open func copySelector() {
if let image = self.image {
UIPasteboard.general.image = image
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// MixedContentNodeWithTimestamp.swift
// nMessenger-iOS
//
// Created by Alexander Dodatko on 12/12/17.
// Copyright © 2017 Ebay Inc. All rights reserved.
//

import Foundation


open class MixedContentNodeWithTimestamp: ContentNode {

open var textNode: ASTextNode?
open var timestampNode: ASTextNode?
open var attachmentsNode: CollectionViewContentNode?

open override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {

let children: [ASLayoutElement?] = [self.timestampNode,
self.textNode,
self.attachmentsNode]

let stackSpec = ASStackLayoutSpec(direction: .vertical,
spacing: 5,
justifyContent: .start,
alignItems: .start,
children: children.flatMap { $0 })

let insets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)

let insetSpec = ASInsetLayoutSpec(insets: insets,
child: stackSpec)
return insetSpec
}

open override func messageNodeLongPressSelector(
_ recognizer: UITapGestureRecognizer)
{
// TODO: rewrite if specific menu is required for each cell
//
// fatalError("handled in MessageNode")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,26 @@ open class NetworkImageContentNode: ContentNode,ASNetworkImageNodeDelegate {
let touchLocation = recognizer.location(in: view)
if self.networkImageMessageNode.frame.contains(touchLocation) {

view.becomeFirstResponder()
self.view.becomeFirstResponder()

delay(0.1, closure: {
self.delay(0.1, closure: {
let menuController = UIMenuController.shared
menuController.menuItems = [UIMenuItem(title: "Copy", action: #selector(NetworkImageContentNode.copySelector))]

let localizedCopyTitle = NSLocalizedString(
"NMessenger.NetworkImageContentNode.Menu.Copy",
comment: "Copy")
let copyTitle =
(localizedCopyTitle.isEmpty)
? "Copy"
: localizedCopyTitle

menuController.menuItems =
[
UIMenuItem(
title: copyTitle,
action: #selector(NetworkImageContentNode.copySelector))
]

menuController.setTargetRect(self.networkImageMessageNode.frame, in: self.view)
menuController.setMenuVisible(true, animated:true)
})
Expand All @@ -123,7 +138,7 @@ open class NetworkImageContentNode: ContentNode,ASNetworkImageNodeDelegate {
Copy Selector for UIMenuController
Puts the node's image on UIPasteboard
*/
open func copySelector() {
@objc open func copySelector() {
if let image = self.networkImageMessageNode.image {
UIPasteboard.general.image = image
}
Expand Down
Loading