file.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package mobile
  2. import (
  3. "io"
  4. "fyne.io/fyne/v2"
  5. "fyne.io/fyne/v2/internal/driver/mobile/app"
  6. "fyne.io/fyne/v2/storage"
  7. )
  8. type fileOpen struct {
  9. io.ReadCloser
  10. uri fyne.URI
  11. done func()
  12. }
  13. func (f *fileOpen) URI() fyne.URI {
  14. return f.uri
  15. }
  16. func fileReaderForURI(u fyne.URI) (fyne.URIReadCloser, error) {
  17. file := &fileOpen{uri: u}
  18. read, err := nativeFileOpen(file)
  19. if read == nil {
  20. return nil, err
  21. }
  22. file.ReadCloser = read
  23. return file, err
  24. }
  25. func mobileFilter(filter storage.FileFilter) *app.FileFilter {
  26. mobile := &app.FileFilter{}
  27. if f, ok := filter.(*storage.MimeTypeFileFilter); ok {
  28. mobile.MimeTypes = f.MimeTypes
  29. } else if f, ok := filter.(*storage.ExtensionFileFilter); ok {
  30. mobile.Extensions = f.Extensions
  31. } else if filter != nil {
  32. fyne.LogError("Custom filter types not supported on mobile", nil)
  33. }
  34. return mobile
  35. }
  36. type hasOpenPicker interface {
  37. ShowFileOpenPicker(func(string, func()), *app.FileFilter)
  38. }
  39. // ShowFileOpenPicker loads the native file open dialog and returns the chosen file path via the callback func.
  40. func ShowFileOpenPicker(callback func(fyne.URIReadCloser, error), filter storage.FileFilter) {
  41. drv := fyne.CurrentApp().Driver().(*mobileDriver)
  42. if a, ok := drv.app.(hasOpenPicker); ok {
  43. a.ShowFileOpenPicker(func(uri string, closer func()) {
  44. if uri == "" {
  45. callback(nil, nil)
  46. return
  47. }
  48. f, err := fileReaderForURI(nativeURI(uri))
  49. if f != nil {
  50. f.(*fileOpen).done = closer
  51. }
  52. callback(f, err)
  53. }, mobileFilter(filter))
  54. }
  55. }
  56. // ShowFolderOpenPicker loads the native folder open dialog and calls back the chosen directory path as a ListableURI.
  57. func ShowFolderOpenPicker(callback func(fyne.ListableURI, error)) {
  58. filter := storage.NewMimeTypeFileFilter([]string{"application/x-directory"})
  59. drv := fyne.CurrentApp().Driver().(*mobileDriver)
  60. if a, ok := drv.app.(hasOpenPicker); ok {
  61. a.ShowFileOpenPicker(func(path string, _ func()) {
  62. if path == "" {
  63. callback(nil, nil)
  64. return
  65. }
  66. uri, err := storage.ParseURI(path)
  67. if err != nil {
  68. callback(nil, err)
  69. return
  70. }
  71. callback(listerForURI(uri))
  72. }, mobileFilter(filter))
  73. }
  74. }
  75. type fileSave struct {
  76. io.WriteCloser
  77. uri fyne.URI
  78. done func()
  79. }
  80. func (f *fileSave) URI() fyne.URI {
  81. return f.uri
  82. }
  83. func fileWriterForURI(u fyne.URI) (fyne.URIWriteCloser, error) {
  84. file := &fileSave{uri: u}
  85. write, err := nativeFileSave(file)
  86. if write == nil {
  87. return nil, err
  88. }
  89. file.WriteCloser = write
  90. return file, err
  91. }
  92. type hasSavePicker interface {
  93. ShowFileSavePicker(func(string, func()), *app.FileFilter, string)
  94. }
  95. // ShowFileSavePicker loads the native file save dialog and returns the chosen file path via the callback func.
  96. func ShowFileSavePicker(callback func(fyne.URIWriteCloser, error), filter storage.FileFilter, filename string) {
  97. drv := fyne.CurrentApp().Driver().(*mobileDriver)
  98. if a, ok := drv.app.(hasSavePicker); ok {
  99. a.ShowFileSavePicker(func(path string, closer func()) {
  100. if path == "" {
  101. callback(nil, nil)
  102. return
  103. }
  104. uri, err := storage.ParseURI(path)
  105. if err != nil {
  106. callback(nil, err)
  107. return
  108. }
  109. f, err := fileWriterForURI(uri)
  110. if f != nil {
  111. f.(*fileSave).done = closer
  112. }
  113. callback(f, err)
  114. }, mobileFilter(filter), filename)
  115. }
  116. }