~whereswaldon/gio-x

abf2811a8cc2a36baf7b8d9fe9a4241d5ae5b117 — Sebastien Binet 4 months ago e9435b4
explorer: introduce ChooseFiles to select multiple files

This CL introduces a new API, ChooseFiles, to allow users to select
multiple files through the native mecanism to do so.

Signed-off-by: Sebastien Binet <binet@cern.ch>
M explorer/explorer.go => explorer/explorer.go +27 -0
@@ 114,6 114,33 @@ func (e *Explorer) ChooseFile(extensions ...string) (io.ReadCloser, error) {
	return e.importFile(extensions...)
}

// ChooseFiles shows the files selector, allowing the user to select multiple files.
// Optionally, it's possible to define which file extensions is supported to
// be selected (such as `.jpg`, `.png`).
//
// Example: ChooseFiles(".jpg", ".png") will only accept the selection of files with
// .jpg or .png extensions.
//
// In some platforms the resulting `io.ReadCloser` is a `os.File`, but it's not
// a guarantee.
//
// In most known browsers, when user clicks cancel then this function never returns.
//
// It's a blocking call, you should call it on a separated goroutine. For most OSes, only one
// ChooseFile{,s} or CreateFile, can happen at the same time, for each app.Window/Explorer.
func (e *Explorer) ChooseFiles(extensions ...string) ([]io.ReadCloser, error) {
	if e == nil {
		return nil, ErrNotAvailable
	}

	if runtime.GOOS != "js" {
		e.mutex.Lock()
		defer e.mutex.Unlock()
	}

	return e.importFiles(extensions...)
}

// CreateFile opens the file selector, and writes the given content into
// some file, which the use can choose the location.
//

M explorer/explorer_android.go => explorer/explorer_android.go +4 -0
@@ 132,6 132,10 @@ func (e *Explorer) importFile(extensions ...string) (io.ReadCloser, error) {
	return file.file.(io.ReadCloser), nil
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

//export Java_org_gioui_x_explorer_explorer_1android_ImportCallback
func Java_org_gioui_x_explorer_explorer_1android_ImportCallback(env *C.JNIEnv, _ C.jclass, stream C.jobject, id C.jint, err C.jstring) {
	fileCallback(env, stream, id, err)

M explorer/explorer_ios.go => explorer/explorer_ios.go +4 -0
@@ 97,6 97,10 @@ func (e *Explorer) importFile(extensions ...string) (io.ReadCloser, error) {
	return file.file.(io.ReadCloser), nil
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

//export importCallback
func importCallback(u C.CFTypeRef, id C.int32_t) {
	fileCallback(u, id)

M explorer/explorer_js.go => explorer/explorer_js.go +4 -0
@@ 50,6 50,10 @@ func (e *Explorer) importFile(extensions ...string) (io.ReadCloser, error) {
	return file.file.(io.ReadCloser), nil
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

type FileReader struct {
	buffer                   js.Value
	isClosed                 bool

M explorer/explorer_linux.go => explorer/explorer_linux.go +4 -0
@@ 276,3 276,7 @@ func (e *Explorer) importFile(extensions ...string) (io.ReadCloser, error) {
	}
	return os.Open(filepath)
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

M explorer/explorer_macos.go => explorer/explorer_macos.go +4 -0
@@ 69,6 69,10 @@ func (e *Explorer) importFile(extensions ...string) (io.ReadCloser, error) {
	return resp.file.(io.ReadCloser), resp.error
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

//export importCallback
func importCallback(u *C.char, id int32) {
	if v, ok := active.Load(id); ok {

M explorer/explorer_unsupported.go => explorer/explorer_unsupported.go +4 -0
@@ 27,3 27,7 @@ func (e *Explorer) exportFile(_ string) (io.WriteCloser, error) {
func (e *Explorer) importFile(_ ...string) (io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

M explorer/explorer_windows.go => explorer/explorer_windows.go +4 -0
@@ 118,6 118,10 @@ func (e *Explorer) importFile(extensions ...string) (io.ReadCloser, error) {
	return os.Open(path)
}

func (e *Explorer) importFiles(_ ...string) ([]io.ReadCloser, error) {
	return nil, ErrNotAvailable
}

func buildFilter(extensions []string) *uint16 {
	if len(extensions) <= 0 {
		return nil