Use the same sorting of labels on iOS as Web

This commit is contained in:
Jackson Harper
2023-05-29 15:02:51 +08:00
parent 27eb891acc
commit 50bbdfa441
3 changed files with 108 additions and 15 deletions

View File

@ -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] {

View File

@ -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<CGFloat>) -> some View {
GeometryReader { geometry -> Color in
let rect = geometry.frame(in: .local)
DispatchQueue.main.async {
binding.wrappedValue = rect.size.height
}
return .clear
}
}
}

View File

@ -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()