From 75594db5ac9b8b46b4df4ab5ea61e8a96f4f22c6 Mon Sep 17 00:00:00 2001
From: Bruno Muniz Azevedo Filho <bruno@elixxir.io>
Date: Fri, 22 Jul 2022 17:27:43 -0300
Subject: [PATCH] Refactored avatar cell

---
 .../ContactListTableController.swift          |   2 +-
 .../Controllers/CreateGroupController.swift   |   2 +-
 .../Controllers/SearchLeftController.swift    |  40 +++--
 Sources/Shared/Views/AvatarCell.swift         | 168 ++++++++----------
 Sources/Shared/Views/AvatarCellButton.swift   |  53 ++++++
 5 files changed, 159 insertions(+), 106 deletions(-)
 create mode 100644 Sources/Shared/Views/AvatarCellButton.swift

diff --git a/Sources/ContactListFeature/Controllers/ContactListTableController.swift b/Sources/ContactListFeature/Controllers/ContactListTableController.swift
index ac7a0662..b01fa771 100644
--- a/Sources/ContactListFeature/Controllers/ContactListTableController.swift
+++ b/Sources/ContactListFeature/Controllers/ContactListTableController.swift
@@ -49,7 +49,7 @@ final class ContactListTableController: UITableViewController {
         let contact = sections[indexPath.section][indexPath.row]
         let name = (contact.nickname ?? contact.username) ?? "Fetching username..."
 
-        cell.setup(title: name, image: contact.photo)
+        cell.set(image: contact.photo, h1Text: name)
         return cell
     }
 
diff --git a/Sources/ContactListFeature/Controllers/CreateGroupController.swift b/Sources/ContactListFeature/Controllers/CreateGroupController.swift
index a9559f5c..c6415566 100644
--- a/Sources/ContactListFeature/Controllers/CreateGroupController.swift
+++ b/Sources/ContactListFeature/Controllers/CreateGroupController.swift
@@ -87,7 +87,7 @@ public final class CreateGroupController: UIViewController {
             let cell = tableView.dequeueReusableCell(forIndexPath: indexPath, ofType: AvatarCell.self)
             let title = (contact.nickname ?? contact.username) ?? ""
 
-            cell.setup(title: title, image: contact.photo)
+            cell.set(image: contact.photo, h1Text: title)
 
             if let selectedElements = self?.selectedElements, selectedElements.contains(contact) {
                 tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
diff --git a/Sources/SearchFeature/Controllers/SearchLeftController.swift b/Sources/SearchFeature/Controllers/SearchLeftController.swift
index bbfabd28..4b71340e 100644
--- a/Sources/SearchFeature/Controllers/SearchLeftController.swift
+++ b/Sources/SearchFeature/Controllers/SearchLeftController.swift
@@ -77,22 +77,38 @@ final class SearchLeftController: UIViewController {
                 }
             }
 
-            cell.setup(
-                title: h1Text,
+            var action: AvatarCell.Action?
+
+            if contact.authStatus == .requested {
+                action = .init(
+                    title: Localized.Requests.Cell.requested,
+                    color: Asset.brandPrimary.color,
+                    image: Asset.requestsResend.image,
+                    action: { [weak self] in
+                        guard let self = self else { return }
+
+                        self.viewModel.didTapResend(contact: contact)
+
+                        cell.update(action: .init(
+                            title: Localized.Requests.Cell.resent,
+                            color: Asset.neutralWeak.color,
+                            image: Asset.requestsResent.image,
+                            action: {}
+                        ))
+                    }
+                )
+            }
+
+            cell.set(
                 image: contact.photo,
-                firstSubtitle: h2Text,
-                secondSubtitle: contact.email,
-                thirdSubtitle: contact.phone,
+                h1Text: h1Text,
+                h2Text: h2Text,
+                h3Text: contact.email,
+                h4Text: contact.phone,
                 showSeparator: false,
-                sent: contact.authStatus == .requested
+                action: action
             )
 
-            cell.didTapStateButton = { [weak self] in
-                guard let self = self else { return }
-                self.viewModel.didTapResend(contact: contact)
-                cell.updateToResent()
-            }
-
             return cell
         }
     }
diff --git a/Sources/Shared/Views/AvatarCell.swift b/Sources/Shared/Views/AvatarCell.swift
index 43f0e3fd..aeae12dd 100644
--- a/Sources/Shared/Views/AvatarCell.swift
+++ b/Sources/Shared/Views/AvatarCell.swift
@@ -1,58 +1,42 @@
 import UIKit
 import Combine
 
