feat: initial project scaffold — server, client, Android APK

- FastAPI server with audio mixer (Windows + Voicemeeter), media tracking,
  notifications (progress + alerts), telemetry, and system tray .exe build
- Test suite covering notifications, audio mixer, media, telemetry, and API
- E-Ink web client (vanilla JS, DOM API, block meters, swipe gestures)
- Android WebView APK for BOOX Go 7 Color Gen II (Android 13, Kotlin)
- Design decision records in .pi/docs/design/
- PyInstaller build script for server .exe
This commit is contained in:
Imrayya
2026-07-01 11:19:32 +00:00
commit 0b4f739d12
36 changed files with 3916 additions and 0 deletions
+349
View File
@@ -0,0 +1,349 @@
/* PaperDash — E-Ink optimized styles */
/* High contrast, no smooth transitions, block-based UI */
:root {
--bg: #000000;
--fg: #ffffff;
--border: #ffffff;
--dim: #888888;
--panel-bg: #111111;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
background: var(--bg);
color: var(--fg);
font-family: "Courier New", monospace;
font-size: 16px;
overflow-x: hidden;
-webkit-user-select: none;
user-select: none;
}
#app {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
/* Screens */
.screen {
display: none;
flex-direction: column;
height: 100%;
padding: 16px;
}
.screen.active {
display: flex;
}
/* Login */
#login-screen {
justify-content: center;
align-items: center;
text-align: center;
gap: 16px;
}
#login-screen h1 {
font-size: 2em;
border-bottom: 2px solid var(--border);
padding-bottom: 8px;
}
#pin-input {
background: var(--bg);
color: var(--fg);
border: 2px solid var(--border);
padding: 12px 24px;
font-size: 1.5em;
text-align: center;
letter-spacing: 8px;
width: 200px;
font-family: inherit;
}
#connect-btn {
background: var(--bg);
color: var(--fg);
border: 2px solid var(--border);
padding: 10px 32px;
font-size: 1.1em;
cursor: pointer;
font-family: inherit;
}
.error {
color: var(--dim);
font-size: 0.9em;
}
/* Panels */
.panel {
border: 2px solid var(--border);
padding: 12px;
margin-bottom: 12px;
flex-shrink: 0;
}
.panel h2 {
font-size: 1em;
border-bottom: 1px solid var(--dim);
padding-bottom: 4px;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 2px;
}
/* Media */
#artwork-container {
width: 100%;
max-height: 120px;
overflow: hidden;
margin-bottom: 8px;
border: 1px solid var(--dim);
}
#artwork-container img {
width: 100%;
height: 100%;
object-fit: contain;
}
.track-title {
font-size: 1.2em;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.track-artist,
.track-album {
color: var(--dim);
font-size: 0.9em;
}
/* Progress bar — block stepped for E-Ink */
#progress-container {
margin: 8px 0;
}
#progress-bar {
width: 100%;
height: 20px;
border: 2px solid var(--border);
background: var(--bg);
overflow: hidden;
}
#progress-fill {
height: 100%;
background: var(--fg);
width: 0%;
}
#progress-text {
display: flex;
justify-content: space-between;
font-size: 0.8em;
color: var(--dim);
margin-top: 2px;
}
/* Media controls */
#media-controls {
display: flex;
gap: 8px;
justify-content: center;
margin-top: 8px;
}
.control-btn {
background: var(--bg);
color: var(--fg);
border: 2px solid var(--border);
width: 50px;
height: 50px;
font-size: 1.3em;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-family: inherit;
}
/* Audio mixer */
#master-volume {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
flex-wrap: wrap;
}
#master-label {
font-weight: bold;
min-width: 60px;
}
.volume-controls {
display: flex;
align-items: center;
gap: 4px;
flex: 1;
}
.volume-btn {
background: var(--bg);
color: var(--fg);
border: 2px solid var(--border);
width: 40px;
height: 40px;
font-size: 1.2em;
cursor: pointer;
font-family: inherit;
}
#master-volume-value {
min-width: 45px;
text-align: center;
}
.mute-btn {
background: var(--bg);
color: var(--fg);
border: 2px solid var(--border);
padding: 6px 12px;
font-size: 0.8em;
cursor: pointer;
font-family: inherit;
text-transform: uppercase;
}
.mute-btn.muted {
background: var(--fg);
color: var(--bg);
}
/* Channels */
.channel {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 0;
border-top: 1px solid var(--dim);
}
.channel-name {
min-width: 30px;
font-weight: bold;
}
.channel-meter {
flex: 1;
height: 16px;
border: 1px solid var(--dim);
overflow: hidden;
font-family: monospace;
font-size: 14px;
line-height: 16px;
}
.channel-meter-fill {
height: 100%;
background: var(--fg);
}
.channel-volume {
min-width: 35px;
text-align: right;
font-size: 0.85em;
}
/* Telemetry */
#telemetry-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.telemetry-item {
display: flex;
justify-content: space-between;
padding: 4px 8px;
border: 1px solid var(--dim);
}
.telemetry-label {
color: var(--dim);
text-transform: uppercase;
font-size: 0.85em;
}
.telemetry-value {
font-weight: bold;
}
/* Notifications */
.notification {
border: 2px solid var(--border);
padding: 8px;
margin-bottom: 6px;
}
.notification.alert {
border-color: var(--dim);
}
.notification.alert.warning {
border-style: double;
}
.notification.alert.error {
border-width: 3px;
}
.notification-title {
font-weight: bold;
margin-bottom: 4px;
}
.notification-message {
font-size: 0.9em;
color: var(--dim);
}
.notification-progress {
margin-top: 6px;
font-family: monospace;
font-size: 14px;
}
.notification-eta {
font-size: 0.8em;
color: var(--dim);
margin-top: 2px;
}
/* Scrollable dashboard */
#dashboard-screen {
overflow-y: auto;
overflow-x: hidden;
}
/* E-Ink specific: no transitions, sharp edges */
* {
transition: none !important;
-webkit-transition: none !important;
}