Skip to content

Commit

Permalink
Add support for opening folders.
Browse files Browse the repository at this point in the history
This does open mobile pickers as well, though the lack of ListableURI in mobile means it does not return correctly.

Fixes fyne-io#941
  • Loading branch information
andydotxyz committed Oct 23, 2020
1 parent 41c8fe3 commit 970ef77
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 188 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -8,7 +8,7 @@ More detailed release notes can be found on the [releases page](https://github.c
### Added (highlights)

* List (#156), Table (#157) and Tree collection Widgets
* Card, FileItem widgets
* Card, FileItem, Separator widgets
* ColorPicker dialog
* User selection of primary colour
* Container API package to ease using layouts and container widgets
Expand All @@ -20,6 +20,7 @@ More detailed release notes can be found on the [releases page](https://github.c
* Canvas.InteractiveArea() to indicate where widgets should avoid
* TextFormatter for ProgressBar
* FileDialog.SetLocation() (#821)
* Added dialog.ShowFolderOpen (#941)
* Support to install on iOS and android with 'fyne install'
* Support asset bundling with go:generate
* Add fyne release command for preparing signed apps
Expand Down
354 changes: 179 additions & 175 deletions cmd/fyne/internal/mobile/dex.go

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions cmd/fyne_demo/screens/window.go
Expand Up @@ -172,6 +172,18 @@ func loadDialogGroup(win fyne.Window) *widget.Card {
fileSaved(writer)
}, win)
}),
widget.NewButton("Folder Open", func() {
dialog.ShowFolderOpen(func(list fyne.ListableURI, err error) {
if list == nil {
return
}
if err != nil {
dialog.ShowError(err, win)
return
}
dialog.ShowInformation("Folder Open", list.String(), win)
}, win)
}),
widget.NewButton("Color Picker", func() {
picker := dialog.NewColorPicker("Pick a Color", "What is your favorite color?", func(c color.Color) {
colorPicked(c, win)
Expand Down
26 changes: 25 additions & 1 deletion dialog/file.go
Expand Up @@ -120,6 +120,13 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
f.file.onClosedCallback(true)
}
callback(storage.OpenFileFromURI(f.selected.location))
} else if f.file.isDirectory() {
callback := f.file.callback.(func(fyne.ListableURI, error))
f.win.Hide()
if f.file.onClosedCallback != nil {
f.file.onClosedCallback(true)
}
callback(f.dir, nil)
}
})
f.open.Style = widget.PrimaryButton
Expand All @@ -136,6 +143,8 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
if f.file.callback != nil {
if f.file.save {
f.file.callback.(func(fyne.URIWriteCloser, error))(nil, nil)
} else if f.file.isDirectory() {
f.file.callback.(func(fyne.ListableURI, error))(nil, nil)
} else {
f.file.callback.(func(fyne.URIReadCloser, error))(nil, nil)
}
Expand All @@ -157,7 +166,11 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
scrollBread := widget.NewHScrollContainer(f.breadcrumb)
body := fyne.NewContainerWithLayout(layout.NewBorderLayout(scrollBread, nil, nil, nil),
scrollBread, f.fileScroll)
header := widget.NewLabelWithStyle(label+" File", fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
title := label + " File"
if f.file.isDirectory() {
title = label + " Folder"
}
header := widget.NewLabelWithStyle(title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true})

favorites := f.loadFavorites()

Expand Down Expand Up @@ -215,6 +228,9 @@ func (f *fileDialog) refreshDir(dir fyne.ListableURI) {
if isHidden(file) {
continue
}
if f.file.isDirectory() && !isListable(file) {
continue
}

_, err := storage.ListerForURI(file)
if err == nil {
Expand Down Expand Up @@ -273,6 +289,10 @@ func (f *fileDialog) setLocation(dir fyne.ListableURI) error {
)
}

if f.file.isDirectory() {
f.fileName.SetText(dir.Name())
f.open.Enable()
}
f.refreshDir(dir)

return nil
Expand Down Expand Up @@ -479,6 +499,10 @@ func (f *FileDialog) SetOnClosed(closed func()) {

// SetFilter sets a filter for limiting files that can be chosen in the file dialog.
func (f *FileDialog) SetFilter(filter storage.FileFilter) {
if f.isDirectory() {
fyne.LogError("Cannot set a filter for a folder dialog", nil)
return
}
f.filter = filter
if f.dialog != nil {
f.dialog.refreshDir(f.dialog.dir)
Expand Down
6 changes: 5 additions & 1 deletion dialog/file_mobile.go
Expand Up @@ -23,7 +23,11 @@ func isHidden(file fyne.URI) bool {
}

func fileOpenOSOverride(f *FileDialog) bool {
gomobile.ShowFileOpenPicker(f.callback.(func(fyne.URIReadCloser, error)), f.filter)
if f.isDirectory() {
gomobile.ShowFolderOpenPicker(f.callback.(func(fyne.ListableURI, error)))
} else {
gomobile.ShowFileOpenPicker(f.callback.(func(fyne.URIReadCloser, error)), f.filter)
}
return true
}

Expand Down
41 changes: 41 additions & 0 deletions dialog/folder.go
@@ -0,0 +1,41 @@
package dialog

import (
"fyne.io/fyne"
"fyne.io/fyne/storage"
)

var folderFilter = storage.NewMimeTypeFileFilter([]string{"application/x-directory"})

// NewFolderOpen creates a file dialog allowing the user to choose a folder to open.
// The dialog will appear over the window specified when Show() is called.
func NewFolderOpen(callback func(fyne.ListableURI, error), parent fyne.Window) *FileDialog {
dialog := &FileDialog{}
dialog.callback = callback
dialog.parent = parent
dialog.filter = folderFilter
return dialog
}

// ShowFolderOpen creates and shows a file dialog allowing the user to choose a folder to open.
// The dialog will appear over the window specified.
func ShowFolderOpen(callback func(fyne.ListableURI, error), parent fyne.Window) {
dialog := NewFolderOpen(callback, parent)
if fileOpenOSOverride(dialog) {
return
}
dialog.Show()
}

func (f *FileDialog) isDirectory() bool {
return f.filter == folderFilter
}

func isListable(u fyne.URI) bool {
if _, ok := u.(fyne.ListableURI); ok {
return true
}

_, err := storage.ListerForURI(u)
return err == nil
}
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -7,7 +7,7 @@ require (
github.com/akavel/rsrc v0.8.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.4.9
github.com/fyne-io/mobile v0.0.3-0.20201019162131-a1e87190904e
github.com/fyne-io/mobile v0.0.3-0.20201023100309-6e4995148130
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3
github.com/godbus/dbus/v5 v5.0.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -8,8 +8,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fyne-io/mobile v0.0.3-0.20201019162131-a1e87190904e h1:8uXNy4NvCpLlfg1R01TJk0+n5trhDc0vofqbA/S1I48=
github.com/fyne-io/mobile v0.0.3-0.20201019162131-a1e87190904e/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
github.com/fyne-io/mobile v0.0.3-0.20201023100309-6e4995148130 h1:l+E5KcwiFEOR/0y8I+fIlUOpvSskhyNQ/8e2geqRJ6Y=
github.com/fyne-io/mobile v0.0.3-0.20201023100309-6e4995148130/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 h1:q521PfSp5/z6/sD9FZZOWj4d1MLmfQW8PkRnI9M6PCE=
Expand Down
12 changes: 12 additions & 0 deletions internal/driver/gomobile/file.go
Expand Up @@ -74,3 +74,15 @@ func ShowFileOpenPicker(callback func(fyne.URIReadCloser, error), filter storage
}, mobileFilter(filter))
}
}

// ShowFolderOpenPicker loads the native folder open dialog and calls back the chosen directory path as a ListableURI.
func ShowFolderOpenPicker(callback func(fyne.ListableURI, error)) {
filter := storage.NewMimeTypeFileFilter([]string{"application/x-directory"})
drv := fyne.CurrentApp().Driver().(*mobileDriver)
if a, ok := drv.app.(hasPicker); ok {
a.ShowFileOpenPicker(func(uri string, _ func()) {
f, err := drv.ListerForURI(storage.NewURI(uri))
callback(f, err)
}, mobileFilter(filter))
}
}
8 changes: 6 additions & 2 deletions vendor/github.com/fyne-io/mobile/app/GoNativeActivity.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions vendor/github.com/fyne-io/mobile/app/darwin_ios.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/modules.txt
Expand Up @@ -8,7 +8,7 @@ github.com/akavel/rsrc/ico
github.com/davecgh/go-spew/spew
# github.com/fsnotify/fsnotify v1.4.9
github.com/fsnotify/fsnotify
# github.com/fyne-io/mobile v0.0.3-0.20201019162131-a1e87190904e
# github.com/fyne-io/mobile v0.0.3-0.20201023100309-6e4995148130
github.com/fyne-io/mobile/app
github.com/fyne-io/mobile/app/internal/callfn
github.com/fyne-io/mobile/event/key
Expand Down

0 comments on commit 970ef77

Please sign in to comment.