Fix notification sound
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
||||
*.ico filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||
|
BIN
assets/sounds/MGSSpot.mp3
(Stored with Git LFS)
Normal file
BIN
assets/sounds/MGSSpot.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/sounds/MeetTheSniper.mp3
(Stored with Git LFS)
Normal file
BIN
assets/sounds/MeetTheSniper.mp3
(Stored with Git LFS)
Normal file
Binary file not shown.
223
lib/main.dart
223
lib/main.dart
@@ -1,5 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io'; // Required for Platform check
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart'; // Needed for LogicalKeyboardKey
|
||||
import 'package:system_tray/system_tray.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
@@ -7,7 +9,7 @@ import 'package:audioplayers/audioplayers.dart';
|
||||
|
||||
// --- Configuration ---
|
||||
const Duration popupInterval = Duration(hours: 1); // How often to pop up
|
||||
const String notificationSound = 'MeetTheSniper.ogg';
|
||||
const String notificationSound = 'MeetTheSniper.mp3';
|
||||
// --------------------
|
||||
|
||||
void main() async {
|
||||
@@ -141,6 +143,7 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
||||
final TextEditingController _todoController = TextEditingController();
|
||||
|
||||
Timer? _popupTimer;
|
||||
Timer? _debounceTimer; // Timer for debouncing Todo saves
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -161,6 +164,7 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
||||
void dispose() {
|
||||
windowManager.removeListener(this);
|
||||
_popupTimer?.cancel();
|
||||
_debounceTimer?.cancel(); // Cancel debounce timer on dispose
|
||||
_previousEntryController.dispose();
|
||||
_currentEntryController.dispose();
|
||||
_todoController.dispose();
|
||||
@@ -251,11 +255,20 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
||||
|
||||
Future<void> _playSound() async {
|
||||
try {
|
||||
// Stop any previous playback before starting anew
|
||||
await _audioPlayer.stop();
|
||||
// Assumes the sound file is in assets/sounds/
|
||||
await _audioPlayer.play(AssetSource('sounds/$notificationSound'));
|
||||
debugPrint("Played sound: $notificationSound");
|
||||
} catch (e) {
|
||||
debugPrint("Error playing sound: $e");
|
||||
} catch (e, stackTrace) {
|
||||
// Catch stack trace for more details
|
||||
debugPrint("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
debugPrint("Error playing sound '$notificationSound': $e");
|
||||
debugPrint("Stack trace: $stackTrace");
|
||||
debugPrint(
|
||||
"Ensure file exists, is valid audio, and assets/sounds/ is in pubspec.yaml",
|
||||
);
|
||||
debugPrint("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
// Handle error, e.g., show a notification or log
|
||||
}
|
||||
}
|
||||
@@ -303,15 +316,19 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
||||
|
||||
// --- 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);
|
||||
// --------------------------------------------------------
|
||||
// Cancel any existing timer
|
||||
if (_debounceTimer?.isActive ?? false) _debounceTimer!.cancel();
|
||||
|
||||
// Start a new timer
|
||||
_debounceTimer = Timer(const Duration(milliseconds: 500), () {
|
||||
// This code runs after 500ms of inactivity
|
||||
String todoList = _todoController.text;
|
||||
print("Debounced Save: Saving Todo list... [${todoList.length} chars]");
|
||||
// --- Your actual todo list persistence logic goes here ---
|
||||
// Example:
|
||||
// await saveTodoListToFile(todoList);
|
||||
// --------------------------------------------------------
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to set initial window config like aspect ratio
|
||||
@@ -327,94 +344,104 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
||||
// --- UI Build --- //
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Journaler'),
|
||||
actions: const [
|
||||
// Remove all buttons
|
||||
// No actions needed anymore
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Main journal area (8-10 columns)
|
||||
Expanded(
|
||||
flex:
|
||||
9, // Adjust flex factor (e.g., 8, 9, 10) for desired width ratio
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Previous Entry (read-only conceptually, but TextField for easy display)
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _previousEntryController,
|
||||
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
|
||||
// contentPadding: EdgeInsets.all(8.0), // Handled by theme or default
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8), // Spacing
|
||||
// Current Entry
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _currentEntryController,
|
||||
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
|
||||
// contentPadding: EdgeInsets.all(8.0), // Handled by theme or default
|
||||
),
|
||||
onChanged: (text) {
|
||||
// Optional: Add auto-save logic here if desired
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8), // Spacing between columns
|
||||
// Todo List area (remaining columns)
|
||||
Expanded(
|
||||
flex: 3, // Adjust flex factor (12 - 9 = 3, or 12 - 8 = 4, etc.)
|
||||
child: TextField(
|
||||
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) {
|
||||
// Auto-save Todo list changes (consider debouncing)
|
||||
_saveTodoList();
|
||||
},
|
||||
),
|
||||
),
|
||||
// Listen for keyboard events to close on Escape
|
||||
return RawKeyboardListener(
|
||||
focusNode: FocusNode(), // Need a focus node to receive keys
|
||||
autofocus: true, // Ensure it can receive focus
|
||||
onKey: (event) {
|
||||
if (event.logicalKey == LogicalKeyboardKey.escape) {
|
||||
debugPrint("Escape key pressed - hiding window.");
|
||||
windowManager.hide();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Journaler'),
|
||||
actions: const [
|
||||
// Remove all buttons
|
||||
// No actions needed anymore
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Main journal area (8-10 columns)
|
||||
Expanded(
|
||||
flex:
|
||||
9, // Adjust flex factor (e.g., 8, 9, 10) for desired width ratio
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Previous Entry (read-only conceptually, but TextField for easy display)
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _previousEntryController,
|
||||
maxLines: null, // Allows unlimited lines
|
||||
expands: true, // Fills the available space
|
||||
style:
|
||||
Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium, // Apply theme text style
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Previous Entry',
|
||||
// border: OutlineInputBorder(), // Handled by theme
|
||||
// contentPadding: EdgeInsets.all(8.0), // Handled by theme or default
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8), // Spacing
|
||||
// Current Entry
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _currentEntryController,
|
||||
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
|
||||
// contentPadding: EdgeInsets.all(8.0), // Handled by theme or default
|
||||
),
|
||||
onChanged: (text) {
|
||||
// Optional: Add auto-save logic here if desired
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8), // Spacing between columns
|
||||
// Todo List area (remaining columns)
|
||||
Expanded(
|
||||
flex: 3, // Adjust flex factor (12 - 9 = 3, or 12 - 8 = 4, etc.)
|
||||
child: TextField(
|
||||
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) {
|
||||
// Auto-save Todo list changes (consider debouncing)
|
||||
_saveTodoList();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user