Improve link list order logic

This commit is contained in:
2025-08-16 21:25:52 +10:00
parent 9a091427a9
commit f5e7598ae2
2 changed files with 49 additions and 99 deletions
+9 -5
View File
@@ -16,6 +16,9 @@ class LinkViewModel: ObservableObject {
sortLinks()
}
}
@Published var sortAscending: Bool = true {
didSet { sortLinks() }
}
@Published var selectedTag: Tag? {
didSet {
filterLinks()
@@ -251,17 +254,18 @@ class LinkViewModel: ObservableObject {
}
private func sortLinks() {
let ascending = sortAscending
switch selectedSortOption {
case .alias:
filteredLinks.sort { $0.alias < $1.alias }
filteredLinks.sort { ascending ? ($0.alias < $1.alias) : ($0.alias > $1.alias) }
case .type:
filteredLinks.sort { $0.linkType < $1.linkType }
filteredLinks.sort { ascending ? ($0.linkType < $1.linkType) : ($0.linkType > $1.linkType) }
case .clicks:
filteredLinks.sort { $0.clickCount > $1.clickCount }
filteredLinks.sort { ascending ? ($0.clickCount < $1.clickCount) : ($0.clickCount > $1.clickCount) }
case .dateCreated:
filteredLinks.sort { $0.createdAt > $1.createdAt }
filteredLinks.sort { ascending ? ($0.createdAt < $1.createdAt) : ($0.createdAt > $1.createdAt) }
case .dateUpdated:
filteredLinks.sort { $0.updatedAt > $1.updatedAt }
filteredLinks.sort { ascending ? ($0.updatedAt < $1.updatedAt) : ($0.updatedAt > $1.updatedAt) }
}
}
+40 -94
View File
@@ -1,4 +1,5 @@
import SwiftUI
import UIKit
struct LinkListView: View {
@EnvironmentObject var linkViewModel: LinkViewModel
@@ -14,42 +15,43 @@ struct LinkListView: View {
VStack {
// Search bar
SearchBar(text: $linkViewModel.searchText)
.environmentObject(linkViewModel)
.padding(.horizontal)
// Filter and sort bar
HStack {
Button(action: {
showingFilterSheet = true
}) {
Button(action: { showingFilterSheet = true }) {
HStack {
Image(systemName: "line.horizontal.3.decrease.circle")
Text("filter")
if linkViewModel.selectedTag != nil {
Text("")
.foregroundColor(.blue)
}
if linkViewModel.selectedTag != nil { Text("").foregroundColor(.blue) }
}
}
Spacer()
Menu {
ForEach(LinkViewModel.SortOption.allCases, id: \.self) { option in
Button(action: {
linkViewModel.selectedSortOption = option
}) {
HStack {
Text(option.displayName)
if linkViewModel.selectedSortOption == option {
Image(systemName: "checkmark")
// Sorting controls
HStack(spacing: 8) {
Button(action: { linkViewModel.sortAscending = true }) {
Image(systemName: "arrow.up")
.foregroundColor(linkViewModel.sortAscending ? .blue : .gray)
}
Button(action: { linkViewModel.sortAscending = false }) {
Image(systemName: "arrow.down")
.foregroundColor(!linkViewModel.sortAscending ? .blue : .gray)
}
Menu {
ForEach(LinkViewModel.SortOption.allCases, id: \.self) { option in
Button(action: { linkViewModel.selectedSortOption = option }) {
HStack {
Text(option.displayName)
if linkViewModel.selectedSortOption == option { Image(systemName: "checkmark") }
}
}
}
}
} label: {
HStack {
Image(systemName: "arrow.up.arrow.down")
} label: {
Text(linkViewModel.selectedSortOption.displayName)
.foregroundColor(.blue)
}
}
}
@@ -61,7 +63,6 @@ struct LinkListView: View {
HStack(spacing: 6) {
let filtered = linkViewModel.filteredLinks.count
let total = linkViewModel.links.count
// Use monospace digits for subtle alignment
Text("\(filtered)")
.font(.caption)
.fontWeight(.semibold)
@@ -70,35 +71,25 @@ struct LinkListView: View {
.background(Color.secondary.opacity(0.15))
.foregroundColor(.secondary)
.cornerRadius(4)
.accessibilityLabel("Filtered links count")
if filtered != total && total > 0 {
Text("of \(total)")
.font(.caption2)
.foregroundColor(.secondary)
.transition(.opacity)
}
Spacer()
}
.padding(.horizontal)
.padding(.bottom, 2)
.transition(.opacity)
}
// Links list
if linkViewModel.isLoading {
ProgressView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
ProgressView().frame(maxWidth: .infinity, maxHeight: .infinity)
} else if linkViewModel.filteredLinks.isEmpty {
VStack {
Image(systemName: "link.badge.plus")
.font(.system(size: 60))
.foregroundColor(.secondary)
Text("no_links_found")
.font(.title2)
.foregroundColor(.secondary)
Text("tap_plus_to_add_link")
.font(.caption)
.foregroundColor(.secondary)
Image(systemName: "link.badge.plus").font(.system(size: 60)).foregroundColor(.secondary)
Text("no_links_found").font(.title2).foregroundColor(.secondary)
Text("tap_plus_to_add_link").font(.caption).foregroundColor(.secondary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
@@ -108,78 +99,33 @@ struct LinkListView: View {
markdownLink = customLink
showingMarkdownContent = true
}
.onTapGesture {
selectedLink = link
}
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button("delete", role: .destructive) {
linkViewModel.deleteLink(link)
}
Button("edit") {
selectedLink = link
showingAddLink = true
}
.tint(.blue)
}
.onTapGesture { selectedLink = link }
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button("delete", role: .destructive) { linkViewModel.deleteLink(link) }
Button("edit") { selectedLink = link; showingAddLink = true }.tint(.blue)
}
}
}
.refreshable {
linkViewModel.fetchLinks()
}
.refreshable { linkViewModel.fetchLinks() }
}
}
.navigationTitle("")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
HStack {
Image(systemName: "dog.fill")
.foregroundColor(.black)
Text("Heygo")
.font(.headline)
.foregroundColor(.primary)
}
HStack { Image(systemName: "dog.fill").foregroundColor(.black); Text("Heygo").font(.headline).foregroundColor(.primary) }
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
selectedLink = nil
showingAddLink = true
}) {
Image(systemName: "plus")
}
}
}
.sheet(isPresented: $showingAddLink) {
LinkFormView(link: selectedLink)
.environmentObject(linkViewModel)
}
.sheet(isPresented: $showingFilterSheet) {
FilterView()
.environmentObject(linkViewModel)
}
.sheet(item: $selectedLink) { link in
LinkDetailView(link: link)
.environmentObject(linkViewModel)
}
.sheet(isPresented: $showingMarkdownContent) {
if let markdownLink = markdownLink {
MarkdownContentView(link: markdownLink)
Button(action: { selectedLink = nil; showingAddLink = true }) { Image(systemName: "plus") }
}
}
.sheet(isPresented: $showingAddLink) { LinkFormView(link: selectedLink).environmentObject(linkViewModel) }
.sheet(isPresented: $showingFilterSheet) { FilterView().environmentObject(linkViewModel) }
.sheet(item: $selectedLink) { link in LinkDetailView(link: link).environmentObject(linkViewModel) }
.sheet(isPresented: $showingMarkdownContent) { if let markdownLink = markdownLink { MarkdownContentView(link: markdownLink) } }
}
.onAppear {
if linkViewModel.links.isEmpty {
linkViewModel.fetchLinks()
}
}
.alert("Error", isPresented: .constant(linkViewModel.errorMessage != nil)) {
Button("OK") {
linkViewModel.errorMessage = nil
}
} message: {
Text(linkViewModel.errorMessage ?? "")
}
.onAppear { if linkViewModel.links.isEmpty { linkViewModel.fetchLinks() } }
.alert("Error", isPresented: .constant(linkViewModel.errorMessage != nil)) { Button("OK") { linkViewModel.errorMessage = nil } } message: { Text(linkViewModel.errorMessage ?? "") }
}
}