diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj
index 6941e6a98..ff258445f 100644
--- a/Signal.xcodeproj/project.pbxproj
+++ b/Signal.xcodeproj/project.pbxproj
@@ -164,6 +164,8 @@
 		347850711FDAEB17007B8332 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 3478506F1FDAEB16007B8332 /* OWSUserProfile.m */; };
 		347850721FDAEB17007B8332 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 347850701FDAEB16007B8332 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		348BB254209CD4B80047AEC2 /* ContactFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348BB253209CD4B80047AEC2 /* ContactFieldView.swift */; };
+		348BB25A209CF8E50047AEC2 /* TappableStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348BB258209CF8E40047AEC2 /* TappableStackView.swift */; };
+		348BB25B209CF8E50047AEC2 /* TappableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348BB259209CF8E50047AEC2 /* TappableView.swift */; };
 		3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496744C2076768700080B5F /* OWSMessageBubbleView.m */; };
 		3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496744E2076ACCE00080B5F /* LongTextViewController.swift */; };
 		34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; };
@@ -762,6 +764,8 @@
 		3478506F1FDAEB16007B8332 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUserProfile.m; sourceTree = "<group>"; };
 		347850701FDAEB16007B8332 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUserProfile.h; sourceTree = "<group>"; };
 		348BB253209CD4B80047AEC2 /* ContactFieldView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContactFieldView.swift; path = SignalMessaging/attachments/ContactFieldView.swift; sourceTree = SOURCE_ROOT; };
+		348BB258209CF8E40047AEC2 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = SignalMessaging/Views/TappableStackView.swift; sourceTree = SOURCE_ROOT; };
+		348BB259209CF8E50047AEC2 /* TappableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableView.swift; path = SignalMessaging/Views/TappableView.swift; sourceTree = SOURCE_ROOT; };
 		348F2EAD1F0D21BC00D4ECE0 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceSleepManager.swift; sourceTree = "<group>"; };
 		3495BC911F1426B800B478F5 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = translations/ar.lproj/Localizable.strings; sourceTree = "<group>"; };
 		3496744B2076768600080B5F /* OWSMessageBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageBubbleView.h; sourceTree = "<group>"; };
@@ -1586,15 +1590,17 @@
 			isa = PBXGroup;
 			children = (
 				45F3AEB51DFDE7900080CE33 /* AvatarImageView.swift */,
-				76EB052E18170B33006006FC /* ContactTableViewCell.h */,
-				76EB052F18170B33006006FC /* ContactTableViewCell.m */,
+				346129D11FD2085A00532771 /* CommonStrings.swift */,
 				340CB2221EAC155C0001CAA1 /* ContactsViewHelper.h */,
 				340CB2231EAC155C0001CAA1 /* ContactsViewHelper.m */,
-				346129D11FD2085A00532771 /* CommonStrings.swift */,
+				76EB052E18170B33006006FC /* ContactTableViewCell.h */,
+				76EB052F18170B33006006FC /* ContactTableViewCell.m */,
 				45BE4EA12012AD2000935E59 /* DisappearingTimerConfigurationView.swift */,
 				451573952061B49500803601 /* GradientView.swift */,
 				346129CF1FD207F200532771 /* OWSAlerts.swift */,
 				454A965E1FD60EA2008D2A0E /* OWSFlatButton.swift */,
+				348BB258209CF8E40047AEC2 /* TappableStackView.swift */,
+				348BB259209CF8E50047AEC2 /* TappableView.swift */,
 				3400C7971EAFB772008A8584 /* ThreadViewHelper.h */,
 				3400C7981EAFB772008A8584 /* ThreadViewHelper.m */,
 			);
@@ -3083,6 +3089,8 @@
 				451F8A461FD715BA005CB9DA /* OWSGroupAvatarBuilder.m in Sources */,
 				347850591FD9972E007B8332 /* SwiftSingletons.swift in Sources */,
 				344F248720069ECB00CFB4F4 /* ModalActivityIndicatorViewController.swift in Sources */,
