Implement four-way sort cycling for browser listview
- Added four sort modes: Date ↓, Date ↑, Name ↑, Name ↓ - Sorting happens only when sort mode changes, not every frame - Sorted entries are cached in SortedEntries field - Search query changes trigger re-filtering and re-sorting - Scroll offset resets on sort change
This commit is contained in:
parent
8f185341b3
commit
831f0dac81
|
|
@ -1,7 +1,7 @@
|
|||
package editor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gioui.org/widget"
|
||||
|
|
@ -56,8 +56,10 @@ const (
|
|||
type SortMode int
|
||||
|
||||
const (
|
||||
SortByDateNewest SortMode = iota // default: newest modified first
|
||||
SortByDateDesc SortMode = iota // default: newest first
|
||||
SortByDateAsc
|
||||
SortByNameAsc
|
||||
SortByNameDesc
|
||||
)
|
||||
|
||||
// State holds all application state owned by the logic goroutine.
|
||||
|
|
@ -78,6 +80,7 @@ type State struct {
|
|||
SortOrderLabel string // label text for sort order toggle
|
||||
SearchQuery string // current search query
|
||||
SearchEditor widget.Editor // Gio editor for search input
|
||||
SortedEntries []ui.ListItem // pre-sorted entries (computed only when sort mode changes)
|
||||
// Editor state
|
||||
ActiveFilename string // filename shown in editor status bar
|
||||
}
|
||||
|
|
@ -86,8 +89,9 @@ func NewState() *State {
|
|||
return &State{
|
||||
scale: 1.0,
|
||||
page: EditorPage,
|
||||
SortMode: SortByDateNewest,
|
||||
SortOrderLabel: "Date",
|
||||
SortMode: SortByDateDesc,
|
||||
SortOrderLabel: "Date ↓",
|
||||
SortedEntries: sortEntries(browserEntries, SortByDateDesc),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +113,9 @@ func (s *State) layout() []ui.Element {
|
|||
newQuery := s.SearchEditor.Text()
|
||||
if newQuery != s.SearchQuery {
|
||||
s.BrowserScrollOffset = 0 // reset on query change
|
||||
// Re-sort the filtered entries
|
||||
filtered := getFilteredEntriesRaw()
|
||||
s.SortedEntries = sortEntries(filtered, s.SortMode)
|
||||
}
|
||||
s.SearchQuery = newQuery
|
||||
}
|
||||
|
|
@ -204,17 +211,22 @@ func OpenFile(data any) {
|
|||
TheState.page = EditorPage
|
||||
}
|
||||
|
||||
// ToggleSortOrder cycles the browser sort mode between date and name.
|
||||
// ToggleSortOrder cycles the browser sort mode through four modes.
|
||||
func ToggleSortOrder(data any) {
|
||||
fmt.Printf("[ToggleSortOrder] called, mode was %v\n", TheState.SortMode)
|
||||
TheState.SortMode = (TheState.SortMode + 1) % 2
|
||||
TheState.SortMode = (TheState.SortMode + 1) % 4
|
||||
switch TheState.SortMode {
|
||||
case SortByDateNewest:
|
||||
TheState.SortOrderLabel = "Date"
|
||||
case SortByDateDesc:
|
||||
TheState.SortOrderLabel = "Date ↓"
|
||||
case SortByDateAsc:
|
||||
TheState.SortOrderLabel = "Date ↑"
|
||||
case SortByNameAsc:
|
||||
TheState.SortOrderLabel = "Name"
|
||||
TheState.SortOrderLabel = "Name ↑"
|
||||
case SortByNameDesc:
|
||||
TheState.SortOrderLabel = "Name ↓"
|
||||
}
|
||||
fmt.Printf("[ToggleSortOrder] mode is now %v\n", TheState.SortMode)
|
||||
// Sort once when mode changes, not every frame
|
||||
TheState.SortedEntries = sortEntries(getFilteredEntriesRaw(), TheState.SortMode)
|
||||
TheState.BrowserScrollOffset = 0 // reset scroll on sort change
|
||||
}
|
||||
|
||||
// EditorLayout computes the element tree for the editor page.
|
||||
|
|
@ -301,8 +313,9 @@ func EditorLayout(screenWidth, screenHeight ui.Dp, wordWrap bool) []ui.Element {
|
|||
return []ui.Element{statusBar, editor, bottomBar}
|
||||
}
|
||||
|
||||
// getFilteredEntries returns browser entries filtered by the current search query.
|
||||
func getFilteredEntries() []ui.ListItem {
|
||||
// getFilteredEntriesRaw returns browser entries filtered by the current search query.
|
||||
// Does not use the SortedEntries cache.
|
||||
func getFilteredEntriesRaw() []ui.ListItem {
|
||||
var filtered []ui.ListItem
|
||||
query := strings.ToLower(TheState.SearchQuery)
|
||||
if query == "" {
|
||||
|
|
@ -317,6 +330,52 @@ func getFilteredEntries() []ui.ListItem {
|
|||
return filtered
|
||||
}
|
||||
|
||||
// getFilteredEntries returns browser entries filtered by the current search query.
|
||||
// If SortedEntries is non-nil (sort mode has been set), returns that instead.
|
||||
func getFilteredEntries() []ui.ListItem {
|
||||
if TheState.SortedEntries != nil {
|
||||
return TheState.SortedEntries
|
||||
}
|
||||
return getFilteredEntriesRaw()
|
||||
}
|
||||
|
||||
// sortEntries sorts the entries according to the given sort mode.
|
||||
func sortEntries(entries []ui.ListItem, mode SortMode) []ui.ListItem {
|
||||
// Make a copy to avoid modifying the original slice
|
||||
sorted := make([]ui.ListItem, len(entries))
|
||||
copy(sorted, entries)
|
||||
|
||||
// Parse date from subtext (format: "2025-01-15 • 4.2 KB")
|
||||
getDate := func(entry ui.ListItem) string {
|
||||
// Extract date part before the first space
|
||||
parts := strings.Split(entry.Subtext, " ")
|
||||
if len(parts) > 0 {
|
||||
return parts[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case SortByDateDesc:
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return getDate(sorted[i]) > getDate(sorted[j])
|
||||
})
|
||||
case SortByDateAsc:
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return getDate(sorted[i]) < getDate(sorted[j])
|
||||
})
|
||||
case SortByNameAsc:
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return strings.ToLower(sorted[i].Text) < strings.ToLower(sorted[j].Text)
|
||||
})
|
||||
case SortByNameDesc:
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return strings.ToLower(sorted[i].Text) > strings.ToLower(sorted[j].Text)
|
||||
})
|
||||
}
|
||||
return sorted
|
||||
}
|
||||
|
||||
// browserEntries is a static list of sample files for the browser page.
|
||||
// It is longer than the viewport so scrolling can be tested.
|
||||
var browserEntries = []ui.ListItem{
|
||||
|
|
@ -365,10 +424,14 @@ func BrowserLayout(screenWidth, screenHeight ui.Dp, sortMode SortMode) []ui.Elem
|
|||
}
|
||||
var sortLabel string
|
||||
switch sortMode {
|
||||
case SortByDateNewest:
|
||||
case SortByDateDesc:
|
||||
sortLabel = "Date ↓"
|
||||
case SortByDateAsc:
|
||||
sortLabel = "Date ↑"
|
||||
case SortByNameAsc:
|
||||
sortLabel = "Name ↑"
|
||||
case SortByNameDesc:
|
||||
sortLabel = "Name ↓"
|
||||
}
|
||||
headerBar := ui.NewContainer(
|
||||
headerRegion,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user