Skip to content

Commit

Permalink
feat: install basic install feature
Browse files Browse the repository at this point in the history
  • Loading branch information
amoshydra committed Feb 15, 2024
1 parent 81fddd6 commit 67a7f04
Show file tree
Hide file tree
Showing 12 changed files with 400 additions and 28 deletions.
20 changes: 20 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@
</head>
<body>
<div id="root"></div>
<script>
const SETTINGS = {
pretokenise : true,
minify : false, // disabled by default due to https://github.com/espruino/BangleApps/pull/355#issuecomment-620124162
settime : false, // Always update time when we connect
favourites : ["launch"],
language : "",
bleCompat: false, // 20 byte MTU BLE Compatibility mode
sendUsageStats: true, // send usage stats to banglejs.com
alwaysAllowUpdate : false, // Always show "reinstall app" buttonregardless of the version
autoReload: false // Automatically reload watch after app App Loader actions (removes "Hold button" prompt)
};
</script>
<script src="https://banglejs.com/apps/core/js/utils.js"></script>
<script src="https://banglejs.com/apps/webtools/puck.js"></script>
<script src="https://banglejs.com/apps/webtools/heatshrink.js"></script>
<script src="https://banglejs.com/apps/core/lib/espruinotools.js"></script>
<script src="https://banglejs.com/apps/core/js/comms.js"></script>
<script src="https://banglejs.com/apps/core/js/appinfo.js"></script>
<script src="https://banglejs.com/apps/gadgetbridge.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^6.22.0",
"rehype-highlight": "^7.0.0",
"rehype-sanitize": "^6.0.0",
Expand Down
3 changes: 2 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "react-router-dom";
import App from './views/Apps';
import { SWRConfig } from 'swr';
import { GlobalProgressToaster } from './services/GlobalProgress';