+				348BB25B209CF8E50047AEC2 /* TappableView.swift in Sources */,
+				348BB25A209CF8E50047AEC2 /* TappableStackView.swift in Sources */,
 				346129961FD1E30000532771 /* OWSDatabaseMigration.m in Sources */,
 				344D6CEC20069E070042AF96 /* NewNonContactConversationViewController.m in Sources */,
 				346129FB1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.m in Sources */,
diff --git a/Signal/src/ViewControllers/ContactViewController.swift b/Signal/src/ViewControllers/ContactViewController.swift
index 9914c33e5..425a58b0e 100644
--- a/Signal/src/ViewControllers/ContactViewController.swift
+++ b/Signal/src/ViewControllers/ContactViewController.swift
@@ -9,36 +9,6 @@ import Reachability
 import ContactsUI
 import MessageUI
 
-class TappableView: UIView {
-    let actionBlock : (() -> Void)
-
-    // MARK: - Initializers
-
-    @available(*, unavailable, message: "use other constructor instead.")
-    required init?(coder aDecoder: NSCoder) {
-        fatalError("Unimplemented")
-    }
-
-    required init(actionBlock : @escaping () -> Void) {
-        self.actionBlock = actionBlock
-        super.init(frame: CGRect.zero)
-
-        self.isUserInteractionEnabled = true
-        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(wasTapped)))
-    }
-
-    func wasTapped(sender: UIGestureRecognizer) {
-        Logger.info("\(logTag) \(#function)")
-
-        guard sender.state == .recognized else {
-            return
-        }
-        actionBlock()
-    }
-}
-
-// MARK: -
-
 class ContactViewController: OWSViewController, CNContactViewControllerDelegate {
 
     enum ContactViewMode {
@@ -372,37 +342,35 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
 //        }
 
         for phoneNumber in contactShare.phoneNumbers {
-            let formattedPhoneNumber = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber.phoneNumber)
-
-            rows.append(createSimpleFieldRow(name: phoneNumber.localizedLabel(),
-                                             value: formattedPhoneNumber,
-                                             actionBlock: {
-                                                guard let url = NSURL(string: "tel:\(phoneNumber.phoneNumber)") else {
-                                                    owsFail("\(ContactViewController.logTag) could not open phone number.")
-                                                    return
-                                                }
-                                                UIApplication.shared.openURL(url as URL)
+            rows.append(ContactFieldView.contactFieldView(forPhoneNumber: phoneNumber,
+                                                          layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin),
+                                                          actionBlock: {
+                                                            guard let url = NSURL(string: "tel:\(phoneNumber.phoneNumber)") else {
+                                                                owsFail("\(ContactViewController.logTag) could not open phone number.")
+                                                                return
+                                                            }
+                                                            UIApplication.shared.openURL(url as URL)
             }))
         }
 
         for email in contactShare.emails {
-            rows.append(createSimpleFieldRow(name: email.localizedLabel(),
-                                        value: email.email,
-                                        actionBlock: {
-                                            guard let url = NSURL(string: "mailto:\(email.email)") else {
-                                                owsFail("\(ContactViewController.logTag) could not open email.")
-                                                return
-                                            }
-                                            UIApplication.shared.openURL(url as URL)
+            rows.append(ContactFieldView.contactFieldView(forEmail: email,
+                                                          layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin),
+                                                          actionBlock: {
+                                                            guard let url = NSURL(string: "mailto:\(email.email)") else {
+                                                                owsFail("\(ContactViewController.logTag) could not open email.")
+                                                                return
+                                                            }
+                                                            UIApplication.shared.openURL(url as URL)
             }))
         }
 
         for address in contactShare.addresses {
-            rows.append(createAddressFieldRow(name: address.localizedLabel(),
-                                        address: address,
-                                        actionBlock: { [weak self] _ in
-                                            guard let strongSelf = self else { return }
-                                            strongSelf.didPressAddress(address: address)
+            rows.append(ContactFieldView.contactFieldView(forAddress: address,
+                                                          layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin),
+                                                          actionBlock: { [weak self] _ in
+                                                            guard let strongSelf = self else { return }
+                                                            strongSelf.didPressAddress(address: address)
             }))
         }
 
@@ -432,112 +400,6 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
         return row
     }
 
-    private func createSimpleFieldRow(name: String, value: String?, actionBlock : @escaping () -> Void) -> UIView {
-        let row = TappableView(actionBlock: actionBlock)
-        row.layoutMargins.left = 0
-        row.layoutMargins.right = 0
-
-        let stackView = UIStackView()
-        stackView.axis = .vertical
-        stackView.alignment = .leading
-        stackView.spacing = 3
-        row.addSubview(stackView)
-        stackView.autoPinTopToSuperviewMargin()
-        stackView.autoPinBottomToSuperviewMargin()
-        stackView.autoPinLeadingToSuperviewMargin(withInset: hMargin)
-        stackView.autoPinTrailingToSuperviewMargin(withInset: hMargin)
-
-        let nameLabel = UILabel()
-        nameLabel.text = name
-        nameLabel.font = UIFont.ows_dynamicTypeSubheadline
-        nameLabel.textColor = UIColor.black
-        nameLabel.lineBreakMode = .byTruncatingTail
-        stackView.addArrangedSubview(nameLabel)
-
-        let valueLabel = UILabel()
-        valueLabel.text = value
-        valueLabel.font = UIFont.ows_dynamicTypeBody
-        valueLabel.textColor = UIColor.ows_materialBlue
-        valueLabel.lineBreakMode = .byTruncatingTail
-        stackView.addArrangedSubview(valueLabel)
-
-        return row
-    }
-
-    private func createAddressFieldRow(name: String, address: OWSContactAddress, actionBlock : @escaping () -> Void) -> UIView {
-        let row = TappableView(actionBlock: actionBlock)
-        row.layoutMargins.left = 0
-        row.layoutMargins.right = 0
-
-        let stackView = UIStackView()
-        stackView.axis = .vertical
-        stackView.alignment = .leading
-        stackView.spacing = 3
-        stackView.layoutMargins = .zero
-        row.addSubview(stackView)
-        stackView.autoPinTopToSuperviewMargin()
-        stackView.autoPinBottomToSuperviewMargin()
-        stackView.autoPinLeadingToSuperviewMargin(withInset: hMargin)
-        stackView.autoPinTrailingToSuperviewMargin(withInset: hMargin)
-
-        let nameLabel = UILabel()
-        nameLabel.text = name
-        nameLabel.font = UIFont.ows_dynamicTypeSubheadline
-        nameLabel.textColor = UIColor.black
-        nameLabel.lineBreakMode = .byTruncatingTail
-        stackView.addArrangedSubview(nameLabel)
-
-        let tryToAddNameValue: ((String, String?) -> Void) = { (propertyName, propertyValue) in
-            guard let propertyValue = propertyValue else {
-                return
-            }
-            guard propertyValue.count > 0 else {
-                return
-            }
-
-            let row = UIStackView()
-            row.axis = .horizontal
-            row.alignment = .leading
-            row.spacing = 10
-            row.layoutMargins = .zero
-
-            let nameLabel = UILabel()
-            nameLabel.text = propertyName
-            nameLabel.font = UIFont.ows_dynamicTypeBody
-            nameLabel.textColor = UIColor.black
-            nameLabel.lineBreakMode = .byTruncatingTail
-            row.addArrangedSubview(nameLabel)
-            nameLabel.setContentHuggingHigh()
-            nameLabel.setCompressionResistanceHigh()
-
-            let valueLabel = UILabel()
-            valueLabel.text = propertyValue
-            valueLabel.font = UIFont.ows_dynamicTypeBody
-            valueLabel.textColor = UIColor.ows_materialBlue
-            valueLabel.lineBreakMode = .byTruncatingTail
-            row.addArrangedSubview(valueLabel)
-
-            stackView.addArrangedSubview(row)
-        }
-
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_STREET", comment: "Label for the 'street' field of a contact's address."),
-                          address.street)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POBOX", comment: "Label for the 'pobox' field of a contact's address."),
-                          address.pobox)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_NEIGHBORHOOD", comment: "Label for the 'neighborhood' field of a contact's address."),
-                          address.neighborhood)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_CITY", comment: "Label for the 'city' field of a contact's address."),
-                          address.city)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_REGION", comment: "Label for the 'region' field of a contact's address."),
-                          address.region)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POSTCODE", comment: "Label for the 'postcode' field of a contact's address."),
-                          address.postcode)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_COUNTRY", comment: "Label for the 'country' field of a contact's address."),
-                          address.country)
-
-        return row
-    }
-
     // TODO: Use real assets.
     private func createCircleActionButton(text: String, actionBlock : @escaping () -> Void) -> UIView {
         let buttonSize = CGFloat(50)
diff --git a/Signal/src/ViewControllers/ContactsPicker.swift b/Signal/src/ViewControllers/ContactsPicker.swift
index 24c49bbd2..255c9c9bb 100644
--- a/Signal/src/ViewControllers/ContactsPicker.swift
+++ b/Signal/src/ViewControllers/ContactsPicker.swift
@@ -244,6 +244,8 @@ public class ContactsPicker: OWSViewController, UITableViewDelegate, UITableView
     }
 
     open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        Logger.verbose("\(logTag) \(#function)")
