From 50bbdfa44111eff591c378b4504324dd58c21d6f Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Mon, 29 May 2023 15:02:51 +0800 Subject: [PATCH] Use the same sorting of labels on iOS as Web --- .../Sources/Models/DataModels/FeedItem.swift | 33 +++++++- .../Views/FeedItem/LabelsFlowLayout.swift | 75 +++++++++++++++++++ .../Views/FeedItem/LibraryItemCard.swift | 15 +--- 3 files changed, 108 insertions(+), 15 deletions(-) create mode 100644 apple/OmnivoreKit/Sources/Views/FeedItem/LabelsFlowLayout.swift diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift index ac57b4290..92d4eda80 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift @@ -127,9 +127,38 @@ public extension LinkedItem { } var sortedLabels: [LinkedItemLabel] { - labels.asArray(of: LinkedItemLabel.self).sorted { - ($0.name ?? "").lowercased() < ($1.name ?? "").lowercased() + sortedLabels(labels: labels.asArray(of: LinkedItemLabel.self)) + } + + func sortedLabels(labels: [LinkedItemLabel]?) -> [LinkedItemLabel] { + guard let labels = labels else { + return [] } + + var colors = [String: [LinkedItemLabel]]() + for label in labels { + if let color = label.color { + var list = colors[color] ?? [] + list.append(label) + colors[color] = list.sorted(by: { ($0.name ?? "").localizedCompare($1.name ?? "") == .orderedAscending }) + } + } + + let sortedColors = Array(colors.keys).sorted(by: { leftLabel, rightLabel -> Bool in + let aname = colors[leftLabel]?.first?.name ?? leftLabel + let bname = colors[rightLabel]?.first?.name ?? rightLabel + return aname.localizedCompare(bname) == .orderedAscending + }) + + var result = [LinkedItemLabel]() + for key in sortedColors { + if let items = colors[key] { + let sorted = items.sorted(by: { ($0.name ?? "").localizedCompare($1.name ?? "") == .orderedAscending }) + result.append(contentsOf: sorted) + } + } + + return result } var sortedHighlights: [Highlight] { diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/LabelsFlowLayout.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/LabelsFlowLayout.swift new file mode 100644 index 000000000..60eb7cadb --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/LabelsFlowLayout.swift @@ -0,0 +1,75 @@ +// +// based on: LabelsMasonaryView.swift we should try to combine the two + +import Foundation +import Models +import SwiftUI + +struct LabelsFlowLayout: View { + @State private var totalHeight = CGFloat.zero + private var labelItems: [LinkedItemLabel] + + init( + labels: [LinkedItemLabel] + ) { + self.labelItems = labels + } + + var body: some View { + VStack { + GeometryReader { geometry in + self.generateContent(in: geometry) + } + }.padding(5) + .frame(height: totalHeight) + } + + private func generateContent(in geom: GeometryProxy) -> some View { + var width = CGFloat.zero + var height = CGFloat.zero + + return ZStack(alignment: .topLeading) { + ForEach(self.labelItems, id: \.self) { label in + self.item(for: label) + .padding(.horizontal, 1) + .padding(.vertical, 1) + .alignmentGuide(.leading, computeValue: { dim in + if abs(width - dim.width) > geom.size.width { + width = 0 + height -= dim.height + } + let result = width + if label == self.labelItems.last! { + width = 0 // last item + } else { + width -= dim.width + } + return result + }) + .alignmentGuide(.top, computeValue: { _ in + let result = height + if label == self.labelItems.last! { + height = 0 // last item + } + return result + }) + } + } + .background(viewHeightReader($totalHeight)) + } + + private func item(for item: LinkedItemLabel) -> some View { + let chip = TextChip(feedItemLabel: item, padded: false, onTap: nil) + return chip + } + + private func viewHeightReader(_ binding: Binding) -> some View { + GeometryReader { geometry -> Color in + let rect = geometry.frame(in: .local) + DispatchQueue.main.async { + binding.wrappedValue = rect.size.height + } + return .clear + } + } +} diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift index f42d86e05..965404147 100644 --- a/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift @@ -213,19 +213,8 @@ public struct LibraryItemCard: View { } var labels: some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack { - ForEach(item.sortedLabels, id: \.self) { - TextChip(feedItemLabel: $0) - } - Spacer() - } - }.introspectScrollView { scrollView in - #if os(iOS) - scrollView.bounces = false - #endif - } - .padding(.top, 0) + LabelsFlowLayout(labels: item.sortedLabels) + .padding(.top, 0) #if os(macOS) .onTapGesture { tapHandler()