From 2f7880af8e70163f9a3aafe0a1d588178eccefda Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Tue, 12 Mar 2019 13:17:49 -0400
Subject: [PATCH 1/7] Fix hit testing of text layers.

---
 .../Views/ImageEditor/ImageEditorCanvasView.swift  | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift
index dbe3448a3..dba18ef70 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift
@@ -642,10 +642,24 @@ public class ImageEditorCanvasView: UIView {
         guard let sublayers = contentView.layer.sublayers else {
             return nil
         }
+
+        // First we build a map of all text layers.
+        var layerMap = [String: EditorTextLayer]()
         for layer in sublayers {
             guard let textLayer = layer as? EditorTextLayer else {
                 continue
             }
+            layerMap[textLayer.itemId] = textLayer
+        }
+
+        // The layer ordering in the model is authoritative.
+        // Iterate over the layers in _reverse_ order of which they appear
+        // in the model, so that layers "on top" are hit first.
+        for item in model.items().reversed() {
+            guard let textLayer = layerMap[item.itemId] else {
+                // Not a text layer.
+                continue
+            }
             if textLayer.hitTest(point) != nil {
                 return textLayer
             }

From 66efcb4639b75440cf84ca5d4994db232f8f4355 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Tue, 12 Mar 2019 13:27:35 -0400
Subject: [PATCH 2/7] Update rail icons.

---
 .../x-24.imageset/Contents.json               |  23 ++++++++++++++++++
 .../Images.xcassets/x-24.imageset/x-24@1x.png | Bin 0 -> 243 bytes
 .../Images.xcassets/x-24.imageset/x-24@2x.png | Bin 0 -> 398 bytes
 .../Images.xcassets/x-24.imageset/x-24@3x.png | Bin 0 -> 573 bytes
 .../AttachmentApprovalViewController.swift    |  22 +++++++++--------
 SignalMessaging/Views/GalleryRailView.swift   |   9 ++++---
 6 files changed, 40 insertions(+), 14 deletions(-)
 create mode 100644 Signal/Images.xcassets/x-24.imageset/Contents.json
 create mode 100644 Signal/Images.xcassets/x-24.imageset/x-24@1x.png
 create mode 100644 Signal/Images.xcassets/x-24.imageset/x-24@2x.png
 create mode 100644 Signal/Images.xcassets/x-24.imageset/x-24@3x.png

diff --git a/Signal/Images.xcassets/x-24.imageset/Contents.json b/Signal/Images.xcassets/x-24.imageset/Contents.json
new file mode 100644
index 000000000..1f25af162
--- /dev/null
+++ b/Signal/Images.xcassets/x-24.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "x-24@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "x-24@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "x-24@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/Signal/Images.xcassets/x-24.imageset/x-24@1x.png b/Signal/Images.xcassets/x-24.imageset/x-24@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee6d0b887443c3733f4bf3dc008a1adce365639a
GIT binary patch
literal 243
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GGLLkg|>2BR0px{zZ
z7sn8f&bOhtTn!35wXa#^ZYq~4CkHIZJIgEcH&fxt=UR_fi>^r-z4j>muhP(=B`A6@
zMkG5zJ7N#}d4>Zlbry_M>dr}>*=zbIi2c0g0`*-^VY4<UoDx;qeqpBoV+GF|%ZG~_
zr%i0jj0!*C?eRt+V}U}i;=*Jdy<6Wd1@&Hi|JSAK=RV(UJs@>WGsShchAuJR{iW<~
m>yER_Cs;lH?|)y9K|JM*R^O4Q$E1M{X7F_Nb6Mw<&;$VBSYMt1

literal 0
HcmV?d00001

diff --git a/Signal/Images.xcassets/x-24.imageset/x-24@2x.png b/Signal/Images.xcassets/x-24.imageset/x-24@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..ea502285caf8531820a4cffebcb866af3b2bc408
GIT binary patch
literal 398
zcmV;90df9`P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00009a7bBm000&x
z000&x0ZCFM@Bjb-KuJVFRA_<iS-}m1Fbs4$0V6Rgqc8&9q#LA)WcsKbHv%8QYEJU!
z0ADUZ;v^~OOp);j-TGnR1{el<qsc%@X%ZwDt(rd#q?8sSTCX(0S}SYYDDyxqh^QpU
z92*f$wR^pyXt36<yI8pe@wp%q!A%^|6hto*N3{eYZn(h284W>bfi!V8w;*bPFyWC?
z5LS4a@X95KOM1<-BQz4(0Pjyx5J(e{|41VdCQu`pAP^>?!>~qrny{|9Xltai361lc
z#Wm8|1hkG41kePe2n@fZ6psG(6RI>m#!qZC{{F*g=!q<JDG|Du3tdi!UeJVIQifjC
zhu&5Ry|EQ~Yca~^Znd1wIluVf9Zw>fnTLRL&#bj$Gc`3=U%j$ibvB^93G-~AMAJcc
sIWaMN0f1J`aZ=wK!$5Bg16@HxZ<K!I{@13q=l}o!07*qoM6N<$f@d?Gl>h($

literal 0
HcmV?d00001

diff --git a/Signal/Images.xcassets/x-24.imageset/x-24@3x.png b/Signal/Images.xcassets/x-24.imageset/x-24@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..cbb9bb263d56a3b51b69b48ace2bb48ad7eb0b3a
GIT binary patch
literal 573
zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!oCO|{#S9FJ<{->y95KI&fr0V8
zr;B4q#hkZu8aodg2(X05J6in|3!3Hasj2z!^2zcA?g#mgso%Y+c4=;c__PV4ZqF49
zRlNO9SvF_AUVYPPud72F#|Z&ONhJkmmXwYL9>EEUOhzS~0bZG&ns;5C1ExlKpPjx+
zJGj@F?Sn=;;}6CH>*_xl)1|IQot}OC<>$4ny7>>DNGiO2@I-rp%LSu`)a!v69=sO+
z<FbxliQ&yQv*KZWIeBZB!)KlecCm{&(%P;pHWNI<wKCjSX@+3X`6w3y=_U6}I}+49
zlz)jG)S2M+RkKM_f%oldF*m)MFUvz&Ci)+Ex;lni+3C|SLjgw@k9GT}Y&8&4dB1TQ
zhms?gp}^W!K?T>Dr#cjvmIQp>6ZL{q^VZy^hrgSzU7eubkbjY5&$a7ew{4&Q(T=h@
zmC8JoaiyBL#fK=182>N(ejdpvYGyt^^=k8kn1>DC=eONqkln*Kb=&giM%%d;Ocu`!
z_c+WbSrFHoJxPAatp^><uI&>|mP>V6MuwibE!$Oj*vBw`r`9vy>Z38=0?)KMAC0LB
zJ9C!1Yv*5AL-PR5XJR%-?;Ke<<936nd)sC1NgPr082$J?lrm=WZ<cvIrQdmOgNT$L
zbI^VES7vkdj1Sy&wEDC4)~x^kk~+N4V~G_Phgl4N7^5wi+4&uECjrv~gQu&X%Q~lo
FCIH1j>9_y@

literal 0
HcmV?d00001

diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift
index 40e681eda..a442a68aa 100644
--- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift
+++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift
@@ -1676,12 +1676,14 @@ public class ApprovalRailCellView: GalleryRailCellView {
             strongSelf.approvalRailCellDelegate?.approvalRailCellView(strongSelf, didRemoveItem: attachmentItem)
         }
 
-        button.setImage(#imageLiteral(resourceName: "ic_circled_x"), for: .normal)
-
-        let kInsetDistance: CGFloat = 5
-        button.imageEdgeInsets = UIEdgeInsets(top: kInsetDistance, left: kInsetDistance, bottom: kInsetDistance, right: kInsetDistance)
-
-        let kButtonWidth: CGFloat = 24 + kInsetDistance * 2
+        button.setImage(UIImage(named: "x-24")?.withRenderingMode(.alwaysTemplate), for: .normal)
+        button.tintColor = .white
+        button.layer.shadowColor = UIColor.black.cgColor
+        button.layer.shadowRadius = 2
+        button.layer.shadowOpacity = 0.66
+        button.layer.shadowOffset = .zero
+
+        let kButtonWidth: CGFloat = 24
         button.autoSetDimensions(to: CGSize(width: kButtonWidth, height: kButtonWidth))
 
         return button
@@ -1704,8 +1706,8 @@ public class ApprovalRailCellView: GalleryRailCellView {
         if isSelected {
             addSubview(deleteButton)
 
-            deleteButton.autoPinEdge(toSuperviewEdge: .top, withInset: -12)
-            deleteButton.autoPinEdge(toSuperviewEdge: .trailing, withInset: -8)
+            deleteButton.autoPinEdge(toSuperviewEdge: .top, withInset: cellBorderWidth)
+            deleteButton.autoPinEdge(toSuperviewEdge: .trailing, withInset: cellBorderWidth + 4)
         } else {
             deleteButton.removeFromSuperview()
         }
@@ -1726,8 +1728,8 @@ public class ApprovalRailCellView: GalleryRailCellView {
         if hasCaption {
             addSubview(captionIndicator)
 
-            captionIndicator.autoPinEdge(toSuperviewEdge: .top, withInset: 2)
-            captionIndicator.autoPinEdge(toSuperviewEdge: .leading, withInset: 6)
+            captionIndicator.autoPinEdge(toSuperviewEdge: .top, withInset: cellBorderWidth)
+            captionIndicator.autoPinEdge(toSuperviewEdge: .leading, withInset: cellBorderWidth + 4)
         } else {
             captionIndicator.removeFromSuperview()
         }
diff --git a/SignalMessaging/Views/GalleryRailView.swift b/SignalMessaging/Views/GalleryRailView.swift
index 66690ab2a..6f797ea6b 100644
--- a/SignalMessaging/Views/GalleryRailView.swift
+++ b/SignalMessaging/Views/GalleryRailView.swift
@@ -63,17 +63,18 @@ public class GalleryRailCellView: UIView {
 
     private(set) var isSelected: Bool = false
 
+    public let cellBorderWidth: CGFloat = 2
+
     func setIsSelected(_ isSelected: Bool) {
-        let borderWidth: CGFloat = 2
         self.isSelected = isSelected
 
         // Reserve space for the selection border whether or not the cell is selected.
-        layoutMargins = UIEdgeInsets(top: 0, left: borderWidth, bottom: 0, right: borderWidth)
+        layoutMargins = UIEdgeInsets(top: 0, left: cellBorderWidth, bottom: 0, right: cellBorderWidth)
 
         if isSelected {
             imageView.layer.borderColor = Theme.galleryHighlightColor.cgColor
-            imageView.layer.borderWidth = borderWidth
-            imageView.layer.cornerRadius = borderWidth
+            imageView.layer.borderWidth = cellBorderWidth
+            imageView.layer.cornerRadius = cellBorderWidth
         } else {
             imageView.layer.borderWidth = 0
             imageView.layer.cornerRadius = 0

From 337e32a909d259af49a7b2de6b32f6ee5050d3d4 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Tue, 12 Mar 2019 16:28:10 -0400
Subject: [PATCH 3/7] Fix a shadow.

---
 .../ViewControllers/AttachmentApprovalViewController.swift       | 1 +
 1 file changed, 1 insertion(+)

diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift
index a442a68aa..026aaa433 100644
--- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift
+++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift
@@ -1462,6 +1462,7 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
         lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor
         lengthLimitLabel.layer.shadowOffset = .zero
         lengthLimitLabel.layer.shadowOpacity = 0.8
+        lengthLimitLabel.layer.shadowRadius = 2.0
         lengthLimitLabel.isHidden = true
 
         return lengthLimitLabel

From c0ca55b1e02e3f78adbf6ab903f49874475dcf12 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Tue, 12 Mar 2019 17:04:58 -0400
Subject: [PATCH 4/7] Fix shadow on palette view.

---
 .../ImageEditor/ImageEditorPaletteView.swift  | 33 ++++++++++++-------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift
index e1c78ff24..e2382c395 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift
@@ -81,7 +81,9 @@ public class ImageEditorPaletteView: UIView {
 
     private let imageView = UIImageView()
     private let selectionView = UIView()
-    private let selectionWrapper = OWSLayerView()
+    // imageWrapper is used to host the "selection view".
+    private let imageWrapper = OWSLayerView()
+    private let shadowView = UIView()
     private var selectionConstraint: NSLayoutConstraint?
 
     private func createContents() {
@@ -89,9 +91,18 @@ public class ImageEditorPaletteView: UIView {
         self.isOpaque = false
         self.layoutMargins = .zero
 
+        shadowView.backgroundColor = .black
+        shadowView.layer.shadowColor = UIColor.black.cgColor
+        shadowView.layer.shadowRadius = 2.0
+        shadowView.layer.shadowOpacity = 0.33
+        shadowView.layer.shadowOffset = .zero
+        addSubview(shadowView)
+
         if let image = ImageEditorPaletteView.buildPaletteGradientImage() {
             imageView.image = image
-            imageView.layer.cornerRadius = image.size.width * 0.5
+            let imageRadius = image.size.width * 0.5
+            imageView.layer.cornerRadius = imageRadius
+            shadowView.layer.cornerRadius = imageRadius
             imageView.clipsToBounds = true
         } else {
             owsFailDebug("Missing image.")
@@ -102,29 +113,27 @@ public class ImageEditorPaletteView: UIView {
         imageView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin))
         imageView.layer.borderColor = UIColor.white.cgColor
         imageView.layer.borderWidth = CGHairlineWidth()
-        imageView.layer.shadowColor = UIColor.black.cgColor
-        imageView.layer.shadowRadius = 2.0
-        imageView.layer.shadowOpacity = 0.33
-        imageView.layer.shadowOffset = .zero
-        selectionWrapper.layoutCallback = { [weak self] (view) in
+
+        imageWrapper.layoutCallback = { [weak self] (view) in
             guard let strongSelf = self else {
                 return
             }
             strongSelf.updateState()
         }
-        self.addSubview(selectionWrapper)
-        selectionWrapper.autoPin(toEdgesOf: imageView)
+        addSubview(imageWrapper)
+        imageWrapper.autoPin(toEdgesOf: imageView)
+        shadowView.autoPin(toEdgesOf: imageView)
 
         selectionView.addBorder(with: .white)
         selectionView.layer.cornerRadius = selectionSize / 2
         selectionView.autoSetDimensions(to: CGSize(width: selectionSize, height: selectionSize))
-        selectionWrapper.addSubview(selectionView)
+        imageWrapper.addSubview(selectionView)
         selectionView.autoHCenterInSuperview()
 
         // There must be a better way to pin the selection view's location,
         // but I can't find it.
         let selectionConstraint = NSLayoutConstraint(item: selectionView,
-                                                     attribute: .centerY, relatedBy: .equal, toItem: selectionWrapper, attribute: .top, multiplier: 1, constant: 0)
+                                                     attribute: .centerY, relatedBy: .equal, toItem: imageWrapper, attribute: .top, multiplier: 1, constant: 0)
         selectionConstraint.autoInstall()
         self.selectionConstraint = selectionConstraint
 
@@ -201,7 +210,7 @@ public class ImageEditorPaletteView: UIView {
             owsFailDebug("Missing selectionConstraint.")
             return
         }
-        let selectionY = selectionWrapper.height() * selectedValue.palettePhase
+        let selectionY = imageWrapper.height() * selectedValue.palettePhase
         selectionConstraint.constant = selectionY
     }
 

From 75cfd979ba5400c81baf0ffb82d383c58e3dfe62 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Tue, 12 Mar 2019 17:05:17 -0400
Subject: [PATCH 5/7] Modify brush stroke width to reflect current scale.

---
 .../ImageEditor/ImageEditorBrushViewController.swift      | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift b/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift
index af56c8db1..ba47cb82d 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift
@@ -165,9 +165,9 @@ public class ImageEditorBrushViewController: OWSViewController {
             let view = self.canvasView.gestureReferenceView
             let viewBounds = view.bounds
             let newSample = ImageEditorCanvasView.locationImageUnit(forLocationInView: locationInView,
-                                                              viewBounds: viewBounds,
-                                                              model: self.model,
-                                                              transform: self.model.currentTransform())
+                                                                    viewBounds: viewBounds,
+                                                                    model: self.model,
+                                                                    transform: self.model.currentTransform())
 
             if let prevSample = self.currentStrokeSamples.last,
                 prevSample == newSample {
@@ -179,7 +179,7 @@ public class ImageEditorBrushViewController: OWSViewController {
 
         let strokeColor = paletteView.selectedValue.color
         // TODO: Tune stroke width.
-        let unitStrokeWidth = ImageEditorStrokeItem.defaultUnitStrokeWidth()
+        let unitStrokeWidth = ImageEditorStrokeItem.defaultUnitStrokeWidth() / self.model.currentTransform().scaling
 
         switch gestureRecognizer.state {
         case .began:

From fedbe3a5d057c3f285c372d8b32add7011723f95 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Tue, 12 Mar 2019 17:08:07 -0400
Subject: [PATCH 6/7] Fix shadow on palette view.

---
 SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift
index e2382c395..746ba5303 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift
@@ -111,8 +111,7 @@ public class ImageEditorPaletteView: UIView {
         // We use an invisible margin to expand the hot area of this control.
         let margin: CGFloat = 20
         imageView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin))
-        imageView.layer.borderColor = UIColor.white.cgColor
-        imageView.layer.borderWidth = CGHairlineWidth()
+        imageView.addBorder(with: .white)
 
         imageWrapper.layoutCallback = { [weak self] (view) in
             guard let strongSelf = self else {

From d6c91c27536ede1462b9d19280d278d38c371c69 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Wed, 13 Mar 2019 11:40:43 -0400
Subject: [PATCH 7/7] Respond to CR.

---
 .../Views/ImageEditor/ImageEditorBrushViewController.swift       | 1 -
 1 file changed, 1 deletion(-)

diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift b/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift
index ba47cb82d..4281208dc 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorBrushViewController.swift
@@ -178,7 +178,6 @@ public class ImageEditorBrushViewController: OWSViewController {
         }
 
         let strokeColor = paletteView.selectedValue.color
-        // TODO: Tune stroke width.
         let unitStrokeWidth = ImageEditorStrokeItem.defaultUnitStrokeWidth() / self.model.currentTransform().scaling
 
         switch gestureRecognizer.state {