+
         let cell = tableView.cellForRow(at: indexPath) as! ContactCell
         let selectedContact = cell.contact!
 
diff --git a/SignalMessaging/Views/TappableStackView.swift b/SignalMessaging/Views/TappableStackView.swift
new file mode 100644
index 000000000..8fa9e212e
--- /dev/null
+++ b/SignalMessaging/Views/TappableStackView.swift
@@ -0,0 +1,33 @@
+//
+//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
+//
+
+import Foundation
+
+public class TappableStackView: UIStackView {
+    let actionBlock : (() -> Void)
+
+    // MARK: - Initializers
+
+    @available(*, unavailable, message: "use other constructor instead.")
+    public required init(coder aDecoder: NSCoder) {
+        fatalError("Unimplemented")
+    }
+
+    public required init(actionBlock : @escaping () -> Void) {
+        self.actionBlock = actionBlock
+        super.init(frame: CGRect.zero)
+
+        self.isUserInteractionEnabled = true
+        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(wasTapped)))
+    }
+
+    func wasTapped(sender: UIGestureRecognizer) {
+        Logger.info("\(logTag) \(#function)")
+
+        guard sender.state == .recognized else {
+            return
+        }
+        actionBlock()
+    }
+}
diff --git a/SignalMessaging/Views/TappableView.swift b/SignalMessaging/Views/TappableView.swift
new file mode 100644
index 000000000..e440e6554
--- /dev/null
+++ b/SignalMessaging/Views/TappableView.swift
@@ -0,0 +1,33 @@
+//
+//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
+//
+
+import Foundation
+
+public class TappableView: UIView {
+    let actionBlock : (() -> Void)
+
+    // MARK: - Initializers
+
+    @available(*, unavailable, message: "use other constructor instead.")
+    public required init?(coder aDecoder: NSCoder) {
+        fatalError("Unimplemented")
+    }
+
+    public required init(actionBlock : @escaping () -> Void) {
+        self.actionBlock = actionBlock
+        super.init(frame: CGRect.zero)
+
+        self.isUserInteractionEnabled = true
+        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(wasTapped)))
+    }
+
+    func wasTapped(sender: UIGestureRecognizer) {
+        Logger.info("\(logTag) \(#function)")
+
+        guard sender.state == .recognized else {
+            return
+        }
+        actionBlock()
+    }
+}
diff --git a/SignalMessaging/attachments/ApproveContactShareViewController.swift b/SignalMessaging/attachments/ApproveContactShareViewController.swift
index 597c195cc..141466285 100644
--- a/SignalMessaging/attachments/ApproveContactShareViewController.swift
+++ b/SignalMessaging/attachments/ApproveContactShareViewController.swift
@@ -97,7 +97,7 @@ class ContactShareAddress: ContactShareFieldBase<OWSContactAddress> {
 
 // MARK: -
 
-class ContactShareFieldView: UIView {
+class ContactShareFieldView: UIStackView {
 
     let field: ContactShareField
 
@@ -108,7 +108,7 @@ class ContactShareFieldView: UIView {
     // MARK: - Initializers
 
     @available(*, unavailable, message: "use init(call:) constructor instead.")
-    required init?(coder aDecoder: NSCoder) {
+    required init(coder aDecoder: NSCoder) {
         fatalError("Unimplemented")
     }
 
@@ -125,11 +125,14 @@ class ContactShareFieldView: UIView {
     }
 
     let hSpacing = CGFloat(10)
-    let hMargin = CGFloat(0)
+    let hMargin = CGFloat(16)
 
     func createContents() {
-        self.layoutMargins.left = 0
-        self.layoutMargins.right = 0
+        self.axis = .horizontal
+        self.spacing = hSpacing
+        self.alignment = .center
+        self.layoutMargins = UIEdgeInsets(top: 0, left: hMargin, bottom: 0, right: hMargin)
+        self.isLayoutMarginsRelativeArrangement = true
 
         let checkbox = UIButton(type: .custom)
         self.checkbox = checkbox
@@ -142,28 +145,12 @@ class ContactShareFieldView: UIView {
         checkbox.isSelected = field.isIncluded()
         // Disable the checkbox; the entire row is hot.
         checkbox.isUserInteractionEnabled = false
-        addSubview(checkbox)
-        checkbox.autoPinEdge(toSuperviewEdge: .leading, withInset: hMargin)
-        checkbox.autoVCenterInSuperview()
+        self.addArrangedSubview(checkbox)
         checkbox.setCompressionResistanceHigh()
         checkbox.setContentHuggingHigh()
 
-        let nameLabel = UILabel()
-        nameLabel.text = field.localizedLabel()
-        nameLabel.font = UIFont.ows_dynamicTypeCaption1
-        nameLabel.textColor = UIColor.black
-        nameLabel.lineBreakMode = .byTruncatingTail
-        addSubview(nameLabel)
-        nameLabel.autoPinTopToSuperviewMargin()
-        nameLabel.autoPinLeading(toTrailingEdgeOf: checkbox, offset: hSpacing)
-        nameLabel.autoPinTrailingToSuperviewMargin(withInset: hMargin)
-
         let previewView = previewViewBlock()
-        addSubview(previewView)
-        previewView.autoPinEdge(.top, to: .bottom, of: nameLabel, withOffset: 3)
-        previewView.autoPinBottomToSuperviewMargin()
-        previewView.autoPinLeading(toTrailingEdgeOf: checkbox, offset: hSpacing)
-        previewView.autoPinTrailingToSuperviewMargin(withInset: hMargin)
+        self.addArrangedSubview(previewView)
     }
 
     func wasTapped(sender: UIGestureRecognizer) {
@@ -215,27 +202,26 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
 
         // TODO: Avatar
 
+        let previewInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 0)
+
         for phoneNumber in contactShare.phoneNumbers {
             let field = ContactSharePhoneNumber(phoneNumber)
-            let fieldView = ContactShareFieldView(field: field, previewViewBlock: { [weak self] _ in
-                guard let strongSelf = self else { return UIView() }
-                return strongSelf.previewView(forPhoneNumber: phoneNumber)
+            let fieldView = ContactShareFieldView(field: field, previewViewBlock: {
+                return ContactFieldView.contactFieldView(forPhoneNumber: phoneNumber, layoutMargins: previewInsets, actionBlock: nil)
             })
             fieldViews.append(fieldView)
         }
         for email in contactShare.emails {
             let field = ContactShareEmail(email)
-            let fieldView = ContactShareFieldView(field: field, previewViewBlock: { [weak self] _ in
-                guard let strongSelf = self else { return UIView() }
-                return strongSelf.previewView(forEmail: email)
+            let fieldView = ContactShareFieldView(field: field, previewViewBlock: {
+                return ContactFieldView.contactFieldView(forEmail: email, layoutMargins: previewInsets, actionBlock: nil)
             })
             fieldViews.append(fieldView)
         }
         for address in contactShare.addresses {
             let field = ContactShareAddress(address)
-            let fieldView = ContactShareFieldView(field: field, previewViewBlock: { [weak self] _ in
-                guard let strongSelf = self else { return UIView() }
-                return strongSelf.previewView(forAddress: address)
+            let fieldView = ContactShareFieldView(field: field, previewViewBlock: {
+                return ContactFieldView.contactFieldView(forAddress: address, layoutMargins: previewInsets, actionBlock: nil)
             })
             fieldViews.append(fieldView)
         }
@@ -347,126 +333,33 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
     func createNameRow() -> UIView {
         let nameVMargin = CGFloat(16)
 
-        let row = UIView()
-        row.layoutMargins = UIEdgeInsets(top: nameVMargin, left: 0, bottom: nameVMargin, right: 0)
+        let stackView = TappableStackView(actionBlock: { [weak self] _ in
+            guard let strongSelf = self else { return }
+            strongSelf.didPressEditName()
+        })
 
-        let stackView = UIStackView()
         stackView.axis = .horizontal
         stackView.alignment = .center
-        stackView.layoutMargins = .zero
+        stackView.layoutMargins = UIEdgeInsets(top: nameVMargin, left: hMargin, bottom: nameVMargin, right: hMargin)
         stackView.spacing = 10
-        row.addSubview(stackView)
-        stackView.autoPinEdgesToSuperviewMargins()
+        stackView.isLayoutMarginsRelativeArrangement = true
 
         let nameLabel = UILabel()
         self.nameLabel = nameLabel
         nameLabel.text = contactShare.displayName
-        nameLabel.font = UIFont.ows_dynamicTypeBody
-        nameLabel.textColor = UIColor.ows_materialBlue
+        nameLabel.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight()
+        nameLabel.textColor = UIColor.black
         nameLabel.lineBreakMode = .byTruncatingTail
         stackView.addArrangedSubview(nameLabel)
 
         let editNameLabel = UILabel()
         editNameLabel.text = NSLocalizedString("CONTACT_EDIT_NAME_BUTTON", comment: "Label for the 'edit name' button in the contact share approval view.")
-        editNameLabel.font = UIFont.ows_dynamicTypeCaption1
-        editNameLabel.textColor = UIColor.black
+        editNameLabel.font = UIFont.ows_dynamicTypeBody
+        editNameLabel.textColor = UIColor.ows_materialBlue
         stackView.addArrangedSubview(editNameLabel)
         editNameLabel.setContentHuggingHigh()
         editNameLabel.setCompressionResistanceHigh()
 
-        // Icon
-        let iconName = (self.view.isRTL() ? "system_disclosure_indicator_rtl" : "system_disclosure_indicator")
-        guard let iconImage = UIImage(named: iconName) else {
-            owsFail("\(logTag) missing icon.")
-            return row
-        }
-        let iconView = UIImageView(image: iconImage.withRenderingMode(.alwaysTemplate))
-        iconView.contentMode = .scaleAspectFit
-        iconView.tintColor = UIColor.black.withAlphaComponent(0.6)
-        stackView.addArrangedSubview(iconView)
-        iconView.setContentHuggingHigh()
-        iconView.setCompressionResistanceHigh()
-
-        row.isUserInteractionEnabled = true
-        row.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didPressEditName)))
-
-        return row
-    }
-
-    func previewView(forPhoneNumber phoneNumber: OWSContactPhoneNumber) -> UIView {
-        let label = UILabel()
-        label.text = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber.phoneNumber)
-        label.font = UIFont.ows_dynamicTypeCaption1
-        label.textColor = UIColor.ows_materialBlue
-        label.lineBreakMode = .byTruncatingTail
-        return label
-    }
-
-    func previewView(forEmail email: OWSContactEmail) -> UIView {
-        let label = UILabel()
-        label.text = email.email
-        label.font = UIFont.ows_dynamicTypeCaption1
-        label.textColor = UIColor.ows_materialBlue
-        label.lineBreakMode = .byTruncatingTail
-        return label
-    }
-
-    func previewView(forAddress address: OWSContactAddress) -> UIView {
-
-        let stackView = UIStackView()
-        stackView.axis = .vertical
-        stackView.alignment = .leading
-        stackView.spacing = 0
-        stackView.layoutMargins = .zero
-
-        let tryToAddNameValue: ((String, String?) -> Void) = { (name, value) in
-            guard let value = value else {
-                return
-            }
-            guard value.count > 0 else {
-                return
-            }
-            let row = UIView.container()
-
-            let nameLabel = UILabel()
-            nameLabel.text = name
-            nameLabel.font = UIFont.ows_dynamicTypeCaption1
-            nameLabel.textColor = UIColor.black
-            nameLabel.lineBreakMode = .byTruncatingTail
-            row.addSubview(nameLabel)
-            nameLabel.autoPinLeadingToSuperviewMargin()
-            nameLabel.autoPinHeightToSuperview()
-            nameLabel.setContentHuggingHigh()
-            nameLabel.setCompressionResistanceHigh()
-
-            let valueLabel = UILabel()
-            valueLabel.text = value
-            valueLabel.font = UIFont.ows_dynamicTypeCaption1
-            valueLabel.textColor = UIColor.ows_materialBlue
-            valueLabel.lineBreakMode = .byTruncatingTail
-            row.addSubview(valueLabel)
-            valueLabel.autoPinLeading(toTrailingEdgeOf: nameLabel, offset: 10)
-            valueLabel.autoPinTrailingToSuperviewMargin()
-            valueLabel.autoPinHeightToSuperview()
-
-            stackView.addArrangedSubview(row)
-        }
-
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_STREET", comment: "Label for the 'street' field of a contact's address."),
-                          address.street)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POBOX", comment: "Label for the 'pobox' field of a contact's address."),
-                          address.pobox)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_NEIGHBORHOOD", comment: "Label for the 'neighborhood' field of a contact's address."),
-                          address.neighborhood)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_CITY", comment: "Label for the 'city' field of a contact's address."),
-                          address.city)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_REGION", comment: "Label for the 'region' field of a contact's address."),
-                          address.region)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POSTCODE", comment: "Label for the 'postcode' field of a contact's address."),
-                          address.postcode)
-        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_COUNTRY", comment: "Label for the 'country' field of a contact's address."),
-                          address.country)
-
         return stackView
     }
 
diff --git a/SignalMessaging/attachments/ContactFieldView.swift b/SignalMessaging/attachments/ContactFieldView.swift
index ac4ef71f1..0a64b0f63 100644
--- a/SignalMessaging/attachments/ContactFieldView.swift
+++ b/SignalMessaging/attachments/ContactFieldView.swift
@@ -44,8 +44,8 @@ public class ContactFieldView: UIView {
                 addSpacerRow()
             }
             self.addSubview(row)
-            row.autoPinLeadingToSuperviewMargin(withInset: hMargin)
-            row.autoPinTrailingToSuperviewMargin(withInset: hMargin)
+            row.autoPinLeadingToSuperviewMargin()
+            row.autoPinTrailingToSuperviewMargin()
             if let lastRow = lastRow {
                 row.autoPinEdge(.top, to: .bottom, of: lastRow, withOffset: 0)
             } else {
@@ -60,4 +60,114 @@ public class ContactFieldView: UIView {
 
         lastRow?.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0)
     }
+
+    public class func contactFieldView(forPhoneNumber phoneNumber: OWSContactPhoneNumber, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView {
+        let formattedPhoneNumber = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber.phoneNumber)
+        return simpleFieldView(name: phoneNumber.localizedLabel(), value: formattedPhoneNumber, layoutMargins: layoutMargins, actionBlock: actionBlock)
+    }
+
+    public class func contactFieldView(forEmail email: OWSContactEmail, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView {
+        return simpleFieldView(name: email.localizedLabel(), value: email.email, layoutMargins: layoutMargins, actionBlock: actionBlock)
+    }
+
+    private class func simpleFieldView(name: String, value: String?, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView {
+        var stackView: UIStackView
+        if let actionBlock = actionBlock {
+            stackView = TappableStackView(actionBlock: actionBlock)
+        } else {
+            stackView = UIStackView()
+        }
+        stackView.axis = .vertical
+        stackView.alignment = .leading
+        stackView.spacing = 3
+        stackView.layoutMargins = layoutMargins
+        stackView.isLayoutMarginsRelativeArrangement = true
+
+        let nameLabel = UILabel()
+        nameLabel.text = name
+        nameLabel.font = UIFont.ows_dynamicTypeSubheadline
+        nameLabel.textColor = UIColor.black
+        nameLabel.lineBreakMode = .byTruncatingTail
+        stackView.addArrangedSubview(nameLabel)
+
+        let valueLabel = UILabel()
+        valueLabel.text = value
+        valueLabel.font = UIFont.ows_dynamicTypeBody
+        valueLabel.textColor = UIColor.ows_materialBlue
+        valueLabel.lineBreakMode = .byTruncatingTail
+        stackView.addArrangedSubview(valueLabel)
+
+        return stackView
+    }
+
+    public class func contactFieldView(forAddress address: OWSContactAddress, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView {
+        var stackView: UIStackView
+        if let actionBlock = actionBlock {
+             stackView = TappableStackView(actionBlock: actionBlock)
+        } else {
+            stackView = UIStackView()
+        }
+        stackView.axis = .vertical
+        stackView.alignment = .leading
+        stackView.spacing = 3
+        stackView.layoutMargins = layoutMargins
+        stackView.isLayoutMarginsRelativeArrangement = true
+
+        let nameLabel = UILabel()
+        nameLabel.text = address.localizedLabel()
+        nameLabel.font = UIFont.ows_dynamicTypeSubheadline
+        nameLabel.textColor = UIColor.black
+        nameLabel.lineBreakMode = .byTruncatingTail
+        stackView.addArrangedSubview(nameLabel)
+
+        let tryToAddNameValue: ((String, String?) -> Void) = { (propertyName, propertyValue) in
+            guard let propertyValue = propertyValue else {
+                return
+            }
+            guard propertyValue.count > 0 else {
+                return
+            }
+
+            let row = UIStackView()
+            row.axis = .horizontal
+            row.alignment = .leading
+            row.spacing = 10
+            row.layoutMargins = .zero
+
+            let nameLabel = UILabel()
+            nameLabel.text = propertyName
+            nameLabel.font = UIFont.ows_dynamicTypeBody
+            nameLabel.textColor = UIColor.black
+            nameLabel.lineBreakMode = .byTruncatingTail
+            row.addArrangedSubview(nameLabel)
+            nameLabel.setContentHuggingHigh()
+            nameLabel.setCompressionResistanceHigh()
+
+            let valueLabel = UILabel()
+            valueLabel.text = propertyValue
+            valueLabel.font = UIFont.ows_dynamicTypeBody
+            valueLabel.textColor = UIColor.ows_materialBlue
+            valueLabel.lineBreakMode = .byTruncatingTail
+            row.addArrangedSubview(valueLabel)
+
+            stackView.addArrangedSubview(row)
+        }
+
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_STREET", comment: "Label for the 'street' field of a contact's address."),
+                          address.street)
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POBOX", comment: "Label for the 'pobox' field of a contact's address."),
+                          address.pobox)
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_NEIGHBORHOOD", comment: "Label for the 'neighborhood' field of a contact's address."),
+                          address.neighborhood)
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_CITY", comment: "Label for the 'city' field of a contact's address."),
+                          address.city)
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_REGION", comment: "Label for the 'region' field of a contact's address."),
+                          address.region)
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POSTCODE", comment: "Label for the 'postcode' field of a contact's address."),
+                          address.postcode)
+        tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_COUNTRY", comment: "Label for the 'country' field of a contact's address."),
+                          address.country)
+
+        return stackView
+    }
 }
diff --git a/SignalMessaging/categories/UIView+OWS.m b/SignalMessaging/categories/UIView+OWS.m
index a31942e27..14e68d3da 100644
--- a/SignalMessaging/categories/UIView+OWS.m
+++ b/SignalMessaging/categories/UIView+OWS.m
@@ -459,12 +459,13 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value)
 
 - (void)logFrameWithLabel:(NSString *)label
 {
-    DDLogVerbose(@"%@ %@ frame: %@, hidden: %d, opacity: %f",
+    DDLogVerbose(@"%@ %@ frame: %@, hidden: %d, opacity: %f, layoutMargins: %@",
         self.logTag,
         label,
         NSStringFromCGRect(self.frame),
         self.hidden,
-        self.layer.opacity);
+        self.layer.opacity,
+        NSStringFromUIEdgeInsets(self.layoutMargins));
 }
 
 - (void)logFrameLater