AlphabetIndex.swift
68 lignes · 2960 octets
import Foundation enum AlphabetIndex { /// Kotlin returned a `LinkedHashMap<Char, List<CrmContactEntity>>`; /// Swift has no ordered dictionary, so sections are an ordered array of pairs. typealias Section = (letter: Character, contacts: [CrmContactEntity]) static func sortKey(_ c: CrmContactEntity, sort: ContactSort) -> String { switch sort { case .lastName: return c.lastName ?? c.fullName ?? "" case .firstName: return c.firstName ?? c.fullName ?? "" case .company: return c.company ?? "" case .createdAt: let s = String(c.createdAt) return s.count >= 20 ? s : String(repeating: "0", count: 20 - s.count) + s } } static func sectionLetter(_ key: String) -> Character { let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines) guard let first = trimmed.first else { return "#" } let up = String(first).uppercased() // Compare on the scalar value like Kotlin's `c in 'A'..'Z'` (so 'É' → '#'). guard up.unicodeScalars.count == 1, let scalar = up.unicodeScalars.first, (65...90).contains(scalar.value) else { return "#" } return Character(up) } /// Alphabetical sorts: ordered A–Z then `#`, contacts sorted within each section. /// `ContactSort.createdAt`: single flat section (chrono desc), no A–Z rail sections. static func group(contacts: [CrmContactEntity], sort: ContactSort) -> [Section] { if sort == .createdAt { // Stable descending sort by createdAt. let sorted = contacts.enumerated().sorted { l, r in if l.element.createdAt != r.element.createdAt { return l.element.createdAt > r.element.createdAt } return l.offset < r.offset }.map { $0.element } return [(letter: "#", contacts: sorted)] } // Stable case-insensitive sort (Kotlin: compareBy(String.CASE_INSENSITIVE_ORDER)). let sorted = contacts.enumerated().sorted { l, r in let cmp = sortKey(l.element, sort: sort).caseInsensitiveCompare(sortKey(r.element, sort: sort)) if cmp != .orderedSame { return cmp == .orderedAscending } return l.offset < r.offset }.map { $0.element } var order: [Character] = [] var buckets: [Character: [CrmContactEntity]] = [:] for c in sorted { let letter = sectionLetter(sortKey(c, sort: sort)) if buckets[letter] == nil { order.append(letter) } buckets[letter, default: []].append(c) } var out: [Section] = [] for k in order where k != "#" { out.append((letter: k, contacts: buckets[k] ?? [])) } if let hash = buckets["#"] { out.append((letter: "#", contacts: hash)) } return out } }
GitRust