const router = createHashRouter(
createRoutesFromElements(
Expand All @@ -32,11 +33,11 @@ const router = createHashRouter(
)
);


function Entry() {
return (
<SWRConfig value={{ provider: localStorageProvider }}>
<RouterProvider router={router} />
<GlobalProgressToaster />
</SWRConfig>
)
}
Expand Down
10 changes: 5 additions & 5 deletions src/components/AppListItemDetailView/AppDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { AppDetailViewProps } from "./interface";
import { Readme } from "./Readme";
import { AppStorageController } from "./AppStorageController";

export const AppDetailView = ({ app, className }: AppDetailViewProps) => {
export const AppDetailView = ({ app, apps, className }: AppDetailViewProps) => {
return (
<div
className={className}
Expand All @@ -15,11 +15,11 @@ export const AppDetailView = ({ app, className }: AppDetailViewProps) => {
flex-direction: column;
`}
>
<Heading app={app} />
<AppStorageController app={app} />
<Heading app={app} apps={apps} />
<AppStorageController app={app} apps={apps} />
<p>{app.description}</p>
<Screenshost app={app} />
<Readme app={app} />
<Screenshost app={app} apps={apps} />
<Readme app={app} apps={apps} />
<pre css={css`word-break: break-all; white-space: pre-wrap;`}>
{JSON.stringify(app, null, 2)}
</pre>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Modal } from "./Modal";
import { AppDetailView } from "./AppDetailView";

export interface AppListItemDetailViewProps {
data: AppItem | null;
apps: AppItem[];
app: AppItem | null;
isLoading: boolean;
error: Error | null;
}
Expand All @@ -24,13 +25,13 @@ export const AppListItemDetailView = (p: AppListItemDetailViewProps) => {
)
}

if (p.data === null) {
if (p.app === null) {
return (
<div>404 not found</div>
)
}

return <AppDetailView app={p.data} />
return <AppDetailView app={p.app} apps={p.apps} />
})();

const navigate = useNavigate()
Expand Down
125 changes: 107 additions & 18 deletions src/components/AppListItemDetailView/AppStorageController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { css } from "@emotion/react";
import { AppDetailViewProps } from "./interface";
import { UiButton } from "../Buttons/UiButton";
import { ButtonIconContainer } from "../Buttons/ButtonIconContainer";
import { faGear, faDownload } from "@fortawesome/free-solid-svg-icons";
import { faGear, faDownload, faTrash } from "@fortawesome/free-solid-svg-icons";
import { EspruinoComms } from "../../services/Espruino/Comms";
import { useApps } from "../../api/banglejs/methods";

Check failure on line 7 in src/components/AppListItemDetailView/AppStorageController.tsx

View workflow job for this annotation

GitHub Actions / deploy

'useApps' is declared but its value is never read.
import { useEffect, useState } from "react";

interface ControlButtonProps extends AppDetailViewProps {
hasConfiguration: boolean;
Expand All @@ -24,7 +27,51 @@ const InstallControlButton = (props: ControlButtonProps) => {
}

return (
<UiButton fullWidth>
<UiButton
fullWidth
onClick={async () => {
try {
const deviceInfo = await EspruinoComms.getDeviceInfo();
const device = {
...deviceInfo,
appsInstalled: deviceInfo.apps,
}

if (props.app.dependencies) {
Object.entries(props.app.dependencies)
.map(async ([dependencyAppId]) => {
const hasInstalled = device.apps.find(app => app.id === dependencyAppId);
if (hasInstalled) return;

const dependencyApp = props.apps.find(app => app.id === dependencyAppId);
if (!dependencyApp) {
const errorMessage = `dependency required "${dependencyAppId}" is not found`;
alert(errorMessage);
throw new Error(errorMessage)
}

await EspruinoComms.uploadApp(dependencyApp, { device });
// TODO: Implement dependency clash with the usage of provide_modules
// see AppInfo.checkDependencies
})
}

await EspruinoComms.uploadApp(props.app, { device });
if (props.app.type === "clock") {
const settings = await EspruinoComms.readFile("setting.json");
await EspruinoComms.writeFile("setting.json", JSON.stringify({
...JSON.parse(settings),
clock: `${props.app.id}.app.js`,
}))
EspruinoComms.resetDevice()
}

} catch (error) {
alert((error as Error).message);
throw error;
}
}}
>
<ButtonIconContainer
leftIcon={faDownload}
>
Expand All @@ -34,28 +81,69 @@ const InstallControlButton = (props: ControlButtonProps) => {
)
};
const ConfigureControlButton = (props: ControlButtonProps) => {
if (props.hasConfiguration) {
return (
<UiButton fullWidth>
<ButtonIconContainer
leftIcon={faGear}
>
Configure
</ButtonIconContainer>
</UiButton>
);
}

return null
};
if (props.hasConfiguration) {
return (
<UiButton fullWidth>
<ButtonIconContainer
leftIcon={faGear}
>
Configure
</ButtonIconContainer>
</UiButton>
);
}

return null
};

const UninstallControlButton = (props: ControlButtonProps) => {
if (props.hasInstalled) {
return (
<UiButton
fullWidth
onClick={async () => {
try {
await EspruinoComms.getDeviceInfo();
await EspruinoComms.removeApp(props.app)
} catch (error) {
alert((error as Error).message);
throw error;
}
}}
>
<ButtonIconContainer
leftIcon={faTrash}
>
Remove
</ButtonIconContainer>
</UiButton>
);
}

return null
};


export const AppStorageController = (props: AppDetailViewProps) => {
const [ hasInstalled, setHasInstalled ] = useState(false);
const [ hasUpdate, setHasUpdate ] = useState(false);
useEffect(() => {
if (EspruinoComms.isConnected()) {
EspruinoComms.getDeviceInfo()
.then(({ apps }) => {
const found = apps.find(app => app.id === props.app.id);

setHasInstalled(!!found);
setHasUpdate(!!(found && found.version === props.app.version));
})
}
}, [props.app]);

const controlButtonProps: ControlButtonProps = {
...props,
hasConfiguration: !!(props.app.custom ?? props.app.interface),
hasInstalled: false,
hasUpdate: false,
hasInstalled,
hasUpdate,
};
return (
<div
Expand All @@ -66,6 +154,7 @@ export const AppStorageController = (props: AppDetailViewProps) => {
`}
>
<ConfigureControlButton {...controlButtonProps} />
<UninstallControlButton {...controlButtonProps} />
<InstallControlButton {...controlButtonProps} />
</div>
)
Expand Down
1 change: 1 addition & 0 deletions src/components/AppListItemDetailView/interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AppItem } from "../../api/banglejs/interface";

export interface AppDetailViewProps {
apps: AppItem[];
app: AppItem;
className?: string;
}
13 changes: 13 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,16 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
<App />
</React.StrictMode>,
)

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const espruinoOriginalHttpGet = httpGet;
console.log(espruinoOriginalHttpGet);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.httpGet = (url: string) => {
console.log('fetching', url);
const updatedUrl = new URL(url, "https://banglejs.com/apps/");
console.log('fetching', url, updatedUrl);
return espruinoOriginalHttpGet(updatedUrl.href);
}
Loading

0 comments on commit 67a7f04

Please sign in to comment.