comparison libervia/desktop_kivy/core/file_chooser.py @ 514:d78728d7fd6a

plugin wid calls, core: implements WebRTC DataChannel file transfer: - Add a new "file" icon in call UI to send a file via WebRTC. - Handle new preflight mechanism, and WebRTC file transfer. - Native file chooser handling has been moved to new `core.file_chooser` module, and now supports "save" and "dir" modes (based on `plyer`). rel 442
author Goffi <goffi@goffi.org>
date Sat, 06 Apr 2024 13:37:27 +0200
parents
children
comparison
equal deleted inserted replaced
513:0fdf3e59aaad 514:d78728d7fd6a
1 #!/usr/bin/env python3
2
3 # Libervia Desktop-Kivy
4 # Copyright (C) 2016-2024 Jérôme Poisson (goffi@goffi.org)
5
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Affero General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Affero General Public License for more details.
15
16 # You should have received a copy of the GNU Affero General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 import asyncio
20 import threading
21
22 from libervia.backend.core import exceptions
23 from libervia.backend.core.i18n import _
24
25 from kivy import properties
26 from kivy.clock import Clock
27 from kivy.event import EventDispatcher
28 from plyer import filechooser, storagepath
29
30
31 class FileChooser(EventDispatcher):
32 callback = properties.ObjectProperty()
33 cancel_cb = properties.ObjectProperty()
34 native_filechooser = True
35 default_path = properties.StringProperty(storagepath.get_home_dir())
36 mode = properties.OptionProperty("open", options=["open", "save", "dir"])
37 title = properties.StringProperty(_("Please select a file to upload"))
38
39 def open(self):
40 """Open the file selection dialog in a separate thread"""
41 thread = threading.Thread(target=self._native_file_chooser)
42 thread.start()
43
44 @classmethod
45 async def a_open(cls, **kwargs) -> str | None:
46 """Open the file selection dialog asynchronously
47
48 @return: The path of the selected file
49 None if the dialog has been cancelled.
50 """
51 future = asyncio.Future()
52
53 def on_success(file_path):
54 if not future.done():
55 future.set_result(file_path)
56
57 def on_cancel(__):
58 if not future.done():
59 future.set_result(None)
60
61 file_chooser = cls(
62 **kwargs,
63 callback=on_success,
64 cancel_cb=on_cancel
65 )
66
67 file_chooser.open()
68
69 return await future
70
71 def _native_file_chooser(self, *args, **kwargs):
72 match self.mode:
73 case "open":
74 method = filechooser.open_file
75 case "save":
76 method = filechooser.save_file
77 case "dir":
78 method = filechooser.choose_dir
79 case _:
80 raise exceptions.InternalError("Should never be reached.")
81 files = method(
82 title=self.title, path=self.default_path, multiple=False, preview=True
83 )
84 # we want to leave the thread when calling on_files, so we use Clock
85 Clock.schedule_once(lambda *args: self.on_files(files=files), 0)
86
87 def on_files(self, files):
88 if files:
89 self.callback(files[0])
90 else:
91 self.cancel_cb(self)