diff --git a/Sources/ChatListFeature/Controller/ChatListController.swift b/Sources/ChatListFeature/Controller/ChatListController.swift
index bddccd284ce09ecb2b9e479044aa8fb41eb5e757..180c3798ef43de0e00636b85f4a541e31a51bd64 100644
--- a/Sources/ChatListFeature/Controller/ChatListController.swift
+++ b/Sources/ChatListFeature/Controller/ChatListController.swift
@@ -16,7 +16,7 @@ public final class ChatListController: UIViewController {
     lazy private var topRightView = ChatListTopRightNavView()
     lazy private var tableController = ChatListTableController(viewModel)
     lazy private var searchTableController = ChatSearchTableController(viewModel)
-    private var collectionDataSource: UICollectionViewDiffableDataSource<SectionId, Contact>!
+    private var collectionDataSource: UICollectionViewDiffableDataSource<Int, Contact>!
 
     private let viewModel = ChatListViewModel()
     private var cancellables = Set<AnyCancellable>()
@@ -112,7 +112,7 @@ public final class ChatListController: UIViewController {
             .collectionView
             .register(ChatListRecentContactCell.self)
 
-        collectionDataSource = UICollectionViewDiffableDataSource<SectionId, Contact>(
+        collectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>(
             collectionView: screenView.listContainerView.collectionView
         ) { collectionView, indexPath, contact in
             let cell: ChatListRecentContactCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
diff --git a/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift b/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift
index f481b96fb7e3e14b74096919090bf1df8c96c840..852901a4b2d7e1e0395633dd4123fbffddf409d4 100644
--- a/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift
+++ b/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift
@@ -18,7 +18,7 @@ enum SearchItem: Equatable, Hashable {
     case connection(Contact)
 }
 
-typealias RecentsSnapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>
+typealias RecentsSnapshot = NSDiffableDataSourceSnapshot<Int, Contact>
 typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem>
 
 final class ChatListViewModel {
@@ -40,10 +40,9 @@ final class ChatListViewModel {
         session.dbManager.fetchContactsPublisher(.init(isRecent: true))
             .assertNoFailure()
             .map {
-            let section = SectionId()
             var snapshot = RecentsSnapshot()
-            snapshot.appendSections([section])
-            snapshot.appendItems($0, toSection: section)
+            snapshot.appendSections([0])
+            snapshot.appendItems($0, toSection: 0)
             return snapshot
         }.eraseToAnyPublisher()
     }
diff --git a/Sources/ContactListFeature/Controllers/CreateGroupController.swift b/Sources/ContactListFeature/Controllers/CreateGroupController.swift
index fdca1638ae3fda81abcc1fb76d03b642f97520e0..a8c75d45d6289c1fe8fd5a9380100664b0e85b91 100644
--- a/Sources/ContactListFeature/Controllers/CreateGroupController.swift
+++ b/Sources/ContactListFeature/Controllers/CreateGroupController.swift
@@ -19,8 +19,8 @@ public final class CreateGroupController: UIViewController {
     }
     private let viewModel = CreateGroupViewModel()
     private var cancellables = Set<AnyCancellable>()
-    private var topCollectionDataSource: UICollectionViewDiffableDataSource<SectionId, Contact>!
-    private var bottomCollectionDataSource: UICollectionViewDiffableDataSource<SectionId, Contact>!
+    private var topCollectionDataSource: UICollectionViewDiffableDataSource<Int, Contact>!
+    private var bottomCollectionDataSource: UICollectionViewDiffableDataSource<Int, Contact>!
 
     private var count = 0 {
         didSet {
@@ -68,7 +68,7 @@ public final class CreateGroupController: UIViewController {
         screenView.bottomCollectionView.register(AvatarCell.self)
         screenView.topCollectionView.register(CreateGroupCollectionCell.self)
 
-        topCollectionDataSource = UICollectionViewDiffableDataSource<SectionId, Contact>(
+        topCollectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>(
             collectionView: screenView.topCollectionView
         ) { [weak viewModel] collectionView, indexPath, contact in
             let cell: CreateGroupCollectionCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
@@ -80,7 +80,7 @@ public final class CreateGroupController: UIViewController {
             return cell
         }
 
-        bottomCollectionDataSource = UICollectionViewDiffableDataSource<SectionId, Contact>(
+        bottomCollectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>(
             collectionView: screenView.bottomCollectionView
         ) { [weak self] collectionView, indexPath, contact in
             let cell: AvatarCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
@@ -122,8 +122,8 @@ public final class CreateGroupController: UIViewController {
             }.store(in: &cancellables)
 
         selected.map { selectedContacts in
-            var snapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>()
-            let sections = [SectionId()]
+            var snapshot = NSDiffableDataSourceSnapshot<Int, Contact>()
+            let sections = [0]
             snapshot.appendSections(sections)
             sections.forEach { section in snapshot.appendItems(selectedContacts, toSection: section) }
             return snapshot
@@ -133,9 +133,9 @@ public final class CreateGroupController: UIViewController {
         .store(in: &cancellables)
 
         viewModel.contacts
-            .map { contacts -> NSDiffableDataSourceSnapshot<SectionId, Contact> in
-                var snapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>()
-                let sections = [SectionId()]
+            .map { contacts -> NSDiffableDataSourceSnapshot<Int, Contact> in
+                var snapshot = NSDiffableDataSourceSnapshot<Int, Contact>()
+                let sections = [0]
                 snapshot.appendSections(sections)
                 sections.forEach { section in snapshot.appendItems(contacts, toSection: section) }
                 return snapshot
diff --git a/Sources/ContactListFeature/Views/ContactListActionButton.swift b/Sources/ContactListFeature/Views/ContactListActionButton.swift
index f63e480dbe1f758099c6bc1aa515060dee4f9f3a..21743fefdd84be22f8b073010dddf100376e2f59 100644
--- a/Sources/ContactListFeature/Views/ContactListActionButton.swift
+++ b/Sources/ContactListFeature/Views/ContactListActionButton.swift
@@ -6,6 +6,7 @@ final class ContactListActionButton: UIControl {
     private let imageView = UIImageView()
     private let stackView = UIStackView()
     private let notificationLabel = UILabel()
+    private let notificationContainerView = UIView()
 
     init() {
         super.init(frame: .zero)
@@ -13,18 +14,21 @@ final class ContactListActionButton: UIControl {
         titleLabel.textColor = Asset.brandPrimary.color
         titleLabel.font = Fonts.Mulish.semiBold.font(size: 14.0)
 
-        notificationLabel.layer.cornerRadius = 5
-        notificationLabel.layer.masksToBounds = true
         notificationLabel.textColor = Asset.neutralWhite.color
-        notificationLabel.backgroundColor = Asset.brandPrimary.color
-        notificationLabel.font = Fonts.Mulish.black.font(size: 12.0)
+        notificationLabel.font = Fonts.Mulish.bold.font(size: 12.0)
+
+        notificationContainerView.isHidden = true
+        notificationContainerView.layer.cornerRadius = 10
+        notificationContainerView.layer.masksToBounds = true
+        notificationContainerView.addSubview(notificationLabel)
+        notificationContainerView.backgroundColor = Asset.brandPrimary.color
 
         stackView.spacing = 16
         stackView.addArrangedSubview(imageView)
         stackView.addArrangedSubview(titleLabel)
-        stackView.addArrangedSubview(notificationLabel)
+        stackView.addArrangedSubview(notificationContainerView)
         stackView.addArrangedSubview(FlexibleSpace())
-        stackView.setCustomSpacing(6, after: titleLabel)
+        stackView.setCustomSpacing(8, after: titleLabel)
         stackView.isUserInteractionEnabled = false
 
         addSubview(stackView)
@@ -40,8 +44,8 @@ final class ContactListActionButton: UIControl {
     }
 
     func updateNotification(_ count: Int) {
-        notificationLabel.isHidden = count < 1
-        notificationLabel.text = "  \(count)  " // TODO: Use insets (?) for padding
+        notificationLabel.text = "\(count)"
+        notificationContainerView.isHidden = count == 0
     }
 
     private func setupConstraints() {
@@ -53,5 +57,11 @@ final class ContactListActionButton: UIControl {
         stackView.snp.makeConstraints {
             $0.edges.equalToSuperview()
         }
+
+        notificationLabel.snp.makeConstraints {
+            $0.centerY.equalToSuperview()
+            $0.left.equalToSuperview().offset(8)
+            $0.right.equalToSuperview().offset(-8)
+        }
     }
 }
diff --git a/Sources/ContactListFeature/Views/ContactListView.swift b/Sources/ContactListFeature/Views/ContactListView.swift
index 6411e7ed287472f1e907595cb781f0b1da90e405..bcfe0ce746ce370193527f4ceb8fc5a693ce2042 100644
--- a/Sources/ContactListFeature/Views/ContactListView.swift
+++ b/Sources/ContactListFeature/Views/ContactListView.swift
@@ -3,9 +3,9 @@ import Shared
 
 final class ContactListView: UIView {
     private let separatorView = UIView()
-    private(set) var emptyView = ContactListEmptyView()
-    private(set) var newGroupButton = ContactListActionButton()
-    private(set) var requestsButton = ContactListActionButton()
+    let emptyView = ContactListEmptyView()
+    let newGroupButton = ContactListActionButton()
+    let requestsButton = ContactListActionButton()
 
     lazy var collectionView: UICollectionView = {
         var config = UICollectionLayoutListConfiguration(appearance: .plain)
diff --git a/Sources/ContactListFeature/Views/CreateGroupView.swift b/Sources/ContactListFeature/Views/CreateGroupView.swift
index b333956bca4ab6e422da362e75071e349656b3bf..1b732578c1f65b9479124dee8c0e39d729410592 100644
--- a/Sources/ContactListFeature/Views/CreateGroupView.swift
+++ b/Sources/ContactListFeature/Views/CreateGroupView.swift
@@ -15,8 +15,6 @@ final class CreateGroupView: UIView {
         let collectionView = UICollectionView(frame: bounds, collectionViewLayout: layout)
         collectionView.contentInset = .init(top: 15, left: 0, bottom: 0, right: 0)
         return collectionView
-
-        //tableView.setEditing(true, animated: true)
     }()
 
     let layout: UICollectionViewFlowLayout = {
diff --git a/Sources/Countries/CountryListCell.swift b/Sources/Countries/CountryListCell.swift
index b3b650e5ae8daae80cc8b026fc3d242bac1b9920..fa01c680f5dba5587594ba34ae6698c0f55b8ba7 100644
--- a/Sources/Countries/CountryListCell.swift
+++ b/Sources/Countries/CountryListCell.swift
@@ -1,16 +1,15 @@
 import UIKit
 import Shared
 
-final class CountryListCell: UITableViewCell {
-    let nameLabel = UILabel()
-    let flagLabel = UILabel()
-    let prefixLabel = UILabel()
-    let separatorView = UIView()
+final class CountryListCell: UICollectionViewCell {
+    private let nameLabel = UILabel()
+    private let flagLabel = UILabel()
+    private let prefixLabel = UILabel()
+    private let separatorView = UIView()
 
-    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
-        super.init(style: style, reuseIdentifier: reuseIdentifier)
+    override init(frame: CGRect) {
+        super.init(frame: frame)
 
-        selectionStyle = .none
         backgroundColor = Asset.neutralWhite.color
 
         nameLabel.textColor = Asset.neutralDark.color
@@ -26,6 +25,29 @@ final class CountryListCell: UITableViewCell {
         contentView.addSubview(prefixLabel)
         contentView.addSubview(separatorView)
 
+        setupConstraints()
+    }
+
+    required init?(coder: NSCoder) { nil }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+        nameLabel.text = nil
+        flagLabel.text = nil
+        prefixLabel.text = nil
+    }
+
+    func set(
+        flag: String,
+        name: String,
+        prefix: String
+    ) {
+        flagLabel.text = flag
+        nameLabel.text = name
+        prefixLabel.text = prefix
+    }
+
+    private func setupConstraints() {
         flagLabel.snp.makeConstraints {
             $0.left.top.equalToSuperview().inset(18)
             $0.bottom.equalToSuperview().offset(-16)
@@ -49,14 +71,4 @@ final class CountryListCell: UITableViewCell {
             $0.height.equalTo(1)
         }
     }
-
-    required init?(coder: NSCoder) { nil }
-
-    override func prepareForReuse() {
-        super.prepareForReuse()
-
-        nameLabel.text = nil
-        flagLabel.text = nil
-        prefixLabel.text = nil
-    }
 }
diff --git a/Sources/Countries/CountryListController.swift b/Sources/Countries/CountryListController.swift
index ab7ca357c0d9f074d73c38c1616cbba81d9ed9c1..20309062ca44e9b3784397632738d5b10719d9cc 100644
--- a/Sources/Countries/CountryListController.swift
+++ b/Sources/Countries/CountryListController.swift
@@ -1,4 +1,3 @@
-import os
 import Theme
 import UIKit
 import Shared
@@ -6,14 +5,14 @@ import Combine
 import DependencyInjection
 
 public final class CountryListController: UIViewController {
-    @Dependency private var statusBarController: StatusBarStyleControlling
+    @Dependency var statusBarController: StatusBarStyleControlling
     
     lazy private var screenView = CountryListView()
 
     private var didChoose: ((Country) -> Void)!
     private let viewModel = CountryListViewModel()
     private var cancellables = Set<AnyCancellable>()
-    private var dataSource: UITableViewDiffableDataSource<SectionId, Country>!
+    private var dataSource: UICollectionViewDiffableDataSource<Int, Country>!
 
     public init(_ didChoose: @escaping (Country) -> Void) {
         self.didChoose = didChoose
@@ -25,7 +24,6 @@ public final class CountryListController: UIViewController {
     public override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         statusBarController.style.send(.darkContent)
-
         navigationController?.navigationBar.customize(
             backgroundColor: Asset.neutralWhite.color,
             shadowColor: Asset.neutralDisabled.color
@@ -38,65 +36,70 @@ public final class CountryListController: UIViewController {
 
     public override func viewDidLoad() {
         super.viewDidLoad()
-        screenView.tableView.register(CountryListCell.self)
         setupNavigationBar()
+        setupCollectionView()
         setupBindings()
-
-        viewModel.fetchCountryList()
     }
     
     private func setupNavigationBar() {
         navigationItem.backButtonTitle = " "
 
-        let title = UILabel()
-        title.text = Localized.Countries.title
-        title.textColor = Asset.neutralActive.color
-        title.font = Fonts.Mulish.semiBold.font(size: 18.0)
+        let titleLabel = UILabel()
+        titleLabel.text = Localized.Countries.title
+        titleLabel.textColor = Asset.neutralActive.color
+        titleLabel.font = Fonts.Mulish.semiBold.font(size: 18.0)
 
-        let back = UIButton.back()
-        back.addTarget(self, action: #selector(didTapBack), for: .touchUpInside)
+        let backButton = UIButton.back()
+        backButton.addTarget(self, action: #selector(didTapBack), for: .touchUpInside)
 
         navigationItem.leftBarButtonItem = UIBarButtonItem(
-            customView: UIStackView(arrangedSubviews: [back, title])
+            customView: UIStackView(arrangedSubviews: [backButton, titleLabel])
         )
     }
 
     private func setupBindings() {
-        viewModel.countries
+        viewModel.countriesPublisher
             .receive(on: DispatchQueue.main)
             .sink { [unowned self] in dataSource.apply($0, animatingDifferences: false) }
             .store(in: &cancellables)
 
-        dataSource = UITableViewDiffableDataSource<SectionId, Country>(
-            tableView: screenView.tableView
-        ) { tableView, indexPath, country in
-            let cell: CountryListCell = tableView.dequeueReusableCell(forIndexPath: indexPath)
-            cell.flagLabel.text = country.flag
-            cell.nameLabel.text = country.name
-            cell.prefixLabel.text = country.prefix
-            return cell
-        }
-
         screenView.searchComponent
             .textPublisher
             .removeDuplicates()
             .sink { [unowned self] in viewModel.didSearchFor($0) }
             .store(in: &cancellables)
+    }
+
+    private func setupCollectionView() {
+        screenView.collectionView.register(CountryListCell.self)
 
-        screenView.tableView.delegate = self
-        screenView.tableView.dataSource = dataSource
+        dataSource = UICollectionViewDiffableDataSource<Int, Country>(
+            collectionView: screenView.collectionView
+        ) { collectionView, indexPath, country in
+            let cell: CountryListCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
+
+            cell.set(
+                flag: country.flag,
+                name: country.name,
+                prefix: country.prefix
+            )
+            return cell
+        }
+
+        screenView.collectionView.delegate = self
+        screenView.collectionView.dataSource = dataSource
     }
     
     @objc private func didTapBack() {
         navigationController?.popViewController(animated: true)
     }
+}
 
-    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+extension CountryListController: UICollectionViewDelegate {
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
         if let country = dataSource.itemIdentifier(for: indexPath) {
             didChoose(country)
             navigationController?.popViewController(animated: true)
         }
     }
 }
-
-extension CountryListController: UITableViewDelegate {}
diff --git a/Sources/Countries/CountryListView.swift b/Sources/Countries/CountryListView.swift
index cf743823ace4b8b1d45fefeb1dedc0360374799a..0b82227b6e9e22cfc33c687e3b36e93791e94b85 100644
--- a/Sources/Countries/CountryListView.swift
+++ b/Sources/Countries/CountryListView.swift
@@ -2,19 +2,20 @@ import UIKit
 import Shared
 
 final class CountryListView: UIView {
-    let tableView = UITableView()
     let searchComponent = SearchComponent()
 
+    lazy var collectionView: UICollectionView = {
+        var config = UICollectionLayoutListConfiguration(appearance: .plain)
+        config.backgroundColor = .clear
+        config.showsSeparators = false
+        let layout = UICollectionViewCompositionalLayout.list(using: config)
+        let collectionView = UICollectionView(frame: bounds, collectionViewLayout: layout)
+        collectionView.contentInset = .init(top: 20, left: 0, bottom: 0, right: 0)
+        return collectionView
+    }()
+
     init() {
         super.init(frame: .zero)
-        setup()
-    }
-
-    required init?(coder: NSCoder) { nil }
-
-    private func setup() {
-        tableView.separatorStyle = .none
-        tableView.backgroundColor = .clear
         backgroundColor = Asset.neutralWhite.color
 
         searchComponent.set(
@@ -23,20 +24,26 @@ final class CountryListView: UIView {
             rightAccessibility: Localized.Accessibility.Countries.Search.right
         )
 
-        addSubview(tableView)
+        addSubview(collectionView)
         addSubview(searchComponent)
 
-        searchComponent.snp.makeConstraints { make in
-            make.top.equalToSuperview().offset(20)
-            make.left.equalToSuperview().offset(20)
-            make.right.equalToSuperview().offset(-20)
+        setupConstraints()
+    }
+
+    required init?(coder: NSCoder) { nil }
+
+    private func setupConstraints() {
+        searchComponent.snp.makeConstraints {
+            $0.top.equalToSuperview().offset(20)
+            $0.left.equalToSuperview().offset(20)
+            $0.right.equalToSuperview().offset(-20)
         }
 
-        tableView.snp.makeConstraints { make in
-            make.top.equalTo(searchComponent.snp.bottom).offset(20)
-            make.left.equalToSuperview()
-            make.bottom.equalToSuperview()
-            make.right.equalToSuperview()
+        collectionView.snp.makeConstraints {
+            $0.top.equalTo(searchComponent.snp.bottom).offset(20)
+            $0.left.equalToSuperview()
+            $0.bottom.equalToSuperview()
+            $0.right.equalToSuperview()
         }
     }
 }
diff --git a/Sources/Countries/CountryListViewModel.swift b/Sources/Countries/CountryListViewModel.swift
index e4157a16e1938cc506f0549113d393eb6f5b6202..b737794729fc45225c562705729b2c34bb479b0a 100644
--- a/Sources/Countries/CountryListViewModel.swift
+++ b/Sources/Countries/CountryListViewModel.swift
@@ -1,49 +1,51 @@
-import os
 import UIKit
 import Shared
 import Combine
-import Foundation
 
-private let logger = Logger(subsystem: "logs_xxmessenger", category: "Countries.CountryListViewModel.swift")
+typealias CountryListSnapshot = NSDiffableDataSourceSnapshot<Int, Country>
 
 final class CountryListViewModel {
-    var countries: AnyPublisher<NSDiffableDataSourceSnapshot<SectionId, Country>, Never> {
-        countriesRelay.eraseToAnyPublisher()
+    var queryPublisher: AnyPublisher<String, Never> {
+        querySubject.eraseToAnyPublisher()
+    }
+
+    var countriesPublisher: AnyPublisher<CountryListSnapshot, Never> {
+        countriesSubject.eraseToAnyPublisher()
     }
 
     private var cancellables = Set<AnyCancellable>()
-    private let searchQueryRelay = CurrentValueSubject<String, Never>("")
-    private let countriesRelay = CurrentValueSubject<NSDiffableDataSourceSnapshot<SectionId, Country>, Never>(.init())
-
-    func fetchCountryList() {
-        logger.log("fetchCountryList()")
-
-        Publishers.CombineLatest(Just(Country.all()), searchQueryRelay)
-            .map { countryList, query -> NSDiffableDataSourceSnapshot<SectionId, Country> in
-                var snapshot = NSDiffableDataSourceSnapshot<SectionId, Country>()
-                let section = SectionId()
-                snapshot.appendSections([section])
-
-                guard !query.isEmpty else {
-                    logger.log("query.isEmpty, returning all countries")
-                    snapshot.appendItems(countryList, toSection: section)
-                    return snapshot
-                }
-
-                let filtered = countryList.filter {
-                    $0.name.lowercased().contains(query.lowercased()) ||
-                    $0.prefix.lowercased().contains(query.lowercased())
-                }
-
-                snapshot.appendItems(filtered, toSection: section)
-                return snapshot
-
-            }.sink { [weak countriesRelay] in countriesRelay?.send($0) }
-            .store(in: &cancellables)
+    private let querySubject = CurrentValueSubject<String, Never>("")
+    private let countriesSubject = CurrentValueSubject<CountryListSnapshot, Never>(.init())
+
+    init() {
+        Publishers.CombineLatest(
+            Just(Country.all()),
+            queryPublisher
+        )
+        .map(prepareSnapshot(_:))
+        .sink { [unowned self] in countriesSubject.send($0) }
+        .store(in: &cancellables)
     }
 
     func didSearchFor(_ string: String) {
-        logger.log("didSearchFor \(string, privacy: .public)()")
-        searchQueryRelay.send(string)
+        querySubject.send(string)
+    }
+
+    private func prepareSnapshot(_ pair: (countries: [Country], query: String)) -> CountryListSnapshot {
+        var snapshot = CountryListSnapshot()
+        snapshot.appendSections([0])
+
+        guard !pair.query.isEmpty else {
+            snapshot.appendItems(pair.countries, toSection: 0)
+            return snapshot
+        }
+
+        let filtered = pair.countries.filter {
+            $0.name.lowercased().contains(pair.query.lowercased()) ||
+            $0.prefix.lowercased().contains(pair.query.lowercased())
+        }
+
+        snapshot.appendItems(filtered, toSection: 0)
+        return snapshot
     }
 }
diff --git a/Sources/DrawerFeature/Items/DrawerList.swift b/Sources/DrawerFeature/Items/DrawerList.swift
new file mode 100644
index 0000000000000000000000000000000000000000..8be6eab4dba36e264c5bc7d64d8c5fa777b2a314
--- /dev/null
+++ b/Sources/DrawerFeature/Items/DrawerList.swift
@@ -0,0 +1,68 @@
+import UIKit
+import Shared
+import SnapKit
+
+public final class DrawerList: DrawerItem {
+    private let view = UIView()
+    private var heightConstraint: Constraint?
+    private let collectionView = UICollectionView()
+    private let dataSource: UICollectionViewDiffableDataSource<Int, DrawerListCellModel>
+
+    public var spacingAfter: CGFloat? = 0
+
+    public init(spacingAfter: CGFloat? = 10) {
+        self.dataSource = .init(
+            collectionView: collectionView,
+            cellProvider: { collectionView, indexPath, model in
+                var subtitle: String?
+                var subtitleColor = Asset.neutralSecondaryAlternative.color
+                let cell: DrawerListCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
+
+                if model.isCreator {
+                    subtitle = "Creator"
+                    subtitleColor = Asset.accentSafe.color
+                } else if !model.isConnection {
+                    subtitle = "Not a connection"
+                }
+
+                cell.set(
+                    image: model.image,
+                    title: model.title,
+                    subtitle: subtitle,
+                    subtitleColor: subtitleColor
+                )
+
+                return cell
+            })
+
+        self.spacingAfter = spacingAfter
+    }
+
+    public func makeView() -> UIView {
+        collectionView.register(DrawerListCell.self)
+        collectionView.dataSource = dataSource
+
+        view.addSubview(collectionView)
+
+        collectionView.snp.makeConstraints {
+            $0.edges.equalToSuperview()
+            heightConstraint = $0.height.equalTo(1).priority(.low).constraint
+        }
+
+        return view
+    }
+
+    public func update(models: [DrawerListCellModel]) {
+        let cellHeight = 56
+        self.heightConstraint?.update(offset: cellHeight * models.count)
+
+        var snapshot = NSDiffableDataSourceSnapshot<Int, DrawerListCellModel>()
+        snapshot.appendSections([0])
+        snapshot.appendItems(models, toSection: 0)
+        dataSource.apply(snapshot, animatingDifferences: false) { [self] in
+            let frameHeight = collectionView.frame.height
+            let sizeHeight = collectionView.contentSize.height
+            collectionView.isScrollEnabled =  sizeHeight > frameHeight
+        }
+    }
+}
diff --git a/Sources/DrawerFeature/Items/DrawerListCell.swift b/Sources/DrawerFeature/Items/DrawerListCell.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d1ac87a915f165c00a81cf4affbe301c702bf39e
--- /dev/null
+++ b/Sources/DrawerFeature/Items/DrawerListCell.swift
@@ -0,0 +1,77 @@
+import UIKit
+import Shared
+
+final class DrawerListCell: UICollectionViewCell {
+    private let titleLabel = UILabel()
+    private let subtitleLabel = UILabel()
+    private let avatarView = AvatarView()
+    private let stackView = UIStackView()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+
+        backgroundColor = Asset.neutralWhite.color
+
+        titleLabel.font = Fonts.Mulish.semiBold.font(size: 16.0)
+        subtitleLabel.font = Fonts.Mulish.regular.font(size: 14.0)
+        titleLabel.textColor = Asset.neutralActive.color
+
+        stackView.axis = .vertical
+        stackView.addArrangedSubview(titleLabel)
+        stackView.addArrangedSubview(subtitleLabel)
+
+        contentView.addSubview(avatarView)
+        contentView.addSubview(stackView)
+
+        setupConstraints()
+    }
+
+    required init?(coder: NSCoder) { nil }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+
+        titleLabel.text = nil
+        subtitleLabel.text = nil
+        avatarView.prepareForReuse()
+    }
+
+    func set(
+        image: Data?,
+        title: String,
+        subtitle: String?,
+        subtitleColor: UIColor = Asset.accentSafe.color
+    ) {
+        titleLabel.text = title
+        avatarView.setupProfile(
+            title: title,
+            image: image,
+            size: .medium
+        )
+
+        if let subtitle = subtitle {
+            subtitleLabel.text = subtitle
+            subtitleLabel.isHidden = false
+            subtitleLabel.textColor = subtitleColor
+        } else {
+            subtitleLabel.isHidden = true
+        }
+    }
+
+    private func setupConstraints() {
+        avatarView.snp.makeConstraints {
+            $0.width.equalTo(36)
+            $0.height.equalTo(36)
+            $0.top.equalToSuperview().offset(10)
+            $0.left.equalToSuperview()
+            $0.bottom.equalToSuperview().offset(-10)
+        }
+
+        stackView.snp.makeConstraints {
+            $0.left.equalTo(avatarView.snp.right).offset(15)
+            $0.top.equalTo(avatarView)
+            $0.bottom.equalTo(avatarView)
+            $0.right.equalToSuperview()
+        }
+    }
+}
diff --git a/Sources/DrawerFeature/Items/DrawerListCellModel.swift b/Sources/DrawerFeature/Items/DrawerListCellModel.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d9bf356f4bcd54e30e297552aa9efce53d1aa8bb
--- /dev/null
+++ b/Sources/DrawerFeature/Items/DrawerListCellModel.swift
@@ -0,0 +1,23 @@
+import Foundation
+
+public struct DrawerListCellModel: Hashable {
+    let id: Data
+    let image: Data?
+    let title: String
+    let isCreator: Bool
+    let isConnection: Bool
+
+    public init(
+        id: Data,
+        title: String,
+        image: Data? = nil,
+        isCreator: Bool = false,
+        isConnection: Bool = true
+    ) {
+        self.id = id
+        self.title = title
+        self.image = image
+        self.isCreator = isCreator
+        self.isConnection = isConnection
+    }
+}
diff --git a/Sources/DrawerFeature/Items/DrawerTable.swift b/Sources/DrawerFeature/Items/DrawerTable.swift
deleted file mode 100644
index 726dae9fe28ccd5720167a7b4ed1944eebf419e5..0000000000000000000000000000000000000000
--- a/Sources/DrawerFeature/Items/DrawerTable.swift
+++ /dev/null
@@ -1,146 +0,0 @@
-import UIKit
-import Shared
-import SnapKit
-
-enum DrawerTableSection {
-    case main
-}
-
-public final class DrawerTable: DrawerItem {
-    private let view = UIView()
-    private let tableView = UITableView()
-    private var heightConstraint: Constraint?
-    private let dataSource: UITableViewDiffableDataSource<DrawerTableSection, DrawerTableCellModel>
-
-    public var spacingAfter: CGFloat? = 0
-
-    public init(spacingAfter: CGFloat? = 10) {
-        self.dataSource = .init(
-            tableView: tableView,
-            cellProvider: { tableView, indexPath, model in
-                let cell: DrawerTableCell = tableView.dequeueReusableCell(forIndexPath: indexPath)
-
-                cell.titleLabel.text = model.title
-                cell.avatarView.setupProfile(
-                    title: model.title,
-                    image: model.image,
-                    size: .medium
-                )
-
-                if model.isCreator {
-                    cell.subtitleLabel.text = "Creator"
-                    cell.subtitleLabel.isHidden = false
-                    cell.subtitleLabel.textColor = Asset.accentSafe.color
-                } else if !model.isConnection {
-                    cell.subtitleLabel.text = "Not a connection"
-                    cell.subtitleLabel.isHidden = false
-                    cell.subtitleLabel.textColor = Asset.neutralSecondaryAlternative.color
-                } else {
-                    cell.subtitleLabel.isHidden = true
-                }
-
-                return cell
-            })
-
-        self.spacingAfter = spacingAfter
-    }
-
-    public func makeView() -> UIView {
-        tableView.register(DrawerTableCell.self)
-        tableView.dataSource = dataSource
-        tableView.separatorStyle = .none
-
-        view.addSubview(tableView)
-
-        tableView.snp.makeConstraints {
-            $0.edges.equalToSuperview()
-            heightConstraint = $0.height.equalTo(1).priority(.low).constraint
-        }
-
-        return view
-    }
-
-    public func update(models: [DrawerTableCellModel]) {
-        let cellHeight = 56
-        self.heightConstraint?.update(offset: cellHeight * models.count)
-
-        var snapshot = NSDiffableDataSourceSnapshot<DrawerTableSection, DrawerTableCellModel>()
-        snapshot.appendSections([.main])
-        snapshot.appendItems(models, toSection: .main)
-        dataSource.apply(snapshot, animatingDifferences: false) { [self] in
-            tableView.isScrollEnabled = tableView.contentSize.height > tableView.frame.height
-        }
-    }
-}
-
-public struct DrawerTableCellModel: Hashable {
-    let id: Data
-    let title: String
-    let image: Data?
-    let isCreator: Bool
-    let isConnection: Bool
-
-    public init(
-        id: Data,
-        title: String,
-        image: Data? = nil,
-        isCreator: Bool = false,
-        isConnection: Bool = true
-    ) {
-        self.id = id
-        self.title = title
-        self.image = image
-        self.isCreator = isCreator
-        self.isConnection = isConnection
-    }
-}
-
-final class DrawerTableCell: UITableViewCell {
-    let titleLabel = UILabel()
-    let subtitleLabel = UILabel()
-    let avatarView = AvatarView()
-    let stackView = UIStackView()
-
-    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
-        super.init(style: style, reuseIdentifier: reuseIdentifier)
-
-        selectionStyle = .none
-        backgroundColor = Asset.neutralWhite.color
-
-        titleLabel.font = Fonts.Mulish.semiBold.font(size: 16.0)
-        subtitleLabel.font = Fonts.Mulish.regular.font(size: 14.0)
-        titleLabel.textColor = Asset.neutralActive.color
-
-        stackView.axis = .vertical
-        stackView.addArrangedSubview(titleLabel)
-        stackView.addArrangedSubview(subtitleLabel)
-
-        contentView.addSubview(avatarView)
-        contentView.addSubview(stackView)
-
-        avatarView.snp.makeConstraints {
-            $0.width.equalTo(36)
-            $0.height.equalTo(36)
-            $0.top.equalToSuperview().offset(10)
-            $0.left.equalToSuperview()
-            $0.bottom.equalToSuperview().offset(-10)
-        }
-
-        stackView.snp.makeConstraints {
-            $0.left.equalTo(avatarView.snp.right).offset(15)
-            $0.top.equalTo(avatarView)
-            $0.bottom.equalTo(avatarView)
-            $0.right.equalToSuperview()
-        }
-    }
-
-    required init?(coder: NSCoder) { nil }
-
-    override func prepareForReuse() {
-        super.prepareForReuse()
-
-        titleLabel.text = nil
-        subtitleLabel.text = nil
-        avatarView.prepareForReuse()
-    }
-}
diff --git a/Sources/RequestsFeature/Controllers/RequestsReceivedController.swift b/Sources/RequestsFeature/Controllers/RequestsReceivedController.swift
index 0a30d05fb32b5ec4d3eb54b1fdeb9ced674a17ac..37f37faedf409d55f04fcd118290606c2fae5884 100644
--- a/Sources/RequestsFeature/Controllers/RequestsReceivedController.swift
+++ b/Sources/RequestsFeature/Controllers/RequestsReceivedController.swift
@@ -299,7 +299,7 @@ extension RequestsReceivedController {
 
         items.append(drawerLoading)
 
-        let drawerTable = DrawerTable(spacingAfter: 23)
+        let drawerTable = DrawerList(spacingAfter: 23)
 
         drawerLoading.retryPublisher
             .receive(on: DispatchQueue.main)
diff --git a/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift
index ded18f77a4da0d956d2bdb0b1779495c818d41f5..4a38f458c60fd2b95536bed3d51f065242269e11 100644
--- a/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift
+++ b/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift
@@ -165,7 +165,7 @@ final class RequestsReceivedViewModel {
 
     func fetchMembers(
         _ group: Group,
-        _ completion: @escaping (Result<[DrawerTableCellModel], Error>) -> Void
+        _ completion: @escaping (Result<[DrawerListCellModel], Error>) -> Void
     ) {
         if let info = try? session.dbManager.fetchGroupInfos(.init(groupId: group.id)).first {
             session.dbManager.fetchContactsPublisher(.init(id: Set(info.members.map(\.id))))
@@ -174,7 +174,7 @@ final class RequestsReceivedViewModel {
                     let withUsername = members
                         .filter { $0.username != nil }
                         .map {
-                            DrawerTableCellModel(
+                            DrawerListCellModel(
                                 id: $0.id,
                                 title: $0.nickname ?? $0.username!,
                                 image: $0.photo,
@@ -186,7 +186,7 @@ final class RequestsReceivedViewModel {
                     let withoutUsername = members
                         .filter { $0.username == nil }
                         .map {
-                            DrawerTableCellModel(
+                            DrawerListCellModel(
                                 id: $0.id,
                                 title: "Fetching username...",
                                 image: $0.photo,
diff --git a/Sources/RequestsFeature/Views/RequestsReceivedView.swift b/Sources/RequestsFeature/Views/RequestsReceivedView.swift
index d4df66fea6dae47ee46dac61451f45a05fa2b4e7..9874c4558590659be417a0df6a7bc915dc4c9441 100644
--- a/Sources/RequestsFeature/Views/RequestsReceivedView.swift
+++ b/Sources/RequestsFeature/Views/RequestsReceivedView.swift
@@ -36,7 +36,6 @@ final class RequestsReceivedView: UIView {
         let layout = UICollectionViewCompositionalLayout(section: section)
 
         let collectionView = UICollectionView(frame: bounds, collectionViewLayout: layout)
-        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
         collectionView.backgroundColor = Asset.neutralWhite.color
         collectionView.contentInset = .init(top: 15, left: 0, bottom: 0, right: 0)
         return collectionView
diff --git a/Sources/SearchFeature/Controllers/SearchLeftController.swift b/Sources/SearchFeature/Controllers/SearchLeftController.swift
index e7c393820a83b14948fc42fc8aa2fe5ac5a445de..c4176b345a89399ba0b642bbbe4e73e6e7e0d298 100644
--- a/Sources/SearchFeature/Controllers/SearchLeftController.swift
+++ b/Sources/SearchFeature/Controllers/SearchLeftController.swift
@@ -142,7 +142,6 @@ final class SearchLeftController: UIViewController {
                         .sink { [unowned self] in viewModel.didTapCancelSearch() }
                         .store(in: &self.hudCancellables)
                 } else {
-                    hudCancellables.forEach { $0.cancel() }
                     hudCancellables.removeAll()
                 }
             }
diff --git a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
index d7749c1598d91d559978909829cc87d5a2a07b2e..a9beb9e58d3249aaaf5ce6a4da2ead219fcd0452 100644
--- a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
+++ b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
@@ -59,7 +59,6 @@ final class SearchLeftViewModel {
     }
 
     func didTapCancelSearch() {
-        searchCancellables.forEach { $0.cancel() }
         searchCancellables.removeAll()
         hudSubject.send(.none)
     }
diff --git a/Sources/SearchFeature/Views/SearchLeftView.swift b/Sources/SearchFeature/Views/SearchLeftView.swift
index 53730b9bc434ed82d5b0244e0dd84b6069b2d738..1474be9094953c7f31ed73a7bb7f228f1d0c447e 100644
--- a/Sources/SearchFeature/Views/SearchLeftView.swift
+++ b/Sources/SearchFeature/Views/SearchLeftView.swift
@@ -50,7 +50,6 @@ final class SearchLeftView: UIView {
 
         let layout = UICollectionViewCompositionalLayout(section: section)
         let collectionView = UICollectionView(frame: bounds, collectionViewLayout: layout)
-        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
         collectionView.backgroundColor = Asset.neutralWhite.color
         return collectionView
     }()
diff --git a/Sources/Shared/Controllers/DiffEditableDataSource.swift b/Sources/Shared/Controllers/DiffEditableDataSource.swift
deleted file mode 100644
index 9103733b120a2f7ff7a3a25be34c9ce6c2f3a6eb..0000000000000000000000000000000000000000
--- a/Sources/Shared/Controllers/DiffEditableDataSource.swift
+++ /dev/null
@@ -1,13 +0,0 @@
-import UIKit
-
-public struct SectionId: Hashable {
-    public init() {}
-}
-
-public final class DiffEditableDataSource<SectionIdentifierType, ItemIdentifierType>
-: UITableViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType>
-where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable {
-
-    public override func tableView(_ tableView: UITableView,
-                                   canEditRowAt indexPath: IndexPath) -> Bool { true }
-}
diff --git a/Sources/Shared/EditStateHandler.swift b/Sources/Shared/EditStateHandler.swift
deleted file mode 100644
index 1a8d4c7e89edb3449118679c03e87fc4c1afcc08..0000000000000000000000000000000000000000
--- a/Sources/Shared/EditStateHandler.swift
+++ /dev/null
@@ -1,18 +0,0 @@
-import Combine
-
-public final class EditStateHandler {
-    // MARK: Properties
-
-    public var isEditing: AnyPublisher<Bool, Never> { stateRelay.eraseToAnyPublisher() }
-    private let stateRelay = CurrentValueSubject<Bool, Never>(false)
-
-    // MARK: Lifecycle
-
-    public init() {}
-
-    // MARK: Public
-
-    public func didSwitchEditing() {
-        stateRelay.value.toggle()
-    }
-}
diff --git a/Sources/Shared/Views/AvatarCell.swift b/Sources/Shared/Views/AvatarCell.swift
index cc39fc573e9832d1b967fd6d30f550bb134af197..8dea6ba2b9b2a6f26e72aba615a98ed95c22321a 100644
--- a/Sources/Shared/Views/AvatarCell.swift
+++ b/Sources/Shared/Views/AvatarCell.swift
@@ -76,7 +76,6 @@ public final class AvatarCell: UICollectionViewCell {
         avatarView.prepareForReuse()
         actionButton.prepareForReuse()
 
-        cancellables.forEach { $0.cancel() }
         cancellables.removeAll()
     }
 
@@ -107,23 +106,11 @@ public final class AvatarCell: UICollectionViewCell {
         separatorView.isHidden = !showSeparator
 
         if let action = action {
-            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)
+            update(action: action)
         }
     }
 
     public func update(action: Action) {
-        cancellables.forEach { $0.cancel() }
         cancellables.removeAll()
 
         actionButton.set(