Skip to content

Commit

Permalink
added a search bar to the file dialog
Browse files Browse the repository at this point in the history
the search bar takes advantage of the existing filtering system in order
to only show files or filders that match a specific prompt. for now,
there is no way to recursively search through files, or use something
like regex, though that could be added as options later.

the main internal change needed is, in order to be backwards compatible,
having a list of filters instead of just a single filter at a time. that
way, library users can still have many filters while including the
search bar.
  • Loading branch information
billyb2 committed Sep 13, 2024
1 parent ef35454 commit 828ea2f
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 8 deletions.
61 changes: 55 additions & 6 deletions dialog/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ type FileDialog struct {

confirmText, dismissText string
desiredSize fyne.Size
filter storage.FileFilter
filter []storage.FileFilter
save bool
// this will be applied to dialog.dir when it's loaded
startingLocation fyne.ListableURI
Expand Down Expand Up @@ -203,6 +203,23 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
f.optionsMenu(fyne.CurrentApp().Driver().AbsolutePositionForObject(optionsButton), optionsButton.Size())
})

searchBar := widget.NewEntry()
searchBar.OnChanged = func(filterText string) {
for _, filter := range f.file.filter {
if filter, ok := filter.(*storage.SearchFilter); ok {
filter.FilterText = filterText
}
}
f.refreshDir(f.dir)
}
searchBar.Hidden = true
// we should only draw the search bar if we've added a search filter
for _, filter := range f.file.filter {
if _, ok := filter.(*storage.SearchFilter); ok {
searchBar.Hidden = false
}
}

newFolderButton := widget.NewButtonWithIcon("", theme.FolderNewIcon(), func() {
newFolderEntry := widget.NewEntry()
ShowForm(lang.L("New Folder"), lang.L("Create Folder"), lang.L("Cancel"), []*widget.FormItem{
Expand Down Expand Up @@ -234,8 +251,8 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
optionsButton,
)

header := container.NewBorder(nil, nil, nil, optionsbuttons,
optionsbuttons, widget.NewLabelWithStyle(title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
header := container.NewBorder(nil, nil, container.NewHBox(widget.NewLabelWithStyle(title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), searchBar), optionsbuttons,
optionsbuttons,
)

footer := container.NewBorder(nil, nil, nil, buttons,
Expand Down Expand Up @@ -415,8 +432,18 @@ func (f *fileDialog) refreshDir(dir fyne.ListableURI) {
continue
} else if err == nil { // URI points to a directory
icons = append(icons, listable)
} else if f.file.filter == nil || f.file.filter.Matches(file) {
icons = append(icons, file)
} else {
filterMatches := true
for _, filter := range f.file.filter {
if !filter.Matches(file) {
filterMatches = false
break
}
}

if filterMatches {
icons = append(icons, file)
}
}
}

Expand Down Expand Up @@ -801,12 +828,34 @@ func (f *FileDialog) SetFilter(filter storage.FileFilter) {
fyne.LogError("Cannot set a filter for a folder dialog", nil)
return
}
f.filter = filter
f.filter = []storage.FileFilter{filter}
if f.dialog != nil {
f.dialog.refreshDir(f.dialog.dir)
}
}

// AddFilter adds to the list of existing filters for limiting files that can be chosen in the file dialog
func (f *FileDialog) AddFilter(filter storage.FileFilter) {
if f.isDirectory() {
fyne.LogError("Cannot set a filter for a folder dialog", nil)
return
}
if f.filter == nil {
f.filter = []storage.FileFilter{}
}
f.filter = append(f.filter, filter)
if f.dialog != nil {
f.dialog.refreshDir(f.dialog.dir)
}
}

type ShowSearchBarArgs struct{}

// ShowSearchBar adds a search bar to the file dialog, and allows filtering for specific text in the local directory
func (f *FileDialog) ShowSearchBar(ShowSearchBarArgs) {
f.AddFilter(&storage.SearchFilter{})
}

// SetFileName sets the filename in a FileDialog in save mode.
// This is normally called before the dialog is shown.
func (f *FileDialog) SetFileName(fileName string) {
Expand Down
13 changes: 11 additions & 2 deletions dialog/folder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ func NewFolderOpen(callback func(fyne.ListableURI, error), parent fyne.Window) *
dialog := &FileDialog{}
dialog.callback = callback
dialog.parent = parent
dialog.filter = folderFilter
if dialog.filter == nil {
dialog.filter = []storage.FileFilter{}
}
dialog.filter = append(dialog.filter, folderFilter)
return dialog
}

Expand All @@ -38,5 +41,11 @@ func ShowFolderOpen(callback func(fyne.ListableURI, error), parent fyne.Window)
}

func (f *FileDialog) isDirectory() bool {
return f.filter == folderFilter
for _, filter := range f.filter {
if filter == folderFilter {
return true
}
}

return false
}
9 changes: 9 additions & 0 deletions storage/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ type MimeTypeFileFilter struct {
MimeTypes []string
}

// SearchFilter represents a file or directory filter based on user inputted text
type SearchFilter struct {
FilterText string
}

// Matches returns true if a file URI has one of the filtered extensions.
func (e *ExtensionFileFilter) Matches(uri fyne.URI) bool {
extension := uri.Extension()
Expand Down Expand Up @@ -63,3 +68,7 @@ func (mt *MimeTypeFileFilter) Matches(uri fyne.URI) bool {
func NewMimeTypeFileFilter(mimeTypes []string) FileFilter {
return &MimeTypeFileFilter{MimeTypes: mimeTypes}
}

func (s *SearchFilter) Matches(uri fyne.URI) bool {
return strings.Contains(uri.Name(), s.FilterText)
}

0 comments on commit 828ea2f

Please sign in to comment.