extra material and simulink creation script
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -60,10 +60,5 @@ scripts/*.pyc
|
|||||||
scripts/*.pyo
|
scripts/*.pyo
|
||||||
|
|
||||||
# extra resources
|
# extra resources
|
||||||
extra/fonts/*.ttf
|
extra/fonts/
|
||||||
extra/fonts/*.otf
|
extra/images/
|
||||||
extra/images/*.png
|
|
||||||
extra/images/*.jpg
|
|
||||||
extra/images/*.jpeg
|
|
||||||
extra/images/*.gif
|
|
||||||
extra/images/*.svg
|
|
||||||
2
pi/ui/assets/images/.gitignore
vendored
Normal file
2
pi/ui/assets/images/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Generated/symlinked images - created by prepare_assets.sh
|
||||||
|
rei_default.png
|
||||||
3
pi/ui/fonts/.gitignore
vendored
Normal file
3
pi/ui/fonts/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Generated/symlinked font files - created by prepare_assets.sh
|
||||||
|
din1451alt.ttf
|
||||||
|
NotoSans-*.ttf
|
||||||
@@ -20,6 +20,8 @@ class SmartSerowApp extends StatelessWidget {
|
|||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
),
|
),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
|
fontFamily: 'DIN1451',
|
||||||
|
fontFamilyFallback: const ['NotoSans', 'Roboto'],
|
||||||
),
|
),
|
||||||
home: const AppRoot(),
|
home: const AppRoot(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -52,65 +52,90 @@ class _DashboardScreenState extends State<DashboardScreen> {
|
|||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
child: Column(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
// Header
|
// Left side: All dashboard widgets (flex: 2)
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'SMART SEROW',
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
color: Colors.teal,
|
|
||||||
letterSpacing: 2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'${_voltage.toStringAsFixed(1)}V',
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
color: _voltage < 12.0 ? Colors.red : Colors.green,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: 48),
|
|
||||||
|
|
||||||
// Main Pi temperature display
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(
|
flex: 2,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
// Header
|
||||||
_piTemp != null ? _piTemp!.toStringAsFixed(1) : '—',
|
Row(
|
||||||
style: const TextStyle(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
fontSize: 180,
|
children: [
|
||||||
fontWeight: FontWeight.w200,
|
Text(
|
||||||
color: Colors.white,
|
'SMART SEROW',
|
||||||
height: 1,
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
color: Colors.teal,
|
||||||
|
letterSpacing: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${_voltage.toStringAsFixed(1)}V',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
color: _voltage < 12.0 ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 48),
|
||||||
|
|
||||||
|
// Main Pi temperature display
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
_piTemp != null ? _piTemp!.toStringAsFixed(1) : '—',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 180,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
color: Colors.white,
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Pi Temp',
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
'Pi Temp',
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
// Bottom stats row
|
||||||
color: Colors.grey,
|
Row(
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
),
|
children: [
|
||||||
],
|
StatBox(label: 'RPM', value: _rpm.toString()),
|
||||||
),
|
StatBox(label: 'ENG', value: '$_temp°C'),
|
||||||
|
StatBox(label: 'GEAR', value: '—'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Bottom stats row
|
const SizedBox(width: 32),
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
// Right side: Image display (flex: 1)
|
||||||
children: [
|
Expanded(
|
||||||
StatBox(label: 'RPM', value: _rpm.toString()),
|
flex: 1,
|
||||||
StatBox(label: 'ENG', value: '$_temp°C'),
|
child: Center(
|
||||||
StatBox(label: 'GEAR', value: '—'),
|
child: Image.asset(
|
||||||
],
|
'assets/images/rei_default.png',
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
// Graceful fallback - empty box if image missing
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -17,3 +17,18 @@ dev_dependencies:
|
|||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
|
assets:
|
||||||
|
- assets/images/
|
||||||
|
|
||||||
|
fonts:
|
||||||
|
- family: DIN1451
|
||||||
|
fonts:
|
||||||
|
- asset: fonts/din1451alt.ttf
|
||||||
|
- family: NotoSans
|
||||||
|
fonts:
|
||||||
|
- asset: fonts/NotoSans-Regular.ttf
|
||||||
|
- asset: fonts/NotoSans-Bold.ttf
|
||||||
|
weight: 700
|
||||||
|
- asset: fonts/NotoSans-Light.ttf
|
||||||
|
weight: 300
|
||||||
|
|||||||
@@ -71,6 +71,14 @@ def build(clean: bool = False) -> bool:
|
|||||||
|
|
||||||
os.chdir(UI_DIR)
|
os.chdir(UI_DIR)
|
||||||
|
|
||||||
|
# Prepare assets (fonts, images)
|
||||||
|
prepare_script = SCRIPT_DIR / "prepare_assets.sh"
|
||||||
|
if prepare_script.exists():
|
||||||
|
print("Preparing assets...")
|
||||||
|
run(["bash", str(prepare_script)])
|
||||||
|
else:
|
||||||
|
print(f"WARNING: {prepare_script} not found")
|
||||||
|
|
||||||
# Initialize elinux project if needed
|
# Initialize elinux project if needed
|
||||||
elinux_dir = UI_DIR / "elinux"
|
elinux_dir = UI_DIR / "elinux"
|
||||||
if not elinux_dir.exists():
|
if not elinux_dir.exists():
|
||||||
|
|||||||
@@ -36,6 +36,15 @@ echo "Cross-compiler: $CXX"
|
|||||||
|
|
||||||
cd "$UI_DIR"
|
cd "$UI_DIR"
|
||||||
|
|
||||||
|
# Prepare assets (fonts, images)
|
||||||
|
PREPARE_SCRIPT="$SCRIPT_DIR/prepare_assets.sh"
|
||||||
|
if [ -x "$PREPARE_SCRIPT" ]; then
|
||||||
|
echo "Preparing assets..."
|
||||||
|
"$PREPARE_SCRIPT"
|
||||||
|
else
|
||||||
|
echo "WARNING: $PREPARE_SCRIPT not found or not executable"
|
||||||
|
fi
|
||||||
|
|
||||||
# Initialize elinux project if not already configured
|
# Initialize elinux project if not already configured
|
||||||
if [ ! -d "elinux" ]; then
|
if [ ! -d "elinux" ]; then
|
||||||
echo "Initializing elinux project structure..."
|
echo "Initializing elinux project structure..."
|
||||||
|
|||||||
109
scripts/prepare_assets.sh
Normal file
109
scripts/prepare_assets.sh
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# prepare_assets.sh - Prepares fonts and images for Flutter build
|
||||||
|
# Run this before 'flutter build' to ensure assets are in place
|
||||||
|
#
|
||||||
|
# This script handles:
|
||||||
|
# - DIN1451 font: symlinks from extra/ if present, otherwise downloads Noto Sans as fallback
|
||||||
|
# - Dashboard image: symlinks from extra/ if present, otherwise skipped (handled at runtime)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
|
UI_DIR="$PROJECT_ROOT/pi/ui"
|
||||||
|
FONTS_DIR="$UI_DIR/fonts"
|
||||||
|
IMAGES_DIR="$UI_DIR/assets/images"
|
||||||
|
EXTRA_FONTS="$PROJECT_ROOT/extra/fonts"
|
||||||
|
EXTRA_IMAGES="$PROJECT_ROOT/extra/images"
|
||||||
|
|
||||||
|
# Noto Sans download URLs (Google Fonts)
|
||||||
|
NOTO_SANS_BASE="https://github.com/googlefonts/noto-fonts/raw/main/hinted/ttf/NotoSans"
|
||||||
|
NOTO_REGULAR="$NOTO_SANS_BASE/NotoSans-Regular.ttf"
|
||||||
|
NOTO_BOLD="$NOTO_SANS_BASE/NotoSans-Bold.ttf"
|
||||||
|
NOTO_LIGHT="$NOTO_SANS_BASE/NotoSans-Light.ttf"
|
||||||
|
|
||||||
|
echo "=== Smart Serow Asset Preparation ==="
|
||||||
|
|
||||||
|
# --- FONTS ---
|
||||||
|
echo ""
|
||||||
|
echo "--- Fonts ---"
|
||||||
|
|
||||||
|
# Ensure Noto Sans fallbacks exist
|
||||||
|
download_noto() {
|
||||||
|
local weight=$1
|
||||||
|
local url=$2
|
||||||
|
local dest="$FONTS_DIR/NotoSans-${weight}.ttf"
|
||||||
|
|
||||||
|
if [ ! -f "$dest" ]; then
|
||||||
|
echo "Downloading Noto Sans $weight..."
|
||||||
|
curl -sL "$url" -o "$dest" || {
|
||||||
|
echo "Warning: Failed to download Noto Sans $weight"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
echo " -> Downloaded $dest"
|
||||||
|
else
|
||||||
|
echo " Noto Sans $weight already present"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
download_noto "Regular" "$NOTO_REGULAR"
|
||||||
|
download_noto "Bold" "$NOTO_BOLD"
|
||||||
|
download_noto "Light" "$NOTO_LIGHT"
|
||||||
|
|
||||||
|
# DIN1451 - symlink if available, otherwise use Noto Sans
|
||||||
|
DIN_TARGET="$FONTS_DIR/din1451alt.ttf"
|
||||||
|
DIN_SOURCE="$EXTRA_FONTS/din1451alt.ttf"
|
||||||
|
|
||||||
|
# Remove old symlink/file to ensure fresh state
|
||||||
|
rm -f "$DIN_TARGET"
|
||||||
|
|
||||||
|
if [ -f "$DIN_SOURCE" ]; then
|
||||||
|
echo "DIN1451 found - linking/copying"
|
||||||
|
# Try symlink first, fall back to copy (Windows compatibility)
|
||||||
|
if ln -s "$DIN_SOURCE" "$DIN_TARGET" 2>/dev/null; then
|
||||||
|
echo " -> Linked $DIN_TARGET -> $DIN_SOURCE"
|
||||||
|
else
|
||||||
|
cp "$DIN_SOURCE" "$DIN_TARGET"
|
||||||
|
echo " -> Copied $DIN_TARGET (symlinks not supported)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "DIN1451 not found - using Noto Sans as fallback"
|
||||||
|
if [ -f "$FONTS_DIR/NotoSans-Regular.ttf" ]; then
|
||||||
|
cp "$FONTS_DIR/NotoSans-Regular.ttf" "$DIN_TARGET"
|
||||||
|
echo " -> Copied Noto Sans Regular as $DIN_TARGET"
|
||||||
|
else
|
||||||
|
echo " ERROR: No fallback font available!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- IMAGES ---
|
||||||
|
echo ""
|
||||||
|
echo "--- Images ---"
|
||||||
|
|
||||||
|
REI_TARGET="$IMAGES_DIR/rei_default.png"
|
||||||
|
REI_SOURCE="$EXTRA_IMAGES/rei_default.png"
|
||||||
|
|
||||||
|
# Remove old symlink/file
|
||||||
|
rm -f "$REI_TARGET"
|
||||||
|
|
||||||
|
if [ -f "$REI_SOURCE" ]; then
|
||||||
|
echo "Dashboard image found - linking/copying"
|
||||||
|
# Try symlink first, fall back to copy (Windows compatibility)
|
||||||
|
if ln -s "$REI_SOURCE" "$REI_TARGET" 2>/dev/null; then
|
||||||
|
echo " -> Linked $REI_TARGET -> $REI_SOURCE"
|
||||||
|
else
|
||||||
|
cp "$REI_SOURCE" "$REI_TARGET"
|
||||||
|
echo " -> Copied $REI_TARGET (symlinks not supported)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Dashboard image not found - will use empty fallback at runtime"
|
||||||
|
# Create a tiny transparent PNG placeholder (1x1 pixel)
|
||||||
|
# This avoids asset not found errors while keeping the build clean
|
||||||
|
printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01\r\n-\xb4\x00\x00\x00\x00IEND\xaeB`\x82' > "$REI_TARGET"
|
||||||
|
echo " -> Created 1x1 transparent placeholder"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Asset preparation complete ==="
|
||||||
|
echo "You can now run: flutter build linux"
|
||||||
Reference in New Issue
Block a user