diff --git a/lib/main.dart b/lib/main.dart index fe092bc..ef7004a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; // Required for Platform check import 'package:flutter/material.dart'; import 'package:system_tray/system_tray.dart'; import 'package:window_manager/window_manager.dart'; @@ -8,8 +7,7 @@ import 'package:audioplayers/audioplayers.dart'; // --- Configuration --- const Duration popupInterval = Duration(hours: 1); // How often to pop up -const String notificationSound = - 'notification.wav'; // Sound file in assets/sounds/ +const String notificationSound = 'MeetTheSniper.ogg'; // -------------------- void main() async { @@ -37,64 +35,89 @@ void main() async { class JournalerApp extends StatelessWidget { const JournalerApp({super.key}); + // --- Base Theme Configuration --- + static final TextTheme _baseTextTheme = const TextTheme( + bodyMedium: TextStyle(fontSize: 24), + // Define other common styles if needed + ); + + static final TextStyle _baseTitleTextStyle = const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + ); + + static final InputDecorationTheme + _baseInputDecorationTheme = const InputDecorationTheme( + border: OutlineInputBorder(), + labelStyle: TextStyle(fontSize: 20), // Base label size + // contentPadding: EdgeInsets.all(12.0), // Example: Add padding globally + ); + // ------------------------------ + // Define the light theme - static final ThemeData lightTheme = ThemeData( - brightness: Brightness.light, - primarySwatch: Colors.blue, // Or use ColorScheme.fromSeed(seedColor: Colors.blue) + static final ThemeData lightTheme = ThemeData.light().copyWith( visualDensity: VisualDensity.adaptivePlatformDensity, - scaffoldBackgroundColor: Colors.grey[100], // Slightly off-white - appBarTheme: const AppBarTheme( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, // Title and icons + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.blue, + brightness: Brightness.light, ), - inputDecorationTheme: InputDecorationTheme( - border: const OutlineInputBorder(), + scaffoldBackgroundColor: Colors.grey[100], + appBarTheme: AppBarTheme( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + titleTextStyle: _baseTitleTextStyle.copyWith(color: Colors.white), + ), + inputDecorationTheme: _baseInputDecorationTheme.copyWith( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue.shade600, width: 2.0), ), - labelStyle: TextStyle(color: Colors.grey[700]), + labelStyle: _baseInputDecorationTheme.labelStyle?.copyWith( + color: Colors.grey[700], + ), + ), + textTheme: _baseTextTheme.copyWith( + // Optionally override specific light theme text styles here ), - // Add other theme properties like textTheme if needed ); // Define the dark theme - static final ThemeData darkTheme = ThemeData( - brightness: Brightness.dark, - primarySwatch: Colors.blue, // Keep blue, or choose a different shade - // Or use ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark) + static final ThemeData darkTheme = ThemeData.dark().copyWith( visualDensity: VisualDensity.adaptivePlatformDensity, - scaffoldBackgroundColor: Colors.grey[900], // Dark background - appBarTheme: AppBarTheme( - backgroundColor: Colors.grey[850], // Darker app bar - foregroundColor: Colors.white, // Title and icons + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.blue, + brightness: Brightness.dark, ), - inputDecorationTheme: InputDecorationTheme( + scaffoldBackgroundColor: Colors.grey[900], + appBarTheme: AppBarTheme( + backgroundColor: Colors.grey[850], + foregroundColor: Colors.white, + titleTextStyle: _baseTitleTextStyle.copyWith(color: Colors.white), + ), + inputDecorationTheme: _baseInputDecorationTheme.copyWith( border: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.grey), // Lighter border for dark theme + borderSide: BorderSide(color: Colors.grey), // Dark theme default border ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue.shade300, width: 2.0), ), - labelStyle: TextStyle(color: Colors.grey[400]), // Lighter label for dark theme - // Ensure content padding is applied if needed, or use default - // contentPadding: const EdgeInsets.all(8.0), // This was in TextField, maybe move to theme? + labelStyle: _baseInputDecorationTheme.labelStyle?.copyWith( + color: Colors.grey[400], + ), ), - // Ensure text field text color is readable - textTheme: const TextTheme( - bodyMedium: TextStyle(color: Colors.white), // Default text style - // Define other text styles as needed + textTheme: _baseTextTheme.copyWith( + // Ensure body text is readable on dark background + bodyMedium: _baseTextTheme.bodyMedium?.copyWith(color: Colors.white), + // Optionally override other dark theme text styles here ), - // Define icon theme for app bar if needed, though foregroundColor often handles it - // iconTheme: const IconThemeData(color: Colors.white), ); @override Widget build(BuildContext context) { return MaterialApp( title: 'Journaler', - theme: lightTheme, // Use the light theme definition - darkTheme: darkTheme, // Use the dark theme definition - themeMode: ThemeMode.system, // Automatically switch based on system settings + theme: lightTheme, + darkTheme: darkTheme, + themeMode: ThemeMode.system, home: const MainPage(), debugShowCheckedModeBanner: false, ); @@ -109,7 +132,6 @@ class MainPage extends StatefulWidget { } class _MainPageState extends State with WindowListener { - // final AppWindow _appWindow = AppWindow(); // REMOVED - Not used final SystemTray _systemTray = SystemTray(); final AudioPlayer _audioPlayer = AudioPlayer(); @@ -167,8 +189,7 @@ class _MainPageState extends State with WindowListener { Future _initSystemTray() async { // Use simple relative paths for assets declared in pubspec.yaml // The build process handles packaging these assets correctly. - String iconPath = - Platform.isWindows ? 'assets/app_icon.ico' : 'assets/app_icon.png'; + String iconPath = 'assets/app_icon.ico'; // IMPORTANT: You need to create an icon file named app_icon.ico (for Windows) // and/or app_icon.png (for Mac/Linux) and place it in the 'assets/' directory. @@ -200,35 +221,28 @@ class _MainPageState extends State with WindowListener { // Handle system tray menu item clicks _systemTray.registerSystemTrayEventHandler((eventName) { debugPrint("System Tray Event: $eventName"); - if (eventName == kSystemTrayEventClick) { - _showWindow(); - } else if (eventName == kSystemTrayEventRightClick) { - // Optional: Show a context menu on right click - // _systemTray.popUpContextMenu() - need to define menu items first - } + _showWindow(); }); } // --- Periodic Popup & Sound --- // void _startPopupTimer() { _popupTimer = Timer.periodic(popupInterval, (timer) { - _showWindowAndPlaySound(); + // Timer now only requests the window to show + _showWindow(); }); } - Future _showWindowAndPlaySound() async { - await _showWindow(); - await _playSound(); - } - Future _showWindow() async { - bool isVisible = await windowManager.isVisible(); - if (!isVisible) { + bool wasVisible = await windowManager.isVisible(); + if (!wasVisible) { // Ensure size and position before showing await windowManager.setSize(const Size(1600, 900)); // Set desired size await windowManager.center(); // Center the window await windowManager.show(); await windowManager.focus(); + // Play sound ONLY when window becomes visible + await _playSound(); } else { // If already visible, just bring to front and focus await windowManager.focus(); @@ -287,6 +301,19 @@ class _MainPageState extends State with WindowListener { // _currentEntryController.clear(); // Decide if you want to clear it immediately } + // --- Add a specific save function for Todo List --- // + void _saveTodoList() { + // TODO: Implement debounced logic to save the todo list + // Avoid saving on every single keystroke - use a debounce mechanism + // (e.g., wait 500ms after the last change before saving) + String todoList = _todoController.text; + print("Saving Todo list (placeholder)... [${todoList.length} chars]"); + // --- Your actual todo list persistence logic goes here --- + // Example: + // await saveTodoListToFile(todoList); + // -------------------------------------------------------- + } + // Helper to set initial window config like aspect ratio Future _setWindowConfig() async { // Wait a moment to ensure window manager is fully ready after init @@ -303,23 +330,9 @@ class _MainPageState extends State with WindowListener { return Scaffold( appBar: AppBar( title: const Text('Journaler'), - // Optional: Add a save button or other actions - actions: [ - IconButton( - icon: const Icon(Icons.save), - onPressed: _saveData, - tooltip: 'Save Current Entry & Todo', - ), - IconButton( - icon: const Icon(Icons.volume_up), - onPressed: _playSound, // For testing sound - tooltip: 'Test Sound', - ), - IconButton( - icon: const Icon(Icons.timer), - onPressed: _showWindowAndPlaySound, // For testing popup - tooltip: 'Test Popup', - ), + actions: const [ + // Remove all buttons + // No actions needed anymore ], ), body: Padding( @@ -341,6 +354,10 @@ class _MainPageState extends State with WindowListener { maxLines: null, // Allows unlimited lines expands: true, // Fills the available space readOnly: true, // Make it non-editable + style: + Theme.of( + context, + ).textTheme.bodyMedium, // Apply theme text style decoration: const InputDecoration( labelText: 'Previous Entry', // border: OutlineInputBorder(), // Handled by theme @@ -356,6 +373,10 @@ class _MainPageState extends State with WindowListener { maxLines: null, expands: true, autofocus: true, // Focus here when window appears + style: + Theme.of( + context, + ).textTheme.bodyMedium, // Apply theme text style decoration: const InputDecoration( labelText: 'Current Entry (What\'s on your mind?)', // border: OutlineInputBorder(), // Handled by theme @@ -377,14 +398,18 @@ class _MainPageState extends State with WindowListener { controller: _todoController, maxLines: null, expands: true, + style: + Theme.of( + context, + ).textTheme.bodyMedium, // Apply theme text style decoration: const InputDecoration( labelText: 'Todo List', // border: OutlineInputBorder(), // Handled by theme // contentPadding: EdgeInsets.all(8.0), // Handled by theme or default ), onChanged: (text) { - // Optional: Auto-save Todo list changes - // Consider debouncing if saving frequently + // Auto-save Todo list changes (consider debouncing) + _saveTodoList(); }, ), ),