From 2b2fc8fbd35d85ea1ad1d51c9ad191bb00d7b615 Mon Sep 17 00:00:00 2001 From: Mikkeli Matlock Date: Mon, 9 Feb 2026 21:22:19 +0900 Subject: [PATCH] chore(01-01): create directory structure and infrastructure files - Create lib/screens/, lib/widgets/, lib/providers/, lib/models/, lib/config/ directories - Add Logger utility with error/warn/info/debug levels (kDebugMode guarded) - Add GpsConfig constants (timeouts, heading validation) - Add TimingConfig constants (heartbeat, overlay intervals) - Add OverlayConfig constants (sizing, opacity ratios) --- lib/config/gps_constants.dart | 22 +++++++++++++ lib/config/overlay_constants.dart | 37 ++++++++++++++++++++++ lib/config/timing_constants.dart | 16 ++++++++++ lib/services/logger.dart | 52 +++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 lib/config/gps_constants.dart create mode 100644 lib/config/overlay_constants.dart create mode 100644 lib/config/timing_constants.dart create mode 100644 lib/services/logger.dart diff --git a/lib/config/gps_constants.dart b/lib/config/gps_constants.dart new file mode 100644 index 0000000..343dec4 --- /dev/null +++ b/lib/config/gps_constants.dart @@ -0,0 +1,22 @@ +// GPS behavioral constants — SCREAMING_SNAKE per project convention + +/// GPS configuration constants for data validation and timeouts +abstract class GpsConfig { + /// Time threshold after which GPS data is considered stale + static const Duration STALE_DATA_THRESHOLD = Duration(seconds: 4); + + /// Timeout for initial GPS fix acquisition (outdoor/cold start) + static const Duration INITIAL_FIX_TIMEOUT = Duration(seconds: 20); + + /// Timeout for ongoing GPS updates (indoor/signal loss detection) + static const Duration UPDATE_TIMEOUT = Duration(seconds: 2); + + /// Minimum valid heading value in degrees + static const double VALID_HEADING_MIN = 0.0; + + /// Maximum valid heading value in degrees + static const double VALID_HEADING_MAX = 360.0; + + /// Speed threshold below which heading is considered unreliable (m/s) + static const double LOW_SPEED_THRESHOLD = 1.0; +} diff --git a/lib/config/overlay_constants.dart b/lib/config/overlay_constants.dart new file mode 100644 index 0000000..3fc0536 --- /dev/null +++ b/lib/config/overlay_constants.dart @@ -0,0 +1,37 @@ +// Overlay sizing and display constants — SCREAMING_SNAKE per project convention + +/// Overlay window configuration for proportional sizing and appearance +abstract class OverlayConfig { + /// Overlay width as percentage of screen width + static const double WIDTH_PERCENTAGE = 0.45; + + /// Overlay height aspect ratio relative to width + static const double ASPECT_RATIO = 0.6; + + /// Background color opacity + static const double BACKGROUND_OPACITY = 0.85; + + /// Border color opacity + static const double BORDER_OPACITY = 0.3; + + /// Speed text font size as ratio of overlay width + static const double FONT_SIZE_RATIO = 0.2; + + /// Unit text font size as ratio of speed font size + static const double UNIT_FONT_RATIO = 0.6; + + /// Navigation icon size as ratio of overlay width + static const double ICON_SIZE_RATIO = 0.72; + + /// Heading text font size as ratio of speed font size + static const double HEADING_FONT_RATIO = 0.4; + + /// Default screen width for calculations when actual width unavailable + static const double DEFAULT_SCREEN_WIDTH = 400.0; + + /// Default overlay width for calculations + static const double DEFAULT_OVERLAY_WIDTH = 280.0; + + /// Default overlay height for calculations + static const double DEFAULT_OVERLAY_HEIGHT = 140.0; +} diff --git a/lib/config/timing_constants.dart b/lib/config/timing_constants.dart new file mode 100644 index 0000000..c80718e --- /dev/null +++ b/lib/config/timing_constants.dart @@ -0,0 +1,16 @@ +// Timer and interval constants — SCREAMING_SNAKE per project convention + +/// Timing configuration for background tasks and UI interactions +abstract class TimingConfig { + /// Interval for background heartbeat to keep GPS alive + static const Duration HEARTBEAT_INTERVAL = Duration(seconds: 5); + + /// Interval for checking overlay window status + static const Duration OVERLAY_STATUS_CHECK_INTERVAL = Duration(milliseconds: 1000); + + /// Delay before closing overlay after tap + static const Duration TAP_CLOSE_DELAY = Duration(milliseconds: 500); + + /// Delay for long press gesture signal + static const Duration LONG_PRESS_SIGNAL_DELAY = Duration(milliseconds: 50); +} diff --git a/lib/services/logger.dart b/lib/services/logger.dart new file mode 100644 index 0000000..2e525ec --- /dev/null +++ b/lib/services/logger.dart @@ -0,0 +1,52 @@ +import 'package:flutter/foundation.dart'; + +/// Logger utility for standardized debug output with color-coded severity levels. +/// All logging is guarded by kDebugMode and uses debugPrint to avoid truncation. +class Logger { + // ANSI color codes + static const String _red = '\x1B[31m'; + static const String _yellow = '\x1B[33m'; + static const String _blue = '\x1B[34m'; + static const String _gray = '\x1B[90m'; + static const String _reset = '\x1B[0m'; + + /// Log error-level message (red) + /// Used for failures, exceptions, critical issues + static void error(String message, [String? caller]) { + if (kDebugMode) { + final timestamp = DateTime.now().toUtc().toIso8601String(); + final callerTag = caller != null ? ' [$caller]' : ''; + debugPrint('$_red[ERROR] $timestamp$callerTag $message$_reset'); + } + } + + /// Log warning-level message (yellow) + /// Used for recoverable issues, unexpected states, deprecation warnings + static void warn(String message, [String? caller]) { + if (kDebugMode) { + final timestamp = DateTime.now().toUtc().toIso8601String(); + final callerTag = caller != null ? ' [$caller]' : ''; + debugPrint('$_yellow[WARN] $timestamp$callerTag $message$_reset'); + } + } + + /// Log info-level message (blue) + /// Used for lifecycle events, state transitions, user actions + static void info(String message, [String? caller]) { + if (kDebugMode) { + final timestamp = DateTime.now().toUtc().toIso8601String(); + final callerTag = caller != null ? ' [$caller]' : ''; + debugPrint('$_blue[INFO] $timestamp$callerTag $message$_reset'); + } + } + + /// Log debug-level message (gray) + /// Used for data flow, detailed state changes, verbose diagnostics + static void debug(String message, [String? caller]) { + if (kDebugMode) { + final timestamp = DateTime.now().toUtc().toIso8601String(); + final callerTag = caller != null ? ' [$caller]' : ''; + debugPrint('$_gray[DEBUG] $timestamp$callerTag $message$_reset'); + } + } +}