-final class AvatarCellButton: UIControl {
-    let titleLabel = UILabel()
-    let imageView = UIImageView()
-
-    init() {
-        super.init(frame: .zero)
-        titleLabel.numberOfLines = 0
-        titleLabel.textAlignment = .right
-        titleLabel.font = Fonts.Mulish.semiBold.font(size: 13.0)
-
-        addSubview(imageView)
-        addSubview(titleLabel)
-
-        imageView.snp.makeConstraints {
-            $0.top.greaterThanOrEqualToSuperview()
-            $0.left.equalToSuperview()
-            $0.centerY.equalToSuperview()
-            $0.bottom.lessThanOrEqualToSuperview()
-        }
-
-        titleLabel.snp.makeConstraints {
-            $0.top.greaterThanOrEqualToSuperview()
-            $0.left.equalTo(imageView.snp.right).offset(5)
-            $0.centerY.equalToSuperview()
-            $0.right.equalToSuperview()
-            $0.width.equalTo(60)
-            $0.bottom.lessThanOrEqualToSuperview()
+public final class AvatarCell: UITableViewCell {
+    public struct Action {
+        public var title: String
+        public var color: UIColor
+        public var image: UIImage?
+        public var action: () -> Void
+
+        public init(
+            title: String,
+            color: UIColor,
+            image: UIImage? = nil,
+            action: @escaping () -> Void
+        ) {
+            self.title = title
+            self.color = color
+            self.image = image
+            self.action = action
         }
     }
 
-    required init?(coder: NSCoder) { nil }
-}
-
-public final class AvatarCell: UITableViewCell {
-    let h1Label = UILabel()
-    let h2Label = UILabel()
-    let h3Label = UILabel()
-    let h4Label = UILabel()
-    let separatorView = UIView()
-    let avatarView = AvatarView()
-    let stackView = UIStackView()
-    let stateButton = AvatarCellButton()
-
-    var cancellables = Set<AnyCancellable>()
-    public var didTapStateButton: (() -> Void)!
+    private let h1Label = UILabel()
+    private let h2Label = UILabel()
+    private let h3Label = UILabel()
+    private let h4Label = UILabel()
+    private let separatorView = UIView()
+    private let avatarView = AvatarView()
+    private let stackView = UIStackView()
+    private var didTapAction: (() -> Void)?
+    private let actionButton = AvatarCellButton()
+    private var cancellables = Set<AnyCancellable>()
 
     public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
         super.init(style: style, reuseIdentifier: reuseIdentifier)
 
-        selectedBackgroundView = UIView()
-        multipleSelectionBackgroundView = UIView()
         backgroundColor = Asset.neutralWhite.color
+        separatorView.backgroundColor = Asset.neutralLine.color
 
         h1Label.textColor = Asset.neutralActive.color
         h2Label.textColor = Asset.neutralSecondaryAlternative.color
@@ -66,17 +50,14 @@ public final class AvatarCell: UITableViewCell {
 
         stackView.spacing = 4
         stackView.axis = .vertical
-        
         stackView.addArrangedSubview(h1Label)
         stackView.addArrangedSubview(h2Label)
         stackView.addArrangedSubview(h3Label)
         stackView.addArrangedSubview(h4Label)
 
-        separatorView.backgroundColor = Asset.neutralLine.color
-
         contentView.addSubview(stackView)
         contentView.addSubview(avatarView)
-        contentView.addSubview(stateButton)
+        contentView.addSubview(actionButton)
         contentView.addSubview(separatorView)
 
         setupConstraints()
@@ -90,70 +71,73 @@ public final class AvatarCell: UITableViewCell {
         h2Label.text = nil
         h3Label.text = nil
         h4Label.text = nil
-
-        stateButton.imageView.image = nil
-        stateButton.titleLabel.text = nil
+        didTapAction = nil
 
         avatarView.prepareForReuse()
+        actionButton.prepareForReuse()
+
+        cancellables.forEach { $0.cancel() }
         cancellables.removeAll()
     }
 
-    public func setup(
-        title: String,
+    public func set(
         image: Data?,
-        firstSubtitle: String? = nil,
-        secondSubtitle: String? = nil,
-        thirdSubtitle: String? = nil,
+        h1Text: String,
+        h2Text: String? = nil,
+        h3Text: String? = nil,
+        h4Text: String? = nil,
         showSeparator: Bool = true,
-        sent: Bool = false
+        action: Action? = nil
     ) {
-        h1Label.text = title
+        avatarView.setupProfile(
+            title: h1Text,
+            image: image,
+            size: .medium
+        )
 
-        if let firstSubtitle = firstSubtitle {
-            h2Label.isHidden = false
-            h2Label.text = firstSubtitle
-        } else {
-            h2Label.isHidden = true
-        }
+        h1Label.text = h1Text
+        h2Label.text = h2Text
+        h3Label.text = h3Text
+        h4Label.text = h4Text
 
-        if let secondSubtitle = secondSubtitle {
-            h3Label.isHidden = false
-            h3Label.text = secondSubtitle
-        } else {
-            h3Label.isHidden = true
-        }
+        h2Label.isHidden = h2Text == nil
+        h3Label.isHidden = h3Text == nil
+        h4Label.isHidden = h4Text == nil
 
-        if let thirdSubtitle = thirdSubtitle {
-            h4Label.isHidden = false
-            h4Label.text = thirdSubtitle
-        } else {
-            h4Label.isHidden = true
-        }
+        separatorView.isHidden = !showSeparator
 
-        avatarView.setupProfile(title: title, image: image, size: .medium)
-        separatorView.alpha = showSeparator ? 1.0 : 0.0
+        if let action = action {
+            actionButton.set(
+                image: action.image,
+                title: action.title,
+                titleColor: action.color
+            )
 
-        cancellables.removeAll()
-
-        if sent {
-            stateButton.imageView.image = Asset.requestsResend.image
-            stateButton.titleLabel.text = Localized.Requests.Cell.requested
-            stateButton.titleLabel.textColor = Asset.brandPrimary.color
+            didTapAction = action.action
 
-            stateButton
+            actionButton
                 .publisher(for: .touchUpInside)
-                .sink { [unowned self] in didTapStateButton() }
+                .sink { [unowned self] in didTapAction?() }
                 .store(in: &cancellables)
         }
     }
 
-    public func updateToResent() {
-        stateButton.imageView.image = Asset.requestsResent.image
-        stateButton.titleLabel.text = Localized.Requests.Cell.resent
-        stateButton.titleLabel.textColor = Asset.neutralWeak.color
-
+    public func update(action: Action) {
         cancellables.forEach { $0.cancel() }
         cancellables.removeAll()
+
+        actionButton.set(
+            image: action.image,
+            title: action.title,
+            titleColor: action.color
+        )
+
+        didTapAction = action.action
+
+        actionButton
+            .publisher(for: .touchUpInside)
+            .sink { [unowned self] in didTapAction?() }
+            .store(in: &cancellables)
     }
 
     private func setupConstraints() {
@@ -179,7 +163,7 @@ public final class AvatarCell: UITableViewCell {
             $0.bottom.equalToSuperview()
         }
 
-        stateButton.snp.makeConstraints {
+        actionButton.snp.makeConstraints {
             $0.centerY.equalTo(stackView)
             $0.right.equalToSuperview().offset(-24)
         }
diff --git a/Sources/Shared/Views/AvatarCellButton.swift b/Sources/Shared/Views/AvatarCellButton.swift
new file mode 100644
index 00000000..38d5a01e
--- /dev/null
+++ b/Sources/Shared/Views/AvatarCellButton.swift
@@ -0,0 +1,53 @@
+import UIKit
+
+final class AvatarCellButton: UIControl {
+    private let titleLabel = UILabel()
+    private let imageView = UIImageView()
+
+    init() {
+        super.init(frame: .zero)
+        titleLabel.numberOfLines = 0
+        titleLabel.textAlignment = .right
+        titleLabel.font = Fonts.Mulish.semiBold.font(size: 13.0)
+
+        addSubview(imageView)
+        addSubview(titleLabel)
+
+        setupConstraints()
+    }
+
+    required init?(coder: NSCoder) { nil }
+
+    func prepareForReuse() {
+        titleLabel.text = nil
+        imageView.image = nil
+    }
+
+    func set(
+        image: UIImage?,
+        title: String,
+        titleColor: UIColor
+    ) {
+        imageView.image = image
+        titleLabel.text = title
+        titleLabel.textColor = titleColor
+    }
+
+    private func setupConstraints() {
+        imageView.snp.makeConstraints {
+            $0.top.greaterThanOrEqualToSuperview()
+            $0.left.equalToSuperview()
+            $0.centerY.equalToSuperview()
+            $0.bottom.lessThanOrEqualToSuperview()
+        }
+
+        titleLabel.snp.makeConstraints {
+            $0.top.greaterThanOrEqualToSuperview()
+            $0.left.equalTo(imageView.snp.right).offset(5)
+            $0.centerY.equalToSuperview()
+            $0.right.equalToSuperview()
+            $0.width.equalTo(60)
+            $0.bottom.lessThanOrEqualToSuperview()
+        }
+    }
+}
-- 
GitLab