mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 03:21:08 +00:00
Steam file dialog: keep spaces in the chosen path, cancel when GTK 3 is missing or the bridge reconnects
This commit is contained in:
1 parent
5a56d9f785
commit
8d66570d33
2 files changed
+39
-14
No files matched your search
@@ -199,9 +199,12 @@ TOUR_JS = r"""
|
||||
FILE_BINDING = "droiddeckOpenFileDialog"
|
||||
FILE_JS = r"""
|
||||
(() => {
|
||||
if (window.__droiddeckFiles) return "present";
|
||||
const self = { next: 0, pending: new Map() };
|
||||
const cancelled = () => ({ result: 2, message: "" });
|
||||
if (window.__droiddeckFiles) {
|
||||
window.__droiddeckFiles.cancelAll();
|
||||
return "present";
|
||||
}
|
||||
const self = { next: 0, pending: new Map() };
|
||||
const open = function (options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof window.__BINDING__ !== "function") { reject(cancelled()); return; }
|
||||
@@ -218,6 +221,11 @@ FILE_JS = r"""
|
||||
if (typeof path === "string" && path) item.resolve(path); else item.reject(cancelled());
|
||||
return true;
|
||||
};
|
||||
self.cancelAll = () => {
|
||||
const items = Array.from(self.pending.values());
|
||||
self.pending.clear();
|
||||
for (const item of items) item.reject(cancelled());
|
||||
};
|
||||
const patch = (w) => {
|
||||
const system = w?.SteamClient?.System;
|
||||
if (system && system.OpenFileDialog !== open) system.OpenFileDialog = open;
|
||||
@@ -657,10 +665,16 @@ class Helper:
|
||||
def chooser_done(self):
|
||||
ident, proc = self.chooser
|
||||
self.chooser = None
|
||||
path = proc.stdout.read().decode("utf-8", "replace").strip()
|
||||
out = proc.stdout.read().decode("utf-8", "replace")
|
||||
proc.stdout.close()
|
||||
proc.wait()
|
||||
self.finish_chooser(ident, path if proc.returncode == 0 and path else None)
|
||||
if proc.returncode == 2:
|
||||
say("file dialog needs GTK 3 and PyGObject, which come with the desktop")
|
||||
try:
|
||||
path = json.loads(out) if proc.returncode == 0 else None
|
||||
except ValueError:
|
||||
path = None
|
||||
self.finish_chooser(ident, path if isinstance(path, str) and path else None)
|
||||
|
||||
def finish_chooser(self, ident, path):
|
||||
say("file dialog %s" % ("chose " + path if path else "cancelled"))
|
||||
@@ -878,10 +892,13 @@ def chooser_main():
|
||||
options = json.load(sys.stdin)
|
||||
except ValueError:
|
||||
return 1
|
||||
path = choose_file(options if isinstance(options, dict) else {})
|
||||
try:
|
||||
path = choose_file(options if isinstance(options, dict) else {})
|
||||
except (ImportError, ValueError):
|
||||
return 2
|
||||
if not path:
|
||||
return 1
|
||||
print(path)
|
||||
print(json.dumps(path))
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,11 @@ window.droiddeckOpenFileDialog = payload => asked.push(JSON.parse(payload));
|
||||
const script = require('fs').readFileSync(process.argv[2], 'utf8');
|
||||
(async () => {
|
||||
assert.strictEqual(eval(script), 'installed');
|
||||
const orphan = SteamClient.System.OpenFileDialog({ strTitle: 'Before reconnect' });
|
||||
assert.strictEqual(eval(script), 'present');
|
||||
await assert.rejects(orphan, e => e.result === 2);
|
||||
assert.strictEqual(window.__droiddeckFiles.done(1, '/late'), false);
|
||||
asked.length = 0;
|
||||
assert.notStrictEqual(SteamClient.System.OpenFileDialog, native);
|
||||
assert.strictEqual(popup.window.SteamClient.System.OpenFileDialog, SteamClient.System.OpenFileDialog);
|
||||
popupCallbacks.forEach(cb => cb(later));
|
||||
@@ -34,11 +38,11 @@ const script = require('fs').readFileSync(process.argv[2], 'utf8');
|
||||
const options = { strTitle: 'Pick', bChooseDirectory: true };
|
||||
const chosen = SteamClient.System.OpenFileDialog(options);
|
||||
const cancelled = later.window.SteamClient.System.OpenFileDialog({ strTitle: 'Other' });
|
||||
assert.deepStrictEqual(asked, [{ id: 1, options }, { id: 2, options: { strTitle: 'Other' } }]);
|
||||
assert.strictEqual(window.__droiddeckFiles.done(1, '/root/Storage/Games'), true);
|
||||
assert.strictEqual(window.__droiddeckFiles.done(1, '/again'), false);
|
||||
assert.deepStrictEqual(asked, [{ id: 2, options }, { id: 3, options: { strTitle: 'Other' } }]);
|
||||
assert.strictEqual(window.__droiddeckFiles.done(2, '/root/Storage/Games'), true);
|
||||
assert.strictEqual(window.__droiddeckFiles.done(2, '/again'), false);
|
||||
assert.strictEqual(await chosen, '/root/Storage/Games');
|
||||
window.__droiddeckFiles.done(2, null);
|
||||
window.__droiddeckFiles.done(3, null);
|
||||
await assert.rejects(cancelled, e => e.result === 2);
|
||||
delete window.droiddeckOpenFileDialog;
|
||||
await assert.rejects(SteamClient.System.OpenFileDialog({}), e => e.result === 2);
|
||||
@@ -97,8 +101,9 @@ class FileDialogBridgeTest(unittest.TestCase):
|
||||
self.assertEqual(self.helper.chooser, (1, first))
|
||||
|
||||
def test_the_chosen_path_or_a_cancel_goes_back_to_the_page(self):
|
||||
for code, out, expected in ((0, b"/root/Storage/My Game/game.sh\n", '"/root/Storage/My Game/game.sh"'),
|
||||
(1, b"", "null"), (0, b"\n", "null")):
|
||||
for code, out, expected in ((0, b'"/root/Storage/My Game/game.sh"\n', '"/root/Storage/My Game/game.sh"'),
|
||||
(0, b'" spaced name "\n', '" spaced name "'),
|
||||
(1, b"", "null"), (2, b"", "null"), (0, b"\n", "null"), (0, b"not json\n", "null")):
|
||||
proc = mock.Mock(stdout=io.BytesIO(out), returncode=code)
|
||||
self.helper.chooser = (7, proc)
|
||||
self.helper.chooser_done()
|
||||
@@ -113,8 +118,11 @@ class FileDialogBridgeTest(unittest.TestCase):
|
||||
self.helper.page.evaluate.assert_not_called()
|
||||
|
||||
def test_choose_file_mode_prints_the_path_and_fails_on_cancel(self):
|
||||
for chosen, code, printed in (("/root/Storage/a.exe", 0, "/root/Storage/a.exe\n"), (None, 1, "")):
|
||||
with mock.patch.dict(LIVE["chooser_main"].__globals__, {"choose_file": mock.Mock(return_value=chosen)}), \
|
||||
for chooser, code, printed in ((mock.Mock(return_value="/root/Storage/a.exe "), 0, '"/root/Storage/a.exe "\n'),
|
||||
(mock.Mock(return_value=None), 1, ""),
|
||||
(mock.Mock(side_effect=ValueError("Namespace Gtk not available for version 3.0")), 2, ""),
|
||||
(mock.Mock(side_effect=ImportError("No module named 'gi'")), 2, "")):
|
||||
with mock.patch.dict(LIVE["chooser_main"].__globals__, {"choose_file": chooser}), \
|
||||
mock.patch.object(sys, "stdin", io.StringIO('{"strTitle": "Pick"}')), \
|
||||
mock.patch.object(sys, "stdout", io.StringIO()) as out:
|
||||
self.assertEqual(LIVE["chooser_main"](), code)
|
||||
|
||||
Reference in new issue
Block a user