From f13e0ba86a81641312336c50479fa5c8ca9d4cc0 Mon Sep 17 00:00:00 2001
From: Bruno Muniz Azevedo Filho <bruno@elixxir.io>
Date: Fri, 22 Jul 2022 21:35:51 -0300
Subject: [PATCH] Added contact list indexing

---
 .../Controllers/ContactListController.swift   | 39 ++++++--------
 .../Helpers/IndexedListCollator.swift         | 53 -------------------
 .../Utils/IndexedContactList.swift            | 26 +++++++++
 3 files changed, 43 insertions(+), 75 deletions(-)
 delete mode 100644 Sources/ContactListFeature/Helpers/IndexedListCollator.swift
 create mode 100644 Sources/ContactListFeature/Utils/IndexedContactList.swift

diff --git a/Sources/ContactListFeature/Controllers/ContactListController.swift b/Sources/ContactListFeature/Controllers/ContactListController.swift
index b0957b62..34612913 100644
--- a/Sources/ContactListFeature/Controllers/ContactListController.swift
+++ b/Sources/ContactListFeature/Controllers/ContactListController.swift
@@ -11,9 +11,9 @@ public final class ContactListController: UIViewController {
 
     lazy private var screenView = ContactListView()
 
+    private var dataSource: IndexedContactList!
     private let viewModel = ContactListViewModel()
     private var cancellables = Set<AnyCancellable>()
-    private var dataSource: UICollectionViewDiffableDataSource<Int, Contact>!
 
     public override func loadView() {
         view = screenView
@@ -38,8 +38,9 @@ public final class ContactListController: UIViewController {
         screenView.collectionView.delegate = self
         screenView.collectionView.register(AvatarCell.self)
         screenView.collectionView.dataSource = dataSource
+        screenView.collectionView.tintColor = Asset.neutralDark.color
 
-        dataSource = UICollectionViewDiffableDataSource<Int, Contact>(
+        dataSource = IndexedContactList(
             collectionView: screenView.collectionView
         ) { collectionView, indexPath, contact in
             let cell: AvatarCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
@@ -125,15 +126,25 @@ public final class ContactListController: UIViewController {
 
         viewModel.snapshotPublisher
             .receive(on: DispatchQueue.main)
-            .sink { [unowned self] in
-                screenView.emptyView.isHidden = $0.numberOfItems > 0
+            .sink { [unowned self] snapshot in
+                screenView.emptyView.isHidden = snapshot.numberOfItems > 0
 
-                if $0.numberOfItems == 0 {
+                if snapshot.numberOfItems == 0 {
                     screenView.bringSubviewToFront(screenView.emptyView)
                 }
 
                 let animatingDifferences = dataSource.snapshot().numberOfItems > 0
-                dataSource.apply($0, animatingDifferences: animatingDifferences)
+                dataSource.apply(snapshot, animatingDifferences: animatingDifferences) { [weak self] in
+                    guard let self = self else { return }
+
+                    self.dataSource.set(indexTitles: snapshot.itemIdentifiers.map { contact -> String in
+                        let name = (contact.nickname ?? contact.username) ?? ""
+                        return "\(name.first!)"
+                    })
+
+                    self.screenView.collectionView.reloadData()
+                }
+
             }.store(in: &cancellables)
     }
 
@@ -157,19 +168,3 @@ extension ContactListController: UICollectionViewDelegate {
         }
     }
 }
-
-
-//final class ContactListTableController: UITableViewController {
-//    private var collation = UILocalizedIndexedCollation.current()
-//
-//    override func sectionIndexTitles(for: UITableView) -> [String]? {
-//        collation.sectionIndexTitles
-//    }
-//
-//    override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
-//        collation.sectionTitles[section]
-//    }
-//
-//    override func tableView(_: UITableView, sectionForSectionIndexTitle: String, at index: Int) -> Int {
-//        collation.section(forSectionIndexTitle: index)
-//    }
diff --git a/Sources/ContactListFeature/Helpers/IndexedListCollator.swift b/Sources/ContactListFeature/Helpers/IndexedListCollator.swift
deleted file mode 100644
index 249af6fa..00000000
--- a/Sources/ContactListFeature/Helpers/IndexedListCollator.swift
+++ /dev/null
@@ -1,53 +0,0 @@
-import UIKit
-import XXModels
-
-public protocol IndexableItem {
-    var indexedOn: NSString { get }
-}
-
-class IndexedListCollator<Item: IndexableItem> {
-    private final class CollationWrapper: NSObject {
-        let value: Any
-        @objc let indexedOn: NSString
-
-        init(value: Any, indexedOn: NSString) {
-            self.value = value
-            self.indexedOn = indexedOn
-        }
-
-        func unwrappedValue<UnwrappedType>() -> UnwrappedType {
-            return value as! UnwrappedType
-        }
-    }
-
-    public init() {}
-
-    public func sectioned(items: [Item]) -> (sections: [[Item]], collation: UILocalizedIndexedCollation) {
-        let collation = UILocalizedIndexedCollation.current()
-        let selector = #selector(getter: CollationWrapper.indexedOn)
-
-        let wrappedItems = items.map { item in
-            CollationWrapper(value: item, indexedOn: item.indexedOn)
-        }
-
-        let sortedObjects = collation.sortedArray(from: wrappedItems, collationStringSelector: selector) as! [CollationWrapper]
-
-        var sections = collation.sectionIndexTitles.map { _ in [Item]() }
-        sortedObjects.forEach { item in
-            let sectionNumber = collation.section(for: item, collationStringSelector: selector)
-            sections[sectionNumber].append(item.unwrappedValue())
-        }
-
-        return (sections: sections.filter { !$0.isEmpty }, collation: collation)
-    }
-}
-
-extension Contact: IndexableItem {
-    public var indexedOn: NSString {
-        guard let nickname = nickname else {
-            return "\(username!.first!)" as NSString
-        }
-
-        return "\(nickname.first!)" as NSString
-    }
-}
diff --git a/Sources/ContactListFeature/Utils/IndexedContactList.swift b/Sources/ContactListFeature/Utils/IndexedContactList.swift
new file mode 100644
index 00000000..262618bd
--- /dev/null
+++ b/Sources/ContactListFeature/Utils/IndexedContactList.swift
@@ -0,0 +1,26 @@
+import UIKit
+import XXModels
+
+final class IndexedContactList: UICollectionViewDiffableDataSource<Int, Contact> {
+    private var indexTitles: [String] = []
+
+    func set(indexTitles: [String]) {
+        self.indexTitles = indexTitles
+    }
+
+    override func indexTitles(for collectionView: UICollectionView) -> [String]? {
+        indexTitles
+    }
+
+    override func collectionView(
+        _ collectionView: UICollectionView,
+        indexPathForIndexTitle title: String,
+        at index: Int
+    ) -> IndexPath {
+        guard let index = indexTitles.firstIndex(where: { $0 == title }) else {
+            return IndexPath(item: 0, section: 0)
+        }
+
+        return IndexPath(item: index, section: 0)
+    }
+}
-- 
GitLab