Skip to content

Commit 8ca014c

Browse files
committed
feat: preliminary OTA update support
1 parent ce882e0 commit 8ca014c

File tree

7 files changed

+1308
-525
lines changed

7 files changed

+1308
-525
lines changed

src/App.jsx

+23-5
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,26 @@ import BluetoothNetworkModal from "./components/common/modals/BluetoothNetworkMo
1212
import DeviceSwitcherModal from "./components/player/DeviceSwitcherModal";
1313
import NetworkPasswordModal from "./components/common/modals/NetworkPasswordModal";
1414
import ConnectorQRModal from "./components/common/modals/ConnectorQRModal";
15+
import SystemUpdateModal from "./components/common/modals/SystemUpdateModal";
1516
import ButtonMappingOverlay from "./components/common/overlays/ButtonMappingOverlay";
1617
import { useNetwork } from "./hooks/useNetwork";
1718
import { useGradientState } from "./hooks/useGradientState";
1819
import { PlaybackProgressContext } from "./hooks/usePlaybackProgress";
1920
import { DeviceSwitcherContext } from "./hooks/useSpotifyPlayerControls";
20-
import { useBluetooth } from "./hooks/useBluetooth";
21+
import { useBluetooth, useSystemUpdate } from "./hooks/useNocturned";
2122
import { useSpotifyData } from "./hooks/useSpotifyData";
2223
import { SettingsProvider } from "./contexts/SettingsContext";
2324
import { ConnectorProvider } from "./contexts/ConnectorContext";
2425
import React from "react";
2526

2627
export const NetworkContext = React.createContext({
2728
selectedNetwork: null,
28-
setSelectedNetwork: () => {},
29+
setSelectedNetwork: () => { },
2930
});
3031

3132
export const ConnectorContext = React.createContext({
3233
showConnectorModal: false,
33-
setShowConnectorModal: () => {},
34+
setShowConnectorModal: () => { },
3435
});
3536

3637
function useGlobalButtonMapping({
@@ -281,6 +282,14 @@ function App() {
281282
enableNetworking,
282283
} = useBluetooth();
283284

285+
const {
286+
updateStatus,
287+
progress,
288+
isUpdating,
289+
isError,
290+
errorMessage
291+
} = useSystemUpdate();
292+
284293
const {
285294
currentColor1,
286295
currentColor2,
@@ -453,6 +462,8 @@ function App() {
453462
}
454463
};
455464

465+
const isFlashing = isUpdating && updateStatus.stage === 'flash';
466+
456467
let content;
457468
if (authIsLoading) {
458469
content = null;
@@ -538,19 +549,26 @@ function App() {
538549

539550
<div className="relative z-10">
540551
{content}
541-
{!isConnected && showNoNetwork && <NetworkScreen />}
552+
{!isConnected && showNoNetwork && !isFlashing && <NetworkScreen />}
542553
<BluetoothPairingModal
543554
pairingRequest={pairingRequest}
544555
isConnecting={isConnecting}
545556
onAccept={acceptPairing}
546557
onDeny={denyPairing}
547558
/>
548559
<BluetoothNetworkModal
549-
show={showNetworkPrompt && !isConnected}
560+
show={showNetworkPrompt && !isConnected && !isFlashing}
550561
deviceName={lastConnectedDevice?.name}
551562
onCancel={handleNetworkCancel}
552563
isConnecting={isConnecting}
553564
/>
565+
<SystemUpdateModal
566+
show={isFlashing}
567+
status={updateStatus}
568+
progress={progress}
569+
isError={isError}
570+
errorMessage={errorMessage}
571+
/>
554572
<DeviceSwitcherModal
555573
isOpen={isDeviceSwitcherOpen}
556574
onClose={handleCloseDeviceSwitcher}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
3+
export default function SystemUpdateModal({
4+
show,
5+
status,
6+
progress,
7+
isError,
8+
errorMessage
9+
}) {
10+
if (!show) return null;
11+
12+
return (
13+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
14+
<div className="bg-[#1A1A1A] rounded-2xl p-8 w-[500px] shadow-lg">
15+
<h2 className="text-3xl font-semibold text-white mb-4">
16+
{isError ? "Update Failed" : "System Update in Progress"}
17+
</h2>
18+
19+
{isError ? (
20+
<div className="space-y-6">
21+
<p className="text-xl text-red-400">
22+
{errorMessage || "An unknown error occurred while updating your system."}
23+
</p>
24+
<p className="text-lg text-white/80">
25+
Please try again later or ask in our Discord if the problem persists.
26+
</p>
27+
</div>
28+
) : (
29+
<div className="space-y-6">
30+
<p className="text-xl text-white/80 mb-4">
31+
{status.stage === 'flash'
32+
? "Installing system update. Please do not remove power from your device."
33+
: "Preparing update files. This may take a few minutes."}
34+
</p>
35+
36+
<div className="space-y-2">
37+
<div className="w-full bg-white/10 rounded-full h-4">
38+
<div
39+
className="bg-white h-4 rounded-full transition-all"
40+
style={{ width: `${progress.percent}%` }}
41+
></div>
42+
</div>
43+
44+
<div className="flex justify-between text-lg text-white/80">
45+
<span>{Math.round(progress.percent)}%</span>
46+
<span>
47+
{Math.round(progress.bytesComplete / 1024 / 1024)} MB / {Math.round(progress.bytesTotal / 1024 / 1024)} MB
48+
</span>
49+
<span>{progress.speed} MB/s</span>
50+
</div>
51+
</div>
52+
53+
{status.stage === 'flash' && (
54+
<p className="text-amber-400 text-lg">
55+
Your system will automatically restart when the update is complete.
56+
</p>
57+
)}
58+
</div>
59+
)}
60+
</div>
61+
</div>
62+
);
63+
}

0 commit comments

Comments
 (0)