mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
Improve link list order logic
This commit is contained in:
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ?? "") }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user