From dd71a2240a150b647581daa86ab6a009c91211ac Mon Sep 17 00:00:00 2001 From: Gerhard Tan Date: Fri, 28 Jun 2024 10:03:24 +0000 Subject: [PATCH] Support custom sort order in config list --- pkg/config/app.go | 1 + ui/conf.go | 17 ++++++++++++++++ ui/confview.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++ ui/model.go | 7 ++++++- 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/pkg/config/app.go b/pkg/config/app.go index 139970fa..3c895097 100644 --- a/pkg/config/app.go +++ b/pkg/config/app.go @@ -13,6 +13,7 @@ type App struct { Lang string `json:"lang,omitempty"` Password string `json:"password,omitempty"` Defaults DefaultValue `json:"defaults"` + Sort []string `json:"sort,omitempty"` } type DefaultValue struct { diff --git a/ui/conf.go b/ui/conf.go index 6999ed21..38a1b42e 100644 --- a/ui/conf.go +++ b/ui/conf.go @@ -4,9 +4,11 @@ import ( "os" "path/filepath" "slices" + "strings" "sync" "github.com/lxn/walk" + "github.com/samber/lo" "github.com/koho/frpmgr/pkg/config" "github.com/koho/frpmgr/pkg/consts" @@ -74,6 +76,7 @@ func (conf *Conf) Delete() (bool, error) { func (conf *Conf) Save() error { conf.Data.Complete(false) conf.Path = PathOfConf(conf.Name + ".conf") + defer saveAppConfig() return conf.Data.Save(conf.Path) } @@ -111,6 +114,16 @@ func loadAllConfs() error { confList = append(confList, c) } } + slices.SortStableFunc(confList, func(a, b *Conf) int { + i := slices.Index(appConf.Sort, strings.TrimSuffix(filepath.Base(a.Path), filepath.Ext(a.Path))) + j := slices.Index(appConf.Sort, strings.TrimSuffix(filepath.Base(b.Path), filepath.Ext(b.Path))) + if i < 0 && j >= 0 { + return 1 + } else if j < 0 && i >= 0 { + return -1 + } + return i - j + }) return nil } @@ -133,6 +146,7 @@ func addConf(conf *Conf) { func deleteConf(conf *Conf) bool { confMutex.Lock() defer confMutex.Unlock() + defer saveAppConfig() for i := range confList { if confList[i] == conf { confList = append(confList[:i], confList[i+1:]...) @@ -194,5 +208,8 @@ func newDefaultClientConfig() *config.ClientConfig { } func saveAppConfig() error { + appConf.Sort = lo.Map(confList, func(item *Conf, index int) string { + return strings.TrimSuffix(filepath.Base(item.Path), filepath.Ext(item.Path)) + }) return appConf.Save(config.DefaultAppFile) } diff --git a/ui/confview.go b/ui/confview.go index 888b3b6d..1c589f9f 100644 --- a/ui/confview.go +++ b/ui/confview.go @@ -46,11 +46,14 @@ func NewConfView() *ConfView { } func (cv *ConfView) View() Widget { + moveUpCond := Bind("confView.CurrentIndex > 0") + moveDownCond := Bind("confView.CurrentIndex >= 0 && confView.CurrentIndex < confView.ItemCount - 1") return Composite{ AssignTo: &cv.Composite, Layout: VBox{MarginsZero: true, SpacingZero: true}, Children: []Widget{ TableView{ + Name: "confView", AssignTo: &cv.listView, LastColumnStretched: true, HeaderHidden: true, @@ -63,6 +66,40 @@ func (cv *ConfView) View() Widget { Enabled: Bind("conf.Selected"), OnTriggered: cv.editCurrent, }, + Menu{ + Text: i18n.Sprintf("Move"), + Enabled: Bind("confView.CurrentIndex >= 0 && confView.ItemCount > 1"), + Items: []MenuItem{ + Action{ + Text: i18n.Sprintf("Up"), + Enabled: moveUpCond, + OnTriggered: func() { + cv.onMove(-1) + }, + }, + Action{ + Text: i18n.Sprintf("Down"), + Enabled: moveDownCond, + OnTriggered: func() { + cv.onMove(1) + }, + }, + Action{ + Text: i18n.Sprintf("To Top"), + Enabled: moveUpCond, + OnTriggered: func() { + cv.onMove(-cv.listView.CurrentIndex()) + }, + }, + Action{ + Text: i18n.Sprintf("To Bottom"), + Enabled: moveDownCond, + OnTriggered: func() { + cv.onMove(len(cv.model.items) - cv.listView.CurrentIndex() - 1) + }, + }, + }, + }, Action{Text: i18n.Sprintf("Open File"), Enabled: Bind("conf.Selected"), OnTriggered: func() { cv.onOpen(false) }, @@ -557,6 +594,20 @@ func (cv *ConfView) onNATDiscovery() { } } +func (cv *ConfView) onMove(delta int) { + curIdx := cv.listView.CurrentIndex() + if curIdx < 0 || curIdx >= len(cv.model.items) { + return + } + targetIdx := curIdx + delta + if targetIdx < 0 || targetIdx >= len(cv.model.items) { + return + } + cv.model.Move(curIdx, targetIdx) + saveAppConfig() + cv.listView.SetCurrentIndex(targetIdx) +} + // reset config listview with selected name func (cv *ConfView) reset(selectName string) { // Make sure `sel` is a valid index diff --git a/ui/model.go b/ui/model.go index b740c382..7e393166 100644 --- a/ui/model.go +++ b/ui/model.go @@ -13,7 +13,7 @@ import ( ) type ConfListModel struct { - walk.TableModelBase + walk.ReflectTableModelBase items []*Conf } @@ -35,6 +35,11 @@ func (m *ConfListModel) Items() interface{} { return m.items } +func (m *ConfListModel) Move(i, j int) { + util.MoveSlice(m.items, i, j) + m.PublishRowsChanged(min(i, j), max(i, j)) +} + type ListModel struct { walk.ListModelBase