From 34e0c3d467a8344e756c65225911bf83a732390f Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:07:59 +0200 Subject: [PATCH 01/10] Renames FiltersBarView to EventsFiltersBarView --- NOICommunity.xcodeproj/project.pbxproj | 16 ++++++++-------- .../EventsMainViewController.swift | 2 +- .../EventsMainViewController.xib | 8 ++++---- ...sBarView.swift => EventsFiltersBarView.swift} | 8 ++++---- ...ltersBarView.xib => EventsFiltersBarView.xib} | 7 +++---- 5 files changed, 20 insertions(+), 21 deletions(-) rename NOICommunity/TodayFeature/EventsFeature/Views/{FiltersBarView.swift => EventsFiltersBarView.swift} (98%) rename NOICommunity/TodayFeature/EventsFeature/Views/{FiltersBarView.xib => EventsFiltersBarView.xib} (92%) diff --git a/NOICommunity.xcodeproj/project.pbxproj b/NOICommunity.xcodeproj/project.pbxproj index 8fd7406..dc3f954 100644 --- a/NOICommunity.xcodeproj/project.pbxproj +++ b/NOICommunity.xcodeproj/project.pbxproj @@ -177,8 +177,8 @@ 31C2261C270F596E0098A70E /* EventCardContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 315F4BE127034C00001905AF /* EventCardContentView.xib */; }; 31C2261D270F59750098A70E /* EventDetailsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3187667826FB3A9300782FA6 /* EventDetailsViewController.xib */; }; 31C28BF62719709B00312A62 /* NOICells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C28BF52719709B00312A62 /* NOICells.swift */; }; - 31C28BF8271992F500312A62 /* FiltersBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C28BF7271992F500312A62 /* FiltersBarView.swift */; }; - 31C28BFA2719931400312A62 /* FiltersBarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 31C28BF92719931400312A62 /* FiltersBarView.xib */; }; + 31C28BF8271992F500312A62 /* EventsFiltersBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C28BF7271992F500312A62 /* EventsFiltersBarView.swift */; }; + 31C28BFA2719931400312A62 /* EventsFiltersBarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 31C28BF92719931400312A62 /* EventsFiltersBarView.xib */; }; 31C28BFD2719BD7200312A62 /* LoadingViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 31C28BFB2719BD7200312A62 /* LoadingViewController.xib */; }; 31C28BFE2719BD7200312A62 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C28BFC2719BD7200312A62 /* LoadingViewController.swift */; }; 31C3629F270EFC5C00C92532 /* UIButton+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C3629E270EFC5C00C92532 /* UIButton+Background.swift */; }; @@ -409,8 +409,8 @@ 31C028402B55924B00D851EE /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = ""; }; 31C14C2227DA3597009AF69D /* UIScrollView+ScrollToView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+ScrollToView.swift"; sourceTree = ""; }; 31C28BF52719709B00312A62 /* NOICells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NOICells.swift; sourceTree = ""; }; - 31C28BF7271992F500312A62 /* FiltersBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersBarView.swift; sourceTree = ""; }; - 31C28BF92719931400312A62 /* FiltersBarView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FiltersBarView.xib; sourceTree = ""; }; + 31C28BF7271992F500312A62 /* EventsFiltersBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsFiltersBarView.swift; sourceTree = ""; }; + 31C28BF92719931400312A62 /* EventsFiltersBarView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EventsFiltersBarView.xib; sourceTree = ""; }; 31C28BFB2719BD7200312A62 /* LoadingViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LoadingViewController.xib; sourceTree = ""; }; 31C28BFC2719BD7200312A62 /* LoadingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = ""; }; 31C3629E270EFC5C00C92532 /* UIButton+Background.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Background.swift"; sourceTree = ""; }; @@ -513,8 +513,8 @@ 315F4BE327035679001905AF /* EventCardContentConfiguration.SharedConfig.swift */, 31AA31F026F0B40800744A00 /* EventCardContentView.swift */, 315F4BE127034C00001905AF /* EventCardContentView.xib */, - 31C28BF7271992F500312A62 /* FiltersBarView.swift */, - 31C28BF92719931400312A62 /* FiltersBarView.xib */, + 31C28BF7271992F500312A62 /* EventsFiltersBarView.swift */, + 31C28BF92719931400312A62 /* EventsFiltersBarView.xib */, ); path = Views; sourceTree = ""; @@ -1204,7 +1204,7 @@ 31515A20286C868600642907 /* SourceSansPro-LightItalic.ttf in Resources */, 3121AFDE2858B43A00248CDF /* MeetMainViewController.xib in Resources */, 31515A1F286C868600642907 /* SourceSansPro-Bold.ttf in Resources */, - 31C28BFA2719931400312A62 /* FiltersBarView.xib in Resources */, + 31C28BFA2719931400312A62 /* EventsFiltersBarView.xib in Resources */, 313010CD2846102000AF6520 /* MyAccountViewController.xib in Resources */, 31EBA3742807FAD9001AAE8F /* AuthWelcomeViewController.xib in Resources */, 3132EF3A283D29E00016DF7F /* PersonCardContentView.xib in Resources */, @@ -1335,7 +1335,7 @@ 312F5D292808252900C84598 /* WelcomeViewModel.swift in Sources */, 31DAC7BE2B568A0100F24D79 /* IndexPathAdditions.swift in Sources */, 3101FC5B283394FA00A3416F /* TodayCoordinator.swift in Sources */, - 31C28BF8271992F500312A62 /* FiltersBarView.swift in Sources */, + 31C28BF8271992F500312A62 /* EventsFiltersBarView.swift in Sources */, 3145D23326B3F73F00F16787 /* SceneDelegate.swift in Sources */, 31B192722C6A367D009872E9 /* DeveloperToolsViewController.swift in Sources */, 31AA31E826F09E3600744A00 /* Event.swift in Sources */, diff --git a/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.swift b/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.swift index 01b35dc..fbca53a 100644 --- a/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.swift +++ b/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.swift @@ -66,7 +66,7 @@ final class EventsMainViewController: UIViewController { } @IBOutlet private var filterBarContainerView: UIView! - @IBOutlet private var filterBarView: FiltersBarView! + @IBOutlet private var filterBarView: EventsFiltersBarView! @IBOutlet private var contentContainerView: UIView! private var dateIntervalsControl: UISegmentedControl { diff --git a/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.xib b/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.xib index f7a377f..998cf41 100644 --- a/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.xib +++ b/NOICommunity/TodayFeature/EventsFeature/View Controllers/EventsMainViewController.xib @@ -1,9 +1,9 @@ - + - + @@ -29,8 +29,8 @@ - - + + diff --git a/NOICommunity/TodayFeature/EventsFeature/Views/FiltersBarView.swift b/NOICommunity/TodayFeature/EventsFeature/Views/EventsFiltersBarView.swift similarity index 98% rename from NOICommunity/TodayFeature/EventsFeature/Views/FiltersBarView.swift rename to NOICommunity/TodayFeature/EventsFeature/Views/EventsFiltersBarView.swift index d84a87d..6f463b3 100644 --- a/NOICommunity/TodayFeature/EventsFeature/Views/FiltersBarView.swift +++ b/NOICommunity/TodayFeature/EventsFeature/Views/EventsFiltersBarView.swift @@ -13,7 +13,7 @@ import UIKit // MARK: - FiltersBarView -class FiltersBarView: UIView { +class EventsFiltersBarView: UIView { @IBOutlet private(set) var scrollView: UIScrollView! @IBOutlet private(set) var filtersButton: UIButton! { @@ -56,7 +56,7 @@ class FiltersBarView: UIView { // MARK: Private APIs -private extension FiltersBarView { +private extension EventsFiltersBarView { class SegmentedControl: UISegmentedControl { @@ -81,7 +81,7 @@ private extension FiltersBarView { // Load containerView from its xib and embed it as a subview Bundle.main.loadNibNamed( - "\(FiltersBarView.self)", + "\(EventsFiltersBarView.self)", owner: self, options: nil ) @@ -124,7 +124,7 @@ private extension FiltersBarView { // MARK: - FiltersBarView.SegmentedControlImageFactory -private extension FiltersBarView { +private extension EventsFiltersBarView { @objc func selectedFilterValueDidChange(sender: UISegmentedControl) { let selectedSegmentIndex = sender.selectedSegmentIndex diff --git a/NOICommunity/TodayFeature/EventsFeature/Views/FiltersBarView.xib b/NOICommunity/TodayFeature/EventsFeature/Views/EventsFiltersBarView.xib similarity index 92% rename from NOICommunity/TodayFeature/EventsFeature/Views/FiltersBarView.xib rename to NOICommunity/TodayFeature/EventsFeature/Views/EventsFiltersBarView.xib index c91a93e..3fb29b2 100644 --- a/NOICommunity/TodayFeature/EventsFeature/Views/FiltersBarView.xib +++ b/NOICommunity/TodayFeature/EventsFeature/Views/EventsFiltersBarView.xib @@ -1,15 +1,14 @@ - + - - + - + From 84fa651163a5b2f36bf2e4cdda2452f78b6fe603 Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:25:05 +0200 Subject: [PATCH 02/10] Updates UX/UI of companies filters list in the Meet section --- NOICommunity.xcodeproj/project.pbxproj | 4 + .../CompaniesFiltersViewController.swift | 112 +++++-- .../CompaniesFiltersViewController.xib | 27 +- .../View Models/CompanyViewModel.swift | 174 +++++++++-- .../EventsMainViewController.xib | 1 - .../Views/EventsFiltersBarView.swift | 249 ++-------------- .../Views/EventsFiltersBarView.xib | 58 ++-- NOICommunity/Views/FiltersBarView.swift | 273 ++++++++++++++++++ NOICommunity/de.lproj/InfoPlist.strings | 2 +- NOICommunity/de.lproj/Localizable.strings | 19 +- NOICommunity/en.lproj/InfoPlist.strings | 2 +- NOICommunity/en.lproj/Localizable.strings | 19 +- NOICommunity/it.lproj/InfoPlist.strings | 2 +- NOICommunity/it.lproj/Localizable.strings | 19 +- 14 files changed, 620 insertions(+), 341 deletions(-) create mode 100644 NOICommunity/Views/FiltersBarView.swift diff --git a/NOICommunity.xcodeproj/project.pbxproj b/NOICommunity.xcodeproj/project.pbxproj index dc3f954..15a8e80 100644 --- a/NOICommunity.xcodeproj/project.pbxproj +++ b/NOICommunity.xcodeproj/project.pbxproj @@ -174,6 +174,7 @@ 31BFAB3B283FC88A00EF274D /* CALayer+XibConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BFAB3A283FC88A00EF274D /* CALayer+XibConfiguration.swift */; }; 31C028412B55924B00D851EE /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C028402B55924B00D851EE /* FeatureFlag.swift */; }; 31C14C2327DA3597009AF69D /* UIScrollView+ScrollToView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C14C2227DA3597009AF69D /* UIScrollView+ScrollToView.swift */; }; + 31C1ECB82C74E248004C9104 /* FiltersBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C1ECB72C74E248004C9104 /* FiltersBarView.swift */; }; 31C2261C270F596E0098A70E /* EventCardContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 315F4BE127034C00001905AF /* EventCardContentView.xib */; }; 31C2261D270F59750098A70E /* EventDetailsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3187667826FB3A9300782FA6 /* EventDetailsViewController.xib */; }; 31C28BF62719709B00312A62 /* NOICells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C28BF52719709B00312A62 /* NOICells.swift */; }; @@ -408,6 +409,7 @@ 31BFAB3A283FC88A00EF274D /* CALayer+XibConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+XibConfiguration.swift"; sourceTree = ""; }; 31C028402B55924B00D851EE /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = ""; }; 31C14C2227DA3597009AF69D /* UIScrollView+ScrollToView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+ScrollToView.swift"; sourceTree = ""; }; + 31C1ECB72C74E248004C9104 /* FiltersBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersBarView.swift; sourceTree = ""; }; 31C28BF52719709B00312A62 /* NOICells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NOICells.swift; sourceTree = ""; }; 31C28BF7271992F500312A62 /* EventsFiltersBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsFiltersBarView.swift; sourceTree = ""; }; 31C28BF92719931400312A62 /* EventsFiltersBarView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EventsFiltersBarView.xib; sourceTree = ""; }; @@ -887,6 +889,7 @@ 313010CE28463F1000AF6520 /* ContentConfiguration.swift */, 318664A12B22471E0088A752 /* LinkTextView.swift */, 31B192772C6A434B009872E9 /* BaseWindow.swift */, + 31C1ECB72C74E248004C9104 /* FiltersBarView.swift */, ); path = Views; sourceTree = ""; @@ -1319,6 +1322,7 @@ 3153010528071D1200471153 /* AuthWelcomePageViewController.swift in Sources */, 316F5615281C166B0075B09F /* MyAccountViewController.swift in Sources */, 31C028412B55924B00D851EE /* FeatureFlag.swift in Sources */, + 31C1ECB82C74E248004C9104 /* FiltersBarView.swift in Sources */, 31C640B126FE1449004B71A2 /* TabCoordinatorType.swift in Sources */, 31A5F05527D25A9400FA20BC /* EventFiltersViewController.swift in Sources */, 317B6F9A28118950008D07C0 /* ClientFactory.swift in Sources */, diff --git a/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift b/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift index 7195c0a..e0768a9 100644 --- a/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift +++ b/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift @@ -22,7 +22,21 @@ final class CompaniesFiltersViewController: UIViewController { searchBar.placeholder = .localized("search_label") } } - + + @IBOutlet private var filtersBarView: FiltersBarView! { + didSet { + filtersBarView.items = companyViewModel + .filterItems + .map(\.title) + filtersBarView.scrollView.contentInset = .init( + top: 0, + left: 8, + bottom: 0, + right: 8 + ) + } + } + @IBOutlet private var searchBarContainerView: UIView! @IBOutlet private var actionsContainersView: FooterView! @@ -42,7 +56,15 @@ final class CompaniesFiltersViewController: UIViewController { .configureAsPrimaryActionButton() } } - + + private var filters: UISegmentedControl { + filtersBarView.segmentedControl + } + + private var filtersScrollView: UIScrollView { + filtersBarView.scrollView + } + private var subscriptions: Set = [] private lazy var companyViewModel = peopleViewModel.makeCompanyViewModel() @@ -125,6 +147,9 @@ final class CompaniesFiltersViewController: UIViewController { private extension CompaniesFiltersViewController { + typealias DataSource = UICollectionViewDiffableDataSource + typealias Snapshot = NSDiffableDataSourceSnapshot + func configureBindings() { searchBar.delegate = resultsVC @@ -153,12 +178,13 @@ private extension CompaniesFiltersViewController { } .store(in: &subscriptions) - companyViewModel.$results + companyViewModel + .$results .map { $0?.1.isEmpty } .sink { [weak self] isEmpty in guard let self = self else { return } - + if isEmpty == true { self.containerVC.content = self.emptyResultsVC } else { @@ -166,6 +192,54 @@ private extension CompaniesFiltersViewController { } } .store(in: &subscriptions) + + companyViewModel + .$activeFilter + .sink { [weak filters, weak companyViewModel] newActiveFilter in + guard let filters, + let companyViewModel + else { return } + + if let matchingIndex = companyViewModel.filterItems.firstIndex(of: newActiveFilter) { + filters.selectedSegmentIndex = matchingIndex + } else { + filters.selectedSegmentIndex = UISegmentedControl.noSegment + } + } + .store(in: &subscriptions) + + filters + .publisher(for: .valueChanged) + .sink { [weak filters, weak companyViewModel, weak filtersScrollView] in + guard let filters, + let companyViewModel, + let filtersScrollView + else { return } + + let selectedSegmentIndex = filters.selectedSegmentIndex + let newSelectedFilter = companyViewModel.filterItems[selectedSegmentIndex] + companyViewModel.filterBy(filter: newSelectedFilter) + + let convertRect: (UIView) -> CGRect = { + $0.convert($0.frame, to: filtersScrollView) + } + let selectedControls = filters + .recursiveSubviews { $0 is UILabel } + .sorted { convertRect($0).minX < convertRect($1).minX } + let selectedControl = selectedControls[selectedSegmentIndex] + let selectedControlRect = convertRect(selectedControl) + if !filtersScrollView.bounds.contains( + selectedControlRect + ) { + let targetScrollingRect = selectedControlRect + .insetBy(dx: -100, dy: 0) + filtersScrollView.scrollRectToVisible( + targetScrollingRect, + animated: true + ) + } + } + .store(in: &subscriptions) } } @@ -179,8 +253,8 @@ private extension CompaniesFiltersViewController { let companyViewModel: CompanyViewModel - private var dataSource: UICollectionViewDiffableDataSource! = nil - + private var dataSource: DataSource! + var didSelectHandler: ((CompanyId) -> Void)? private var subscriptions: Set = [] @@ -291,25 +365,15 @@ private extension CompaniesFiltersViewController.CollectionViewController { } let headerRegistration = UICollectionView - .SupplementaryRegistration( + .SupplementaryRegistration( elementKind: UICollectionView.elementKindSectionHeader ) { cell, kind, indexPath in - var config = UIListContentConfiguration.noiGroupedHeader() - - let companyTag = self.dataSource + let initial = self.dataSource .snapshot() .sectionIdentifiers[indexPath.section] - switch companyTag { - case .researchInstitution: - config.text = .localized("filter_by_research_institution") - case .startup: - config.text = .localized("filter_by_startup") - case .company: - config.text = .localized("filter_by_company") - default: - break - } - + + var config = UIListContentConfiguration.noiGroupedHeader() + config.text = initial.value cell.contentConfiguration = config } @@ -339,11 +403,11 @@ private extension CompaniesFiltersViewController.CollectionViewController { } func updateUI( - _ result: ([Company.Tag], [Company.Tag: [CompanyId]]), + _ result: ([Initial], [Initial: [CompanyId]]), animated: Bool ) { let (sections, sectionToItems) = result - var snapshot = NSDiffableDataSourceSnapshot() + var snapshot = CompaniesFiltersViewController.Snapshot() snapshot.appendSections(sections) for section in sections { snapshot.appendItems(sectionToItems[section]!, toSection: section) @@ -417,7 +481,7 @@ extension CompaniesFiltersViewController.CollectionViewController: UISearchBarDe } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { - companyViewModel.filter(searchTerm: searchText) + companyViewModel.filterBy(searchTerm: searchText) } } diff --git a/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.xib b/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.xib index b25f1f2..98e3f18 100644 --- a/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.xib +++ b/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.xib @@ -1,9 +1,9 @@ - + - + @@ -13,6 +13,7 @@ + @@ -26,13 +27,13 @@ - + - + + + + + + + + + + - + - - - - - - - + + + + - + diff --git a/NOICommunity/Views/FiltersBarView.swift b/NOICommunity/Views/FiltersBarView.swift new file mode 100644 index 0000000..bd4ce41 --- /dev/null +++ b/NOICommunity/Views/FiltersBarView.swift @@ -0,0 +1,273 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +// +// FiltersBarView.swift +// NOICommunity +// +// Created by Matteo Matassoni on 20/08/24. +// + +import UIKit + +// MARK: - FiltersBarView + +class FiltersBarView: UIView { + + var items: [String] = [] { + didSet { + guard items != oldValue + else { return } + + segmentedControl.removeAllSegments() + items.reversed().forEach { + segmentedControl.insertSegment( + withTitle: $0, + at: 0, + animated: false + ) + } + } + } + + lazy private(set) var scrollView = UIScrollView() + + lazy private(set) var segmentedControl: UISegmentedControl = { + let activeColor = UIColor.noiSecondaryColor + let color = activeColor.withAlphaComponent(0.5) + var builder = SegmentedControlBuilder( + imageFactory: NoiSegmentedControlImageFactory() + ) + builder.tintColor = color + builder.selectedTintedColor = activeColor + builder.font = .NOI.fixed.caption1Semibold + builder.selectedFont = builder.font + builder.class = SegmentedControl.self + let segmentedControl = builder.makeSegmentedControl( + items: items + ) + segmentedControl.clipsToBounds = false + return segmentedControl + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setup() + } + +} + +// MARK: Private APIs + +private extension FiltersBarView { + + class SegmentedControl: UISegmentedControl { + + // Removes swipe gesture + override func gestureRecognizerShouldBegin( + _ gestureRecognizer: UIGestureRecognizer + ) -> Bool { + true + } + + override func layoutSubviews() { + super.layoutSubviews() + + // Force a square shape + layer.cornerRadius = 0 + } + + } + + func setup() { + backgroundColor = .noiSecondaryBackgroundColor + + embedSubview(scrollView) + configureScrollView() + segmentedControl.addTarget( + self, + action: #selector(selectedFilterValueDidChange(sender:)), + for: .valueChanged + ) + } + + func configureScrollView() { + scrollView.showsHorizontalScrollIndicator = false + scrollView.showsVerticalScrollIndicator = false + scrollView.addSubview(segmentedControl) + segmentedControl.translatesAutoresizingMaskIntoConstraints = false + let contentGuide = scrollView.contentLayoutGuide + let frameGuide = scrollView.frameLayoutGuide + NSLayoutConstraint.activate([ + segmentedControl.leadingAnchor + .constraint(equalTo: contentGuide.leadingAnchor), + segmentedControl.trailingAnchor + .constraint(equalTo: contentGuide.trailingAnchor), + segmentedControl.bottomAnchor + .constraint(equalTo: contentGuide.bottomAnchor), + segmentedControl.topAnchor + .constraint(equalTo: contentGuide.topAnchor), + frameGuide.heightAnchor + .constraint(equalTo: contentGuide.heightAnchor) + ]) + } + +} + +// MARK: - FiltersBarView.SegmentedControlImageFactory + +private extension FiltersBarView { + + @objc func selectedFilterValueDidChange(sender: UISegmentedControl) { + let selectedSegmentIndex = sender.selectedSegmentIndex + let convertRect: (UIView) -> CGRect = { + $0.convert($0.frame, to: self.scrollView) + } + let selectedControls = segmentedControl + .recursiveSubviews { $0 is UILabel } + .sorted { convertRect($0).minX < convertRect($1).minX } + let selectedControl = selectedControls[selectedSegmentIndex] + scrollView.scrollToView( + view: selectedControl, + position: .middle, + animated: true + ) + } + + struct NoiSegmentedControlImageFactory: SegmentedControlImageFactory { + + var height: CGFloat = 40 + var spacing: CGFloat = 5 + var selectedStates: [UIControl.State] = [.selected, .highlighted] + var lineWidth: CGFloat = 2 + var fillColor = UIColor.noiPrimaryColor + var lineColor = UIColor.noiInactiveColor + var selectedLineColor = UIColor.noiSecondaryColor + var cornerRadius: CGFloat = 2 + var edgeOffset: CGFloat { + 0 + } + + func background(for state: UIControl.State) -> UIImage? { + let imageSize = CGSize(width: cornerRadius * 2 + 1 , height: height) + let renderer = UIGraphicsImageRenderer(size: imageSize) + + return renderer.image { context in + let canvasRect = CGRect(origin: .zero, size: imageSize) + let roundedRectPath = UIBezierPath( + roundedRect: canvasRect.insetBy( + dx: lineWidth / 2, + dy: lineWidth / 2 + ), + cornerRadius: cornerRadius + ) + roundedRectPath.lineWidth = lineWidth + strokeColor(for: state).setStroke() + roundedRectPath.stroke() + fillColor.setFill() + roundedRectPath.fill() + } + } + + func divider( + leftState: UIControl.State, + rightState: UIControl.State + ) -> UIImage? { + let halfRoundedRectSize = CGSize( + width: cornerRadius + 1, + height: height + ) + let cornerRadii = CGSize(width: cornerRadius, height: cornerRadius) + let imageSize = CGSize( + width: halfRoundedRectSize.width * 2 + spacing, + height: halfRoundedRectSize.height + ) + let renderer = UIGraphicsImageRenderer(size: imageSize) + + let image = renderer.image { context in + fillColor.setFill() + + let leftHalfRoundedRectRect = CGRect( + origin: .zero, + size: halfRoundedRectSize + ) + let leftHalfRoundedRectPath = UIBezierPath( + roundedRect: leftHalfRoundedRectRect.insetBy( + dx: lineWidth / 2, + dy: lineWidth / 2 + ), + byRoundingCorners: [.topRight, .bottomRight], + cornerRadii: cornerRadii + ) + leftHalfRoundedRectPath.lineWidth = lineWidth + strokeColor(for: leftState).setStroke() + leftHalfRoundedRectPath.stroke() + leftHalfRoundedRectPath.fill() + + let rightHalfRoundedRectRect = leftHalfRoundedRectRect + .offsetBy( + dx: leftHalfRoundedRectRect.maxX + spacing, + dy: 0 + ) + let rightHalfRoundedRectPath = UIBezierPath( + roundedRect: rightHalfRoundedRectRect.insetBy( + dx: lineWidth / 2, + dy: lineWidth / 2 + ), + byRoundingCorners: [.topLeft, .bottomLeft], + cornerRadii: cornerRadii + ) + rightHalfRoundedRectPath.lineWidth = lineWidth + strokeColor(for: rightState).setStroke() + rightHalfRoundedRectPath.stroke() + rightHalfRoundedRectPath.fill() + } + + return image.cropped(with: CGRect( + origin: .zero, + size: imageSize + ).insetBy(dx: lineWidth / 2, dy: 0) + ) + } + + private func strokeColor(for state: UIControl.State) -> UIColor { + switch state { + case .selected, + .highlighted, + [.selected, .highlighted]: + return selectedLineColor + default: + return lineColor + } + } + + } + +} + +private extension UIImage { + + func cropped(with cropRect: CGRect) -> UIImage { + var rect = cropRect + rect.origin.x *= scale + rect.origin.y *= scale + rect.size.width *= scale + rect.size.height *= scale + + let croppedCGImage = cgImage!.cropping( + to: rect + )! + return UIImage( + cgImage: croppedCGImage, + scale: scale, + orientation: imageOrientation + ) + } + +} diff --git a/NOICommunity/de.lproj/InfoPlist.strings b/NOICommunity/de.lproj/InfoPlist.strings index 20e6619..06598f4 100755 --- a/NOICommunity/de.lproj/InfoPlist.strings +++ b/NOICommunity/de.lproj/InfoPlist.strings @@ -2,7 +2,7 @@ * InfoPlist.strings (de) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-01-16T11:00:11+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/de.lproj/Localizable.strings b/NOICommunity/de.lproj/Localizable.strings index fd12329..191b88e 100755 --- a/NOICommunity/de.lproj/Localizable.strings +++ b/NOICommunity/de.lproj/Localizable.strings @@ -2,7 +2,7 @@ * Localizable.strings (de) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-01-16T11:00:11+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 * Please do not edit this file by hand, use the export function from Google Sheet. */ @@ -93,18 +93,21 @@ /* Tab Today: title of top tab Events */ "events_top_tab" = "Events"; -/* Company filters page: title section - Filter by company */ -"filter_by_company" = "Nach Unternehmen filtern"; +/* Companies filters in Meet section: Button title - Filter by All */ +"filter_by_none" = "Alles"; -/* Company filters page: title section - Filter by Research and Institution */ -"filter_by_research_institution" = "Nach Institutionen filtern"; +/* Companies filters in Meet section: Button title - Filter by Companies */ +"filter_by_company" = "Unternehmen"; + +/* Companies filters in Meet section: Button title - Filter by Research and Institution */ +"filter_by_research_institution" = "Institutionen"; + +/* Companies filter in Meet section: Button title - Filter by Startups */ +"filter_by_startup" = "Start-ups"; /* Filters page: title section - Filter by technology sector */ "filter_by_sector" = "Nach Technologiefeld filtern"; -/* Company filters page: title section - Filter by star-up */ -"filter_by_startup" = "Nach Start-ups filtern"; - /* Filters page: title section - Filter by event type */ "filter_by_type" = "Nach Eventart filtern"; diff --git a/NOICommunity/en.lproj/InfoPlist.strings b/NOICommunity/en.lproj/InfoPlist.strings index 95060c1..422b63a 100755 --- a/NOICommunity/en.lproj/InfoPlist.strings +++ b/NOICommunity/en.lproj/InfoPlist.strings @@ -2,7 +2,7 @@ * InfoPlist.strings (en) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-01-16T11:00:11+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/en.lproj/Localizable.strings b/NOICommunity/en.lproj/Localizable.strings index 282da07..4a881d9 100755 --- a/NOICommunity/en.lproj/Localizable.strings +++ b/NOICommunity/en.lproj/Localizable.strings @@ -2,7 +2,7 @@ * Localizable.strings (en) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-01-16T11:00:11+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 * Please do not edit this file by hand, use the export function from Google Sheet. */ @@ -93,18 +93,21 @@ /* Tab Today: title of top tab Events */ "events_top_tab" = "Events"; -/* Company filters page: title section - Filter by company */ -"filter_by_company" = "Filter by companies"; +/* Companies filters in Meet section: Button title - Filter by All */ +"filter_by_none" = "All"; -/* Company filters page: title section - Filter by Research and Institution */ -"filter_by_research_institution" = "Filter by institutions"; +/* Companies filters in Meet section: Button title - Filter by Companies */ +"filter_by_company" = "Companies"; + +/* Companies filters in Meet section: Button title - Filter by Research and Institution */ +"filter_by_research_institution" = "Institutions"; + +/* Companies filter in Meet section: Button title - Filter by Startups */ +"filter_by_startup" = "Start-ups"; /* Filters page: title section - Filter by technology sector */ "filter_by_sector" = "Filter by technology sector"; -/* Company filters page: title section - Filter by star-up */ -"filter_by_startup" = "Filter by start-ups"; - /* Filters page: title section - Filter by event type */ "filter_by_type" = "Filter by event type"; diff --git a/NOICommunity/it.lproj/InfoPlist.strings b/NOICommunity/it.lproj/InfoPlist.strings index ab142cf..0bb862f 100755 --- a/NOICommunity/it.lproj/InfoPlist.strings +++ b/NOICommunity/it.lproj/InfoPlist.strings @@ -2,7 +2,7 @@ * InfoPlist.strings (it) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-01-16T11:00:11+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/it.lproj/Localizable.strings b/NOICommunity/it.lproj/Localizable.strings index e060db3..e6b605f 100755 --- a/NOICommunity/it.lproj/Localizable.strings +++ b/NOICommunity/it.lproj/Localizable.strings @@ -2,7 +2,7 @@ * Localizable.strings (it) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-01-16T11:00:11+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 * Please do not edit this file by hand, use the export function from Google Sheet. */ @@ -93,18 +93,21 @@ /* Tab Today: title of top tab Events */ "events_top_tab" = "Eventi"; -/* Company filters page: title section - Filter by company */ -"filter_by_company" = "Filtra per aziende"; +/* Companies filters in Meet section: Button title - Filter by All */ +"filter_by_none" = "Tutte"; -/* Company filters page: title section - Filter by Research and Institution */ -"filter_by_research_institution" = "Filtra per istituzioni"; +/* Companies filters in Meet section: Button title - Filter by Companies */ +"filter_by_company" = "Aziende"; + +/* Companies filters in Meet section: Button title - Filter by Research and Institution */ +"filter_by_research_institution" = "Istituzioni"; + +/* Companies filter in Meet section: Button title - Filter by Startups */ +"filter_by_startup" = "Start-up"; /* Filters page: title section - Filter by technology sector */ "filter_by_sector" = "Filtra per settore tecnologico"; -/* Company filters page: title section - Filter by star-up */ -"filter_by_startup" = "Filtra per start-up"; - /* Filters page: title section - Filter by event type */ "filter_by_type" = "Filtra per tipo di evento"; From 1102047579276008d8f1e198c32bdcbf62b5000d Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:42:26 +0200 Subject: [PATCH 03/10] Updates UX/UI of people list in the Meet section --- .../MeetMainViewController.swift | 100 +++++++++--------- .../View Models/PeopleViewModel.swift | 36 ++++--- 2 files changed, 74 insertions(+), 62 deletions(-) diff --git a/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift b/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift index 1b078e8..8ca215d 100644 --- a/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift +++ b/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift @@ -98,6 +98,9 @@ extension MeetMainViewController: UISearchBarDelegate { private extension MeetMainViewController { + typealias DataSource = UICollectionViewDiffableDataSource + typealias Snapshot = NSDiffableDataSourceSnapshot + func configureBindings() { barView.searchBar.delegate = self @@ -157,8 +160,8 @@ private extension MeetMainViewController { let viewModel: PeopleViewModel - private var dataSource: UICollectionViewDiffableDataSource! = nil - + private var dataSource: DataSource! + private var subscriptions: Set = [] private var refreshControl: UIRefreshControl? { @@ -242,49 +245,13 @@ private extension MeetMainViewController.CollectionViewController { case main } - func columnCount( - for layoutEnviroment: NSCollectionLayoutEnvironment - ) -> Int { - switch ( - layoutEnviroment.container.effectiveContentSize.width - ) { - case 0..<600: - return 1 - default: - return 2 - } - } - func createLayout() -> UICollectionViewLayout { - let layout = UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in - let columns = self.columnCount(for: layoutEnvironment) - - let estimatedHeight = NSCollectionLayoutDimension.estimated(85) - let itemSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1.0), - heightDimension: estimatedHeight - ) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - - let groupSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1.0), - heightDimension: estimatedHeight - ) - let group = NSCollectionLayoutGroup.horizontal( - layoutSize: groupSize, - subitem: item, - count: columns - ) - group.interItemSpacing = .fixed(2) - - let section = NSCollectionLayoutSection(group: group) - section.interGroupSpacing = 2 - - return section - } - return layout + var config = UICollectionLayoutListConfiguration(appearance: .grouped) + config.headerMode = .supplementary + config.backgroundColor = .noiSecondaryBackgroundColor + return UICollectionViewCompositionalLayout.list(using: config) } - + func configureCollectionView() { collectionView.backgroundColor = .noiSecondaryBackgroundColor collectionView.collectionViewLayout = createLayout() @@ -313,6 +280,19 @@ private extension MeetMainViewController.CollectionViewController { cell.backgroundConfiguration = .noiListPlainCell(for: cell) } + let headerRegistration = UICollectionView + .SupplementaryRegistration( + elementKind: UICollectionView.elementKindSectionHeader + ) { cell, kind, indexPath in + let initial = self.dataSource + .snapshot() + .sectionIdentifiers[indexPath.section] + + var config = UIListContentConfiguration.noiGroupedHeader() + config.text = initial.value + cell.contentConfiguration = config + } + dataSource = .init( collectionView: collectionView ) { collectionView, indexPath, item in @@ -322,13 +302,33 @@ private extension MeetMainViewController.CollectionViewController { item: item ) } + + dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in + switch kind { + case UICollectionView.elementKindSectionHeader: + return collectionView.dequeueConfiguredReusableSupplementary( + using: headerRegistration, + for: indexPath + ) + default: + return nil + } + } + + updateUI(viewModel.results, animated: false) } - func updateUI(peopleIds: [PersonId]?, animated: Bool) { - var snapshot = NSDiffableDataSourceSnapshot() - if let peopleIds = peopleIds { - snapshot.appendSections([.main]) - snapshot.appendItems(peopleIds, toSection: .main) + func updateUI( + _ result: ([Initial], [Initial: [PersonId]])?, + animated: Bool + ) { + var snapshot = MeetMainViewController.Snapshot() + if let result { + let (sections, sectionToItems) = result + snapshot.appendSections(sections) + for section in sections { + snapshot.appendItems(sectionToItems[section]!, toSection: section) + } } dataSource.apply(snapshot, animatingDifferences: animated) } @@ -351,7 +351,7 @@ private extension MeetMainViewController.CollectionViewController { .receive(on: DispatchQueue.main) .sink { [weak self] in let isOnScreen = self?.viewIfLoaded?.window != nil - self?.updateUI(peopleIds: $0, animated: isOnScreen) + self?.updateUI($0, animated: isOnScreen) } .store(in: &subscriptions) @@ -366,7 +366,7 @@ private extension MeetMainViewController.CollectionViewController { .store(in: &subscriptions) viewModel.$results - .map(\.?.isEmpty) + .map(\.?.0.isEmpty) .receive(on: DispatchQueue.main) .sink { [weak self] isEmpty in guard let self = self diff --git a/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift b/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift index 0c5b9ed..e7c59a1 100644 --- a/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift @@ -29,11 +29,10 @@ final class PeopleViewModel { @Published private(set) var peopleIds: [PersonId]! - @Published private(set) var results: [PersonId]! { - didSet { - numberOfResults = results.count - } - } + @Published private(set) var results: ( + [Initial], + [Initial: [PersonId]] + )! @Published private(set) var activeSearchTerm: String? @@ -151,17 +150,19 @@ final class PeopleViewModel { activeSearchTerm = searchTerm activeCompanyIdsFilter = filterCompanyIds - let results = peopleIds + let filteredSortedPeople = peopleIds .lazy + // Maps person id to person .map { self.person(withId: $0) } + // Apply filtering based on search term .filter { person in - // Search term predicate - guard let searchTerm = searchTerm, + guard let searchTerm, !searchTerm.isEmpty else { return true } - return person.fullname - .localizedStandardContains(searchTerm) + + return person.fullname.localizedStandardContains(searchTerm) } + // Apply filtering based on company filters .filter { person in // Belong to company predicate (OR) guard let filterCompanyIds = filterCompanyIds @@ -172,8 +173,19 @@ final class PeopleViewModel { return filterCompanyIds.contains(companyId) } - .map(\.id) - self.results = Array(results) + // Sort alphabetically by name + .sorted { + $0.fullname.localizedCaseInsensitiveCompare($1.fullname) == .orderedAscending + } + + let peopleIdsByInitial = Dictionary( + grouping: filteredSortedPeople, + by: { Initial(from: $0.fullname) } + ) + .mapValues { $0.map(\.id) } + + let initials = Array(Set(peopleIdsByInitial.keys)).sorted() + self.results = (initials, peopleIdsByInitial) } func makeCompanyViewModel() -> CompanyViewModel { From 4e8bab67eaabc8a9dc30bbb7fa228b72479233c9 Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:52:31 +0200 Subject: [PATCH 04/10] Moves Initial to Core module and changed ordering --- .../CompaniesFiltersViewController.swift | 1 + .../MeetMainViewController.swift | 1 + .../View Models/CompanyViewModel.swift | 46 +--------------- .../View Models/PeopleViewModel.swift | 1 + .../Sources/Core/Utils/Initial.swift | 52 +++++++++++++++++++ 5 files changed, 56 insertions(+), 45 deletions(-) create mode 100644 NOICommunityLib/Sources/Core/Utils/Initial.swift diff --git a/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift b/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift index e0768a9..39a3020 100644 --- a/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift +++ b/NOICommunity/MeetFeature/View Controllers/CompaniesFiltersViewController.swift @@ -11,6 +11,7 @@ import UIKit import Combine +import Core import PeopleClient // MARK: CompaniesFiltersViewController diff --git a/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift b/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift index 8ca215d..ec6621b 100644 --- a/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift +++ b/NOICommunity/MeetFeature/View Controllers/MeetMainViewController.swift @@ -11,6 +11,7 @@ import UIKit import Combine +import Core import PeopleClient // MARK: - MeetMainViewController diff --git a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift index ab742a9..24eda2c 100644 --- a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift @@ -11,53 +11,9 @@ import Foundation import Combine +import Core import PeopleClient -// MARK: - Initial - -struct Initial: Hashable { - - let value: String - - static let other = Initial("#") - - private init(_ value: String) { - self.value = value - } - - init(from text: String) { - guard let firstChar = text - // Trim spaces and new lines - .trimmingCharacters(in: .whitespacesAndNewlines) - // Remove diacritics - .applyingTransform(.stripDiacritics, reverse: false)? - .first - else { self = .other; return } - - let value = String(firstChar) - - let isLetter = value.rangeOfCharacter(from: .letters.inverted) == nil - guard isLetter - else { self = .other; return } - - self.init(value) - } - -} - -extension Initial: Comparable { - static func <(lhs: Initial, rhs: Initial) -> Bool { - switch (lhs.value, rhs.value) { - case ("#", _): - return false - case (_, "#"): - return true - case (let lhsValue, let rhsValue): - return lhsValue.localizedCaseInsensitiveCompare(rhsValue) == .orderedAscending - } - } -} - // MARK - CompanyFilter enum CompanyFilter: CaseIterable { diff --git a/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift b/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift index e7c59a1..1bbbdd6 100644 --- a/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift @@ -11,6 +11,7 @@ import Foundation import Combine +import Core import PeopleClient import AuthClient diff --git a/NOICommunityLib/Sources/Core/Utils/Initial.swift b/NOICommunityLib/Sources/Core/Utils/Initial.swift new file mode 100644 index 0000000..74822b2 --- /dev/null +++ b/NOICommunityLib/Sources/Core/Utils/Initial.swift @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +// +// Initial.swift +// Core +// +// Created by Matteo Matassoni on 21/08/24. +// + +import Foundation + +// MARK: - Initial + +public struct Initial: Hashable { + + public let value: String + + public static let other = Initial("#") + + private init(_ value: String) { + self.value = value + } + + public init(from text: String) { + guard let firstChar = text + // Trim spaces and new lines + .trimmingCharacters(in: .whitespacesAndNewlines) + // Remove diacritics + .applyingTransform(.stripDiacritics, reverse: false)? + .first + else { self = .other; return } + + let value = String(firstChar) + + let isLetter = value.rangeOfCharacter(from: .letters.inverted) == nil + guard isLetter + else { self = .other; return } + + self.init(value) + } + +} + +extension Initial: Comparable { + + public static func <(lhs: Initial, rhs: Initial) -> Bool { + lhs.value.localizedCaseInsensitiveCompare(rhs.value) == .orderedAscending + } + +} From 512fd7213fd76f83ec85ce4c291a4bf3f047376f Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:26:16 +0200 Subject: [PATCH 05/10] WIP --- .../View Models/CompanyViewModel.swift | 62 +++++++++++++++---- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift index 24eda2c..3abfc3e 100644 --- a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift @@ -19,20 +19,29 @@ import PeopleClient enum CompanyFilter: CaseIterable { case all + case noiSpa + case researchInstitutes + case universities + case institutions case companies - case startups - case researchInstitutions + case startup var title: String { switch self { - case .all: - .localized("filter_by_none") - case .researchInstitutions: - .localized("filter_by_research_institution") - case .startups: - .localized("filter_by_startup") + case .all: + .localized("filter_by_all") + case .noiSpa: + .localized("filter_by_noi_spa") + case .researchInstitutes: + .localized("filter_by_research_institutes") + case .universities: + .localized("filter_by_universities") + case .institutions: + .localized("filter_by_institutions") case .companies: - .localized("filter_by_company") + .localized("filter_by_companies") + case .startup: + .localized("filter_by_startup") } } @@ -40,12 +49,18 @@ enum CompanyFilter: CaseIterable { switch self { case .all: nil - case .researchInstitutions: + case .noiSpa: + .noiCommunity + case .researchInstitutes: + nil + case .universities: + nil + case .institutions: .researchInstitution - case .startups: - .startup case .companies: .company + case .startup: + .startup } } @@ -99,6 +114,29 @@ final class CompanyViewModel { activeSearchTerm = searchTerm activeFilter = filter + let foo = companyIds + // Maps company id to company + .compactMap { self.company(withId: $0) } + // Apply filtering based on tag + .filter { company in + guard let tag = filter.tag + else { return true } + + return company.tags.contains(tag) + } + // Apply filtering based on search term + .filter { company in + guard let searchTerm, + !searchTerm.isEmpty + else { return true } + + return company.name.localizedStandardContains(searchTerm) + } + // Sort alphabetically by name + .sorted { + $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending + } + let filteredSortedCompanies = companyIds .lazy // Maps company id to company From b4b861265d321c19c17f83470f6d4c3e64a0c9d3 Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:44:17 +0100 Subject: [PATCH 06/10] fixes initial bug --- NOICommunityLib/Sources/Core/Utils/Initial.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOICommunityLib/Sources/Core/Utils/Initial.swift b/NOICommunityLib/Sources/Core/Utils/Initial.swift index 74822b2..5cf12ad 100644 --- a/NOICommunityLib/Sources/Core/Utils/Initial.swift +++ b/NOICommunityLib/Sources/Core/Utils/Initial.swift @@ -38,7 +38,7 @@ public struct Initial: Hashable { guard isLetter else { self = .other; return } - self.init(value) + self.init(value.uppercased()) } } From cb9a03110966a3a5d4c0268ae6bfaf916e16087d Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:44:43 +0100 Subject: [PATCH 07/10] final implementation of the new meet filters --- .../View Models/CompanyViewModel.swift | 38 ------------------- NOICommunity/de.lproj/InfoPlist.strings | 2 +- NOICommunity/de.lproj/Localizable.strings | 26 ++++++------- NOICommunity/en.lproj/InfoPlist.strings | 2 +- NOICommunity/en.lproj/Localizable.strings | 26 ++++++------- NOICommunity/it.lproj/InfoPlist.strings | 2 +- NOICommunity/it.lproj/Localizable.strings | 26 ++++++------- 7 files changed, 42 insertions(+), 80 deletions(-) diff --git a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift index 3abfc3e..affada2 100644 --- a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift @@ -19,9 +19,6 @@ import PeopleClient enum CompanyFilter: CaseIterable { case all - case noiSpa - case researchInstitutes - case universities case institutions case companies case startup @@ -30,12 +27,6 @@ enum CompanyFilter: CaseIterable { switch self { case .all: .localized("filter_by_all") - case .noiSpa: - .localized("filter_by_noi_spa") - case .researchInstitutes: - .localized("filter_by_research_institutes") - case .universities: - .localized("filter_by_universities") case .institutions: .localized("filter_by_institutions") case .companies: @@ -49,12 +40,6 @@ enum CompanyFilter: CaseIterable { switch self { case .all: nil - case .noiSpa: - .noiCommunity - case .researchInstitutes: - nil - case .universities: - nil case .institutions: .researchInstitution case .companies: @@ -114,29 +99,6 @@ final class CompanyViewModel { activeSearchTerm = searchTerm activeFilter = filter - let foo = companyIds - // Maps company id to company - .compactMap { self.company(withId: $0) } - // Apply filtering based on tag - .filter { company in - guard let tag = filter.tag - else { return true } - - return company.tags.contains(tag) - } - // Apply filtering based on search term - .filter { company in - guard let searchTerm, - !searchTerm.isEmpty - else { return true } - - return company.name.localizedStandardContains(searchTerm) - } - // Sort alphabetically by name - .sorted { - $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending - } - let filteredSortedCompanies = companyIds .lazy // Maps company id to company diff --git a/NOICommunity/de.lproj/InfoPlist.strings b/NOICommunity/de.lproj/InfoPlist.strings index 06598f4..27a97dd 100755 --- a/NOICommunity/de.lproj/InfoPlist.strings +++ b/NOICommunity/de.lproj/InfoPlist.strings @@ -2,7 +2,7 @@ * InfoPlist.strings (de) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/de.lproj/Localizable.strings b/NOICommunity/de.lproj/Localizable.strings index 191b88e..1a32cdb 100755 --- a/NOICommunity/de.lproj/Localizable.strings +++ b/NOICommunity/de.lproj/Localizable.strings @@ -2,7 +2,7 @@ * Localizable.strings (de) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ @@ -93,18 +93,6 @@ /* Tab Today: title of top tab Events */ "events_top_tab" = "Events"; -/* Companies filters in Meet section: Button title - Filter by All */ -"filter_by_none" = "Alles"; - -/* Companies filters in Meet section: Button title - Filter by Companies */ -"filter_by_company" = "Unternehmen"; - -/* Companies filters in Meet section: Button title - Filter by Research and Institution */ -"filter_by_research_institution" = "Institutionen"; - -/* Companies filter in Meet section: Button title - Filter by Startups */ -"filter_by_startup" = "Start-ups"; - /* Filters page: title section - Filter by technology sector */ "filter_by_sector" = "Nach Technologiefeld filtern"; @@ -334,6 +322,18 @@ Tab Orientate: button label */ /* Title of jobs page */ "noi_techpark_jobs_page_title" = "Jobs"; +/* Companies filters in Meet section: Button title - Filter by All */ +"filter_by_all" = "Alle"; + +/* Companies filters in Meet section: Button title - Filter by Institution */ +"filter_by_institutions" = "Institutionen"; + +/* Companies filters in Meet section: Button title - Filter by Companies */ +"filter_by_companies" = "Unternehmen"; + +/* Companies filter in Meet section: Button title - Filter by Startups */ +"filter_by_startup" = "Start-ups"; + /* */ "url_home" = "https://noi.bz.it/de"; diff --git a/NOICommunity/en.lproj/InfoPlist.strings b/NOICommunity/en.lproj/InfoPlist.strings index 422b63a..8f29ccf 100755 --- a/NOICommunity/en.lproj/InfoPlist.strings +++ b/NOICommunity/en.lproj/InfoPlist.strings @@ -2,7 +2,7 @@ * InfoPlist.strings (en) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/en.lproj/Localizable.strings b/NOICommunity/en.lproj/Localizable.strings index 4a881d9..d85c1fd 100755 --- a/NOICommunity/en.lproj/Localizable.strings +++ b/NOICommunity/en.lproj/Localizable.strings @@ -2,7 +2,7 @@ * Localizable.strings (en) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ @@ -93,18 +93,6 @@ /* Tab Today: title of top tab Events */ "events_top_tab" = "Events"; -/* Companies filters in Meet section: Button title - Filter by All */ -"filter_by_none" = "All"; - -/* Companies filters in Meet section: Button title - Filter by Companies */ -"filter_by_company" = "Companies"; - -/* Companies filters in Meet section: Button title - Filter by Research and Institution */ -"filter_by_research_institution" = "Institutions"; - -/* Companies filter in Meet section: Button title - Filter by Startups */ -"filter_by_startup" = "Start-ups"; - /* Filters page: title section - Filter by technology sector */ "filter_by_sector" = "Filter by technology sector"; @@ -334,6 +322,18 @@ Tab Orientate: button label */ /* Title of jobs page */ "noi_techpark_jobs_page_title" = "Jobs"; +/* Companies filters in Meet section: Button title - Filter by All */ +"filter_by_all" = "All"; + +/* Companies filters in Meet section: Button title - Filter by Institution */ +"filter_by_institutions" = "Institutions"; + +/* Companies filters in Meet section: Button title - Filter by Companies */ +"filter_by_companies" = "Companies"; + +/* Companies filter in Meet section: Button title - Filter by Startups */ +"filter_by_startup" = "Start-ups"; + /* */ "url_home" = "https://noi.bz.it/en"; diff --git a/NOICommunity/it.lproj/InfoPlist.strings b/NOICommunity/it.lproj/InfoPlist.strings index 0bb862f..b8d4571 100755 --- a/NOICommunity/it.lproj/InfoPlist.strings +++ b/NOICommunity/it.lproj/InfoPlist.strings @@ -2,7 +2,7 @@ * InfoPlist.strings (it) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/it.lproj/Localizable.strings b/NOICommunity/it.lproj/Localizable.strings index e6b605f..d25d8ff 100755 --- a/NOICommunity/it.lproj/Localizable.strings +++ b/NOICommunity/it.lproj/Localizable.strings @@ -2,7 +2,7 @@ * Localizable.strings (it) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-08-21T14:49:30+0200 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ @@ -93,18 +93,6 @@ /* Tab Today: title of top tab Events */ "events_top_tab" = "Eventi"; -/* Companies filters in Meet section: Button title - Filter by All */ -"filter_by_none" = "Tutte"; - -/* Companies filters in Meet section: Button title - Filter by Companies */ -"filter_by_company" = "Aziende"; - -/* Companies filters in Meet section: Button title - Filter by Research and Institution */ -"filter_by_research_institution" = "Istituzioni"; - -/* Companies filter in Meet section: Button title - Filter by Startups */ -"filter_by_startup" = "Start-up"; - /* Filters page: title section - Filter by technology sector */ "filter_by_sector" = "Filtra per settore tecnologico"; @@ -334,6 +322,18 @@ Tab Orientate: button label */ /* Title of jobs page */ "noi_techpark_jobs_page_title" = "Jobs"; +/* Companies filters in Meet section: Button title - Filter by All */ +"filter_by_all" = "Tutti"; + +/* Companies filters in Meet section: Button title - Filter by Institution */ +"filter_by_institutions" = "Istituzioni"; + +/* Companies filters in Meet section: Button title - Filter by Companies */ +"filter_by_companies" = "Aziende"; + +/* Companies filter in Meet section: Button title - Filter by Startups */ +"filter_by_startup" = "Start-up"; + /* */ "url_home" = "https://noi.bz.it/it"; From 30182ad95155807c7a585050ed6150cba3537ab1 Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:52:47 +0100 Subject: [PATCH 08/10] fixes companies filter order --- NOICommunity/MeetFeature/View Models/CompanyViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift index affada2..c6d3c27 100644 --- a/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/CompanyViewModel.swift @@ -19,9 +19,9 @@ import PeopleClient enum CompanyFilter: CaseIterable { case all - case institutions case companies case startup + case institutions var title: String { switch self { From 4edbb83e69956c08af9e71d7a78d55574214f40a Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:00:50 +0100 Subject: [PATCH 09/10] reimported localizable strings --- NOICommunity/de.lproj/InfoPlist.strings | 6 +++++- NOICommunity/de.lproj/Localizable.strings | 6 +++++- NOICommunity/en.lproj/InfoPlist.strings | 6 +++++- NOICommunity/en.lproj/Localizable.strings | 6 +++++- NOICommunity/it.lproj/InfoPlist.strings | 6 +++++- NOICommunity/it.lproj/Localizable.strings | 6 +++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/NOICommunity/de.lproj/InfoPlist.strings b/NOICommunity/de.lproj/InfoPlist.strings index 27a97dd..9e8b4f0 100755 --- a/NOICommunity/de.lproj/InfoPlist.strings +++ b/NOICommunity/de.lproj/InfoPlist.strings @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + /* * InfoPlist.strings (de) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T11:58:16+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/de.lproj/Localizable.strings b/NOICommunity/de.lproj/Localizable.strings index 1a32cdb..f3d0e9a 100755 --- a/NOICommunity/de.lproj/Localizable.strings +++ b/NOICommunity/de.lproj/Localizable.strings @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + /* * Localizable.strings (de) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T11:58:16+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/en.lproj/InfoPlist.strings b/NOICommunity/en.lproj/InfoPlist.strings index 8f29ccf..42888c5 100755 --- a/NOICommunity/en.lproj/InfoPlist.strings +++ b/NOICommunity/en.lproj/InfoPlist.strings @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + /* * InfoPlist.strings (en) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T11:58:16+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/en.lproj/Localizable.strings b/NOICommunity/en.lproj/Localizable.strings index d85c1fd..6096903 100755 --- a/NOICommunity/en.lproj/Localizable.strings +++ b/NOICommunity/en.lproj/Localizable.strings @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + /* * Localizable.strings (en) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T11:58:16+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/it.lproj/InfoPlist.strings b/NOICommunity/it.lproj/InfoPlist.strings index b8d4571..7e0986d 100755 --- a/NOICommunity/it.lproj/InfoPlist.strings +++ b/NOICommunity/it.lproj/InfoPlist.strings @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + /* * InfoPlist.strings (it) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T11:58:16+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ diff --git a/NOICommunity/it.lproj/Localizable.strings b/NOICommunity/it.lproj/Localizable.strings index d25d8ff..0159ab7 100755 --- a/NOICommunity/it.lproj/Localizable.strings +++ b/NOICommunity/it.lproj/Localizable.strings @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + /* * Localizable.strings (it) * Copyright © 2021 Dimension S.r.l. All rights reserved. * - * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T10:34:35+0100 + * Generated from "https://docs.google.com/spreadsheets/d/1Yiol3UqS-0I9q4R5HLifVMdGbTSe3ZwuYBAMPyZJthc/edit#gid=0" on 2024-11-07T11:58:16+0100 * Please do not edit this file by hand, use the export function from Google Sheet. */ From e0a316e29edc776fd10b21a738333a4c9e8cee0f Mon Sep 17 00:00:00 2001 From: Matteo Matassoni <4108197+matax87@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:24:51 +0100 Subject: [PATCH 10/10] fixes number of result on meet tab filters --- NOICommunity/MeetFeature/View Models/PeopleViewModel.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift b/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift index 1bbbdd6..e55a749 100644 --- a/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift +++ b/NOICommunity/MeetFeature/View Models/PeopleViewModel.swift @@ -34,7 +34,7 @@ final class PeopleViewModel { [Initial], [Initial: [PersonId]] )! - + @Published private(set) var activeSearchTerm: String? @Published private(set) var activeCompanyIdsFilter: Set? { @@ -186,6 +186,7 @@ final class PeopleViewModel { .mapValues { $0.map(\.id) } let initials = Array(Set(peopleIdsByInitial.keys)).sorted() + self.numberOfResults = filteredSortedPeople.count self.results = (initials, peopleIdsByInitial) }