From 9619c52720c97ef74842b15aa732dd0a8d6fb26a Mon Sep 17 00:00:00 2001 From: AAGaming Date: Wed, 22 Jun 2022 23:22:27 -0400 Subject: add settings page with install from URL option --- frontend/src/components/PluginView.tsx | 26 ++--------- frontend/src/components/TitleView.tsx | 53 +++++++++++++++++++--- frontend/src/components/settings/index.tsx | 19 ++++++++ .../components/settings/pages/GeneralSettings.tsx | 30 ++++++++++++ frontend/src/components/store/PluginCard.tsx | 23 ++++------ frontend/src/components/store/Store.tsx | 20 ++++++++ frontend/src/plugin-loader.tsx | 24 +++++----- frontend/src/tabs-hook.ts | 4 +- 8 files changed, 141 insertions(+), 58 deletions(-) create mode 100644 frontend/src/components/settings/index.tsx create mode 100644 frontend/src/components/settings/pages/GeneralSettings.tsx (limited to 'frontend/src') diff --git a/frontend/src/components/PluginView.tsx b/frontend/src/components/PluginView.tsx index 92650fec..953abd25 100644 --- a/frontend/src/components/PluginView.tsx +++ b/frontend/src/components/PluginView.tsx @@ -1,37 +1,17 @@ -import { ButtonItem, DialogButton, PanelSection, PanelSectionRow, Router } from 'decky-frontend-lib'; +import { ButtonItem, PanelSection, PanelSectionRow } from 'decky-frontend-lib'; import { VFC } from 'react'; -import { FaArrowLeft, FaStore } from 'react-icons/fa'; import { useDeckyState } from './DeckyState'; const PluginView: VFC = () => { - const { plugins, activePlugin, setActivePlugin, closeActivePlugin } = useDeckyState(); - - const onStoreClick = () => { - Router.CloseSideMenus(); - Router.Navigate('/decky/store'); - }; + const { plugins, activePlugin, setActivePlugin } = useDeckyState(); if (activePlugin) { - return ( -
-
- - - -
- {activePlugin.content} -
- ); + return
{activePlugin.content}
; } return ( -
- - - -
{plugins.map(({ name, icon }) => ( setActivePlugin(name)}> diff --git a/frontend/src/components/TitleView.tsx b/frontend/src/components/TitleView.tsx index 4b4a6825..babcd316 100644 --- a/frontend/src/components/TitleView.tsx +++ b/frontend/src/components/TitleView.tsx @@ -1,18 +1,59 @@ -import { staticClasses } from 'decky-frontend-lib'; -import { VFC } from 'react'; +import { DialogButton, Focusable, Router, staticClasses } from 'decky-frontend-lib'; +import { CSSProperties, VFC } from 'react'; +import { FaArrowLeft, FaCog, FaStore } from 'react-icons/fa'; import { useDeckyState } from './DeckyState'; +const titleStyles: CSSProperties = { + display: 'flex', + paddingTop: '3px', + paddingBottom: '14px', + paddingRight: '16px', + boxShadow: 'unset', +}; + const TitleView: VFC = () => { - const { activePlugin } = useDeckyState(); + const { activePlugin, closeActivePlugin } = useDeckyState(); + + const onSettingsClick = () => { + Router.CloseSideMenus(); + Router.Navigate('/decky/settings'); + }; + + const onStoreClick = () => { + Router.CloseSideMenus(); + Router.Navigate('/decky/store'); + }; if (activePlugin === null) { - return
Decky
; + return ( + + + + +
Decky
+ + + +
+ ); } return ( -
- {activePlugin.name} +
+ + + +
{activePlugin.name}
); }; diff --git a/frontend/src/components/settings/index.tsx b/frontend/src/components/settings/index.tsx new file mode 100644 index 00000000..d4799fa9 --- /dev/null +++ b/frontend/src/components/settings/index.tsx @@ -0,0 +1,19 @@ +import { SidebarNavigation } from 'decky-frontend-lib'; + +import GeneralSettings from './pages/GeneralSettings'; + +export default function SettingsPage() { + return ( + , + route: '/decky/settings/general', + }, + ]} + /> + ); +} diff --git a/frontend/src/components/settings/pages/GeneralSettings.tsx b/frontend/src/components/settings/pages/GeneralSettings.tsx new file mode 100644 index 00000000..1cc8076d --- /dev/null +++ b/frontend/src/components/settings/pages/GeneralSettings.tsx @@ -0,0 +1,30 @@ +import { DialogButton, Field, TextField } from 'decky-frontend-lib'; +import { useState } from 'react'; +import { FaShapes } from 'react-icons/fa'; + +import { installFromURL } from '../../store/Store'; + +export default function GeneralSettings() { + const [pluginURL, setPluginURL] = useState(''); + // const [checked, setChecked] = useState(false); // store these in some kind of State instead + return ( +
+ {/* } + > + setChecked(e)} + /> + */} + setPluginURL(e?.target.value)} />} + icon={} + > + installFromURL(pluginURL)}>Install + +
+ ); +} diff --git a/frontend/src/components/store/PluginCard.tsx b/frontend/src/components/store/PluginCard.tsx index 7816d1bb..28989a88 100644 --- a/frontend/src/components/store/PluginCard.tsx +++ b/frontend/src/components/store/PluginCard.tsx @@ -2,6 +2,7 @@ import { DialogButton, Dropdown, Focusable, + QuickAccessTab, Router, SingleDropdownOption, SuspensefulImage, @@ -9,7 +10,7 @@ import { } from 'decky-frontend-lib'; import { FC, useRef, useState } from 'react'; -import { StorePlugin } from './Store'; +import { StorePlugin, requestPluginInstall } from './Store'; interface PluginCardProps { plugin: StorePlugin; @@ -19,17 +20,6 @@ const classNames = (...classes: string[]) => { return classes.join(' '); }; -async function requestPluginInstall(plugin: StorePlugin, selectedVer: string) { - const formData = new FormData(); - formData.append('artifact', plugin.artifact); - formData.append('version', selectedVer); - formData.append('hash', plugin.versions[selectedVer]); - await fetch('http://localhost:1337/browser/install_plugin', { - method: 'POST', - body: formData, - }); -} - const PluginCard: FC = ({ plugin }) => { const [selectedOption, setSelectedOption] = useState(0); const buttonRef = useRef(null); @@ -50,9 +40,12 @@ const PluginCard: FC = ({ plugin }) => { buttonRef.current!.focus(); }} onCancel={(e: CustomEvent) => { - containerRef.current!.querySelectorAll('* :focus').length === 0 - ? Router.NavigateBackOrOpenMenu() - : containerRef.current!.focus(); + if (containerRef.current!.querySelectorAll('* :focus').length === 0) { + Router.NavigateBackOrOpenMenu(); + setTimeout(() => Router.OpenQuickAccessMenu(QuickAccessTab.Decky), 1000); + } else { + containerRef.current!.focus(); + } }} style={{ display: 'flex', diff --git a/frontend/src/components/store/Store.tsx b/frontend/src/components/store/Store.tsx index ebb2bb8e..0e99a3c2 100644 --- a/frontend/src/components/store/Store.tsx +++ b/frontend/src/components/store/Store.tsx @@ -13,6 +13,26 @@ export interface StorePlugin { tags: string[]; } +export async function installFromURL(url: string) { + const formData = new FormData(); + formData.append('artifact', url); + await fetch('http://localhost:1337/browser/install_plugin', { + method: 'POST', + body: formData, + }); +} + +export async function requestPluginInstall(plugin: StorePlugin, selectedVer: string) { + const formData = new FormData(); + formData.append('artifact', `https://github.com/${plugin.artifact}/archive/refs/tags/${selectedVer}.zip`); + formData.append('version', selectedVer); + formData.append('hash', plugin.versions[selectedVer]); + await fetch('http://localhost:1337/browser/install_plugin', { + method: 'POST', + body: formData, + }); +} + const StorePage: FC<{}> = () => { const [data, setData] = useState(null); diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx index 9b1020c7..cad59c2f 100644 --- a/frontend/src/plugin-loader.tsx +++ b/frontend/src/plugin-loader.tsx @@ -1,9 +1,10 @@ -import { ModalRoot, showModal, staticClasses } from 'decky-frontend-lib'; +import { ModalRoot, QuickAccessTab, showModal, staticClasses } from 'decky-frontend-lib'; import { FaPlug } from 'react-icons/fa'; import { DeckyState, DeckyStateContextProvider } from './components/DeckyState'; import LegacyPlugin from './components/LegacyPlugin'; import PluginView from './components/PluginView'; +import SettingsPage from './components/settings'; import StorePage from './components/store/Store'; import TitleView from './components/TitleView'; import Logger from './logger'; @@ -31,14 +32,11 @@ class PluginLoader extends Logger { this.log('Initialized'); this.tabsHook.add({ - id: 'main', - title: ( - - - - ), + id: QuickAccessTab.Decky, + title: null, content: ( + ), @@ -46,22 +44,23 @@ class PluginLoader extends Logger { }); this.routerHook.addRoute('/decky/store', () => ); + this.routerHook.addRoute('/decky/settings', () => ); } - public addPluginInstallPrompt(artifact: string, version: string, request_id: string) { + public addPluginInstallPrompt(artifact: string, version: string, request_id: string, hash: string) { showModal( { - console.log('ok'); this.callServerMethod('confirm_plugin_install', { request_id }); }} onCancel={() => { - console.log('nope'); this.callServerMethod('cancel_plugin_install', { request_id }); }} > -
- Install {artifact} version {version}? +
+ {hash == 'False' ?

!!!!NO HASH PROVIDED!!!!

: null} + Install {artifact} + {version ? ' version ' + version : null}?
, ); @@ -76,6 +75,7 @@ class PluginLoader extends Logger { public deinit() { this.routerHook.removeRoute('/decky/store'); + this.routerHook.removeRoute('/decky/settings'); } public async importPlugin(name: string) { diff --git a/frontend/src/tabs-hook.ts b/frontend/src/tabs-hook.ts index de03310e..b364712d 100644 --- a/frontend/src/tabs-hook.ts +++ b/frontend/src/tabs-hook.ts @@ -1,4 +1,4 @@ -import { afterPatch, sleep, unpatch } from 'decky-frontend-lib'; +import { QuickAccessTab, afterPatch, sleep, unpatch } from 'decky-frontend-lib'; import { memo } from 'react'; import Logger from './logger'; @@ -18,7 +18,7 @@ const isTabsArray = (tabs: any) => { }; interface Tab { - id: string; + id: QuickAccessTab | number; title: any; content: any; icon: any; -- cgit v1.2.3