mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 07:41:58 +00:00
Better install process UX, fix reinstalling
This commit is contained in:
+7
-1
@@ -10,6 +10,7 @@ from asyncio import get_event_loop
|
|||||||
from time import time
|
from time import time
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
|
from injector import inject_to_tab
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
@@ -23,9 +24,10 @@ class PluginInstallContext:
|
|||||||
self.hash = hash
|
self.hash = hash
|
||||||
|
|
||||||
class PluginBrowser:
|
class PluginBrowser:
|
||||||
def __init__(self, plugin_path, server_instance) -> None:
|
def __init__(self, plugin_path, server_instance, plugins) -> None:
|
||||||
self.log = getLogger("browser")
|
self.log = getLogger("browser")
|
||||||
self.plugin_path = plugin_path
|
self.plugin_path = plugin_path
|
||||||
|
self.plugins = plugins
|
||||||
self.install_requests = {}
|
self.install_requests = {}
|
||||||
|
|
||||||
server_instance.add_routes([
|
server_instance.add_routes([
|
||||||
@@ -64,6 +66,9 @@ class PluginBrowser:
|
|||||||
self.log.info("uninstalling " + name)
|
self.log.info("uninstalling " + name)
|
||||||
self.log.info(" at dir " + self.find_plugin_folder(name))
|
self.log.info(" at dir " + self.find_plugin_folder(name))
|
||||||
await tab.evaluate_js(f"DeckyPluginLoader.unloadPlugin('{name}')")
|
await tab.evaluate_js(f"DeckyPluginLoader.unloadPlugin('{name}')")
|
||||||
|
if self.plugins[name]:
|
||||||
|
self.plugins[name].stop()
|
||||||
|
self.plugins.pop(name, None)
|
||||||
rmtree(self.find_plugin_folder(name))
|
rmtree(self.find_plugin_folder(name))
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.log.warning(f"Plugin {name} not installed, skipping uninstallation")
|
self.log.warning(f"Plugin {name} not installed, skipping uninstallation")
|
||||||
@@ -95,6 +100,7 @@ class PluginBrowser:
|
|||||||
)
|
)
|
||||||
if ret:
|
if ret:
|
||||||
self.log.info(f"Installed {name} (Version: {version})")
|
self.log.info(f"Installed {name} (Version: {version})")
|
||||||
|
await inject_to_tab("SP", "window.syncDeckyPlugins()")
|
||||||
else:
|
else:
|
||||||
self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})")
|
self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})")
|
||||||
else:
|
else:
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ class PluginManager:
|
|||||||
allow_headers="*")
|
allow_headers="*")
|
||||||
})
|
})
|
||||||
self.plugin_loader = Loader(self.web_app, CONFIG["plugin_path"], self.loop, CONFIG["live_reload"])
|
self.plugin_loader = Loader(self.web_app, CONFIG["plugin_path"], self.loop, CONFIG["live_reload"])
|
||||||
self.plugin_browser = PluginBrowser(CONFIG["plugin_path"], self.web_app)
|
self.plugin_browser = PluginBrowser(CONFIG["plugin_path"], self.web_app, self.plugin_loader.plugins)
|
||||||
self.utilities = Utilities(self)
|
self.utilities = Utilities(self)
|
||||||
self.updater = Updater(self)
|
self.updater = Updater(self)
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"decky-frontend-lib": "^1.2.1",
|
"decky-frontend-lib": "^1.2.4",
|
||||||
"react-icons": "^4.4.0"
|
"react-icons": "^4.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+4
-4
@@ -9,7 +9,7 @@ specifiers:
|
|||||||
'@types/react': 16.14.0
|
'@types/react': 16.14.0
|
||||||
'@types/react-router': 5.1.18
|
'@types/react-router': 5.1.18
|
||||||
'@types/webpack': ^5.28.0
|
'@types/webpack': ^5.28.0
|
||||||
decky-frontend-lib: ^1.2.1
|
decky-frontend-lib: ^1.2.4
|
||||||
husky: ^8.0.1
|
husky: ^8.0.1
|
||||||
import-sort-style-module: ^6.0.0
|
import-sort-style-module: ^6.0.0
|
||||||
inquirer: ^8.2.4
|
inquirer: ^8.2.4
|
||||||
@@ -23,7 +23,7 @@ specifiers:
|
|||||||
typescript: ^4.7.4
|
typescript: ^4.7.4
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
decky-frontend-lib: 1.2.1
|
decky-frontend-lib: 1.2.4
|
||||||
react-icons: 4.4.0_react@16.14.0
|
react-icons: 4.4.0_react@16.14.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -806,8 +806,8 @@ packages:
|
|||||||
ms: 2.1.2
|
ms: 2.1.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/decky-frontend-lib/1.2.1:
|
/decky-frontend-lib/1.2.4:
|
||||||
resolution: {integrity: sha512-aJmjOSMwQN9LTquYaMhSqW+FhmKLRgLb75JkcGRWKuIe8rjDfwwbAB/ckJseIC8UMzPKhspvcznfxyp+c72B5Q==}
|
resolution: {integrity: sha512-r3mLEey9KUkF68geJVSjNlOz/Fg4vpMKUzoutSceyd8o/J5l+QR+Vf0b3gwK3UN9Sp4Pj4XQ1eB82+/W0ApsFg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/deepmerge/4.2.2:
|
/deepmerge/4.2.2:
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { ModalRoot, QuickAccessTab, Router, Spinner, sleep, staticClasses } from 'decky-frontend-lib';
|
||||||
|
import { FC, useState } from 'react';
|
||||||
|
|
||||||
|
interface PluginInstallModalProps {
|
||||||
|
artifact: string;
|
||||||
|
version: string;
|
||||||
|
hash: string;
|
||||||
|
// reinstall: boolean;
|
||||||
|
onOK(): void;
|
||||||
|
onCancel(): void;
|
||||||
|
closeModal?(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PluginInstallModal: FC<PluginInstallModalProps> = ({ artifact, version, hash, onOK, onCancel, closeModal }) => {
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
return (
|
||||||
|
<ModalRoot
|
||||||
|
bOKDisabled={loading}
|
||||||
|
closeModal={closeModal}
|
||||||
|
onOK={async () => {
|
||||||
|
setLoading(true);
|
||||||
|
await onOK();
|
||||||
|
Router.NavigateBackOrOpenMenu();
|
||||||
|
await sleep(250);
|
||||||
|
setTimeout(() => Router.OpenQuickAccessMenu(QuickAccessTab.Decky), 1000);
|
||||||
|
}}
|
||||||
|
onCancel={async () => {
|
||||||
|
await onCancel();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={staticClasses.Title} style={{ flexDirection: 'column' }}>
|
||||||
|
{hash == 'False' ? <h3 style={{ color: 'red' }}>!!!!NO HASH PROVIDED!!!!</h3> : null}
|
||||||
|
<div style={{ flexDirection: 'row' }}>
|
||||||
|
{loading && <Spinner style={{ width: '20px' }} />} {loading ? 'Installing' : 'Install'} {artifact}
|
||||||
|
{version ? ' version ' + version : null}?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalRoot>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PluginInstallModal;
|
||||||
@@ -21,7 +21,7 @@ window.importDeckyPlugin = function (name: string) {
|
|||||||
window.syncDeckyPlugins = async function () {
|
window.syncDeckyPlugins = async function () {
|
||||||
const plugins = await (await fetch('http://127.0.0.1:1337/plugins')).json();
|
const plugins = await (await fetch('http://127.0.0.1:1337/plugins')).json();
|
||||||
for (const plugin of plugins) {
|
for (const plugin of plugins) {
|
||||||
window.DeckyPluginLoader?.importPlugin(plugin);
|
if (!window.DeckyPluginLoader.hasPlugin(plugin)) window.DeckyPluginLoader?.importPlugin(plugin);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { ModalRoot, QuickAccessTab, Router, showModal, sleep, staticClasses } from 'decky-frontend-lib';
|
import { ModalRoot, QuickAccessTab, showModal, staticClasses } from 'decky-frontend-lib';
|
||||||
import { FaPlug } from 'react-icons/fa';
|
import { FaPlug } from 'react-icons/fa';
|
||||||
|
|
||||||
import { DeckyState, DeckyStateContextProvider } from './components/DeckyState';
|
import { DeckyState, DeckyStateContextProvider } from './components/DeckyState';
|
||||||
import LegacyPlugin from './components/LegacyPlugin';
|
import LegacyPlugin from './components/LegacyPlugin';
|
||||||
|
import PluginInstallModal from './components/modals/PluginInstallModal';
|
||||||
import PluginView from './components/PluginView';
|
import PluginView from './components/PluginView';
|
||||||
import SettingsPage from './components/settings';
|
import SettingsPage from './components/settings';
|
||||||
import StorePage from './components/store/Store';
|
import StorePage from './components/store/Store';
|
||||||
@@ -55,23 +56,13 @@ class PluginLoader extends Logger {
|
|||||||
|
|
||||||
public addPluginInstallPrompt(artifact: string, version: string, request_id: string, hash: string) {
|
public addPluginInstallPrompt(artifact: string, version: string, request_id: string, hash: string) {
|
||||||
showModal(
|
showModal(
|
||||||
<ModalRoot
|
<PluginInstallModal
|
||||||
onOK={async () => {
|
artifact={artifact}
|
||||||
await this.callServerMethod('confirm_plugin_install', { request_id });
|
version={version}
|
||||||
Router.NavigateBackOrOpenMenu();
|
hash={hash}
|
||||||
await sleep(250);
|
onOK={() => this.callServerMethod('confirm_plugin_install', { request_id })}
|
||||||
setTimeout(() => Router.OpenQuickAccessMenu(QuickAccessTab.Decky), 1000);
|
onCancel={() => this.callServerMethod('cancel_plugin_install', { request_id })}
|
||||||
}}
|
/>,
|
||||||
onCancel={() => {
|
|
||||||
this.callServerMethod('cancel_plugin_install', { request_id });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className={staticClasses.Title} style={{ flexDirection: 'column' }}>
|
|
||||||
{hash == 'False' ? <h3 style={{ color: 'red' }}>!!!!NO HASH PROVIDED!!!!</h3> : null}
|
|
||||||
Install {artifact}
|
|
||||||
{version ? ' version ' + version : null}?
|
|
||||||
</div>
|
|
||||||
</ModalRoot>,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +88,10 @@ class PluginLoader extends Logger {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasPlugin(name: string) {
|
||||||
|
return Boolean(this.plugins.find((plugin) => plugin.name == name));
|
||||||
|
}
|
||||||
|
|
||||||
public dismountAll() {
|
public dismountAll() {
|
||||||
for (const plugin of this.plugins) {
|
for (const plugin of this.plugins) {
|
||||||
this.log(`Dismounting ${plugin.name}`);
|
this.log(`Dismounting ${plugin.name}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user