Mercurial > libervia-desktop-kivy
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libervia/desktop_kivy/core/file_chooser.py Sat Apr 06 13:37:27 2024 +0200 @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 + +# Libervia Desktop-Kivy +# Copyright (C) 2016-2024 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import asyncio +import threading + +from libervia.backend.core import exceptions +from libervia.backend.core.i18n import _ + +from kivy import properties +from kivy.clock import Clock +from kivy.event import EventDispatcher +from plyer import filechooser, storagepath + + +class FileChooser(EventDispatcher): + callback = properties.ObjectProperty() + cancel_cb = properties.ObjectProperty() + native_filechooser = True + default_path = properties.StringProperty(storagepath.get_home_dir()) + mode = properties.OptionProperty("open", options=["open", "save", "dir"]) + title = properties.StringProperty(_("Please select a file to upload")) + + def open(self): + """Open the file selection dialog in a separate thread""" + thread = threading.Thread(target=self._native_file_chooser) + thread.start() + + @classmethod + async def a_open(cls, **kwargs) -> str | None: + """Open the file selection dialog asynchronously + + @return: The path of the selected file + None if the dialog has been cancelled. + """ + future = asyncio.Future() + + def on_success(file_path): + if not future.done(): + future.set_result(file_path) + + def on_cancel(__): + if not future.done(): + future.set_result(None) + + file_chooser = cls( + **kwargs, + callback=on_success, + cancel_cb=on_cancel + ) + + file_chooser.open() + + return await future + + def _native_file_chooser(self, *args, **kwargs): + match self.mode: + case "open": + method = filechooser.open_file + case "save": + method = filechooser.save_file + case "dir": + method = filechooser.choose_dir + case _: + raise exceptions.InternalError("Should never be reached.") + files = method( + title=self.title, path=self.default_path, multiple=False, preview=True + ) + # we want to leave the thread when calling on_files, so we use Clock + Clock.schedule_once(lambda *args: self.on_files(files=files), 0) + + def on_files(self, files): + if files: + self.callback(files[0]) + else: + self.cancel_cb(self)