feat(01-02): extract OverlaySpeedometer to screens/overlay_screen.dart
- Created lib/screens/overlay_screen.dart with OverlaySpeedometer and _OverlaySpeedometerState - All state, methods, gesture handling preserved exactly - main.dart imports screens/overlay_screen.dart - OverlaySpeedometer removed from main.dart - main.dart slimmed to 39 lines (under 60 line target) - main.dart now contains only: main(), overlayMain(), SpeedoApp class - Zero analyzer errors (except intentional SCREAMING_SNAKE warnings)
This commit is contained in:
+1
-301
@@ -1,13 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart'; // For kDebugMode
|
||||
import 'screens/speedometer_screen.dart';
|
||||
import 'screens/overlay_screen.dart';
|
||||
import 'services/logger.dart';
|
||||
import 'dart:math' as math; // Import for math.pi
|
||||
import 'package:flutter_overlay_window/flutter_overlay_window.dart';
|
||||
import 'config/color_themes.dart';
|
||||
import 'config/overlay_constants.dart';
|
||||
import 'config/timing_constants.dart';
|
||||
import 'models/overlay_message.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const SpeedoApp());
|
||||
@@ -42,298 +37,3 @@ class SpeedoApp extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class OverlaySpeedometer extends StatefulWidget {
|
||||
const OverlaySpeedometer({super.key});
|
||||
|
||||
@override
|
||||
State<OverlaySpeedometer> createState() => _OverlaySpeedometerState();
|
||||
}
|
||||
|
||||
class _OverlaySpeedometerState extends State<OverlaySpeedometer> {
|
||||
String _speedText = '--';
|
||||
String _unitText = 'km/h';
|
||||
String _headingText = 'N/A';
|
||||
double _heading = -1.0;
|
||||
int _currentThemeIndex = 0;
|
||||
double _systemScreenWidth = 400;
|
||||
double _overlayWidth = 280;
|
||||
double _overlayHeight = 140;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Logger.info('CREATED - Floating window initialized (${DateTime.now().millisecondsSinceEpoch})', 'Overlay');
|
||||
_getSystemScreenSize();
|
||||
_listenToMainAppMessages();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Logger.info('DISPOSING - Overlay widget disposed (${DateTime.now().millisecondsSinceEpoch})', 'Overlay');
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _getSystemScreenSize() {
|
||||
try {
|
||||
// Get actual system screen resolution, not just app window size
|
||||
final window = WidgetsBinding.instance.platformDispatcher.views.first;
|
||||
final physicalSize = window.physicalSize;
|
||||
final devicePixelRatio = window.devicePixelRatio;
|
||||
final systemSize = physicalSize / devicePixelRatio;
|
||||
|
||||
Logger.debug('Screen detection:', 'Overlay');
|
||||
Logger.debug(' physicalSize: ${physicalSize.width.round()}x${physicalSize.height.round()}', 'Overlay');
|
||||
Logger.debug(' devicePixelRatio: $devicePixelRatio', 'Overlay');
|
||||
Logger.debug(' calculated systemSize: ${systemSize.width.round()}x${systemSize.height.round()}', 'Overlay');
|
||||
|
||||
setState(() {
|
||||
_systemScreenWidth = systemSize.width;
|
||||
});
|
||||
|
||||
Logger.debug('_systemScreenWidth set to: ${_systemScreenWidth.round()}', 'Overlay');
|
||||
} catch (e) {
|
||||
Logger.error('Error getting system screen size: $e', 'Overlay');
|
||||
// Fallback to reasonable default
|
||||
setState(() {
|
||||
_systemScreenWidth = OverlayConfig.DEFAULT_SCREEN_WIDTH;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _listenToMainAppMessages() {
|
||||
FlutterOverlayWindow.overlayListener.listen((data) {
|
||||
if (data is Map) {
|
||||
final message = OverlayMessage.fromMap(data);
|
||||
if (message.action == 'updateDisplay') {
|
||||
setState(() {
|
||||
_speedText = message.speedText ?? '--';
|
||||
_unitText = message.unitText ?? '';
|
||||
_headingText = message.headingText ?? 'N/A';
|
||||
_heading = message.heading ?? -1.0;
|
||||
_currentThemeIndex = message.themeIndex ?? 0;
|
||||
// Update overlay dimensions if provided by main app
|
||||
if (message.overlayWidth != null) {
|
||||
_overlayWidth = message.overlayWidth!;
|
||||
}
|
||||
if (message.overlayHeight != null) {
|
||||
_overlayHeight = message.overlayHeight!;
|
||||
}
|
||||
});
|
||||
|
||||
Logger.debug('UPDATE received:', 'Overlay');
|
||||
Logger.debug(' speedText: "$_speedText"', 'Overlay');
|
||||
Logger.debug(' headingText: "$_headingText"', 'Overlay');
|
||||
Logger.debug(' direction: ${_heading.toStringAsFixed(1)}°', 'Overlay');
|
||||
Logger.debug(' themeIndex: $_currentThemeIndex', 'Overlay');
|
||||
Logger.debug(' systemScreenWidth: ${_systemScreenWidth.round()}', 'Overlay');
|
||||
Logger.debug(' overlaySize from main: ${_overlayWidth.round()}x${_overlayHeight.round()}', 'Overlay');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final buildTimestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final currentTheme = ColorThemes.getTheme(_currentThemeIndex);
|
||||
|
||||
// Use overlay dimensions provided by main app (not calculated locally)
|
||||
final fontSize = (_overlayWidth * OverlayConfig.FONT_SIZE_RATIO);
|
||||
|
||||
Logger.debug('Building overlay widget ($buildTimestamp)', 'Overlay');
|
||||
Logger.debug('Window size: ${_overlayWidth.round()}x${_overlayHeight.round()}, fontSize: ${fontSize.round()}', 'Overlay');
|
||||
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: SizedBox(
|
||||
// Use SizedBox to fill the overlay window completely
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: currentTheme.background.withValues(alpha: OverlayConfig.BACKGROUND_OPACITY),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: currentTheme.speedText.withValues(alpha: OverlayConfig.BORDER_OPACITY),
|
||||
width: 1
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Main content - landscape layout (1:1 flex as per NOTES.txt)
|
||||
Row(
|
||||
children: [
|
||||
// Speed section - left half
|
||||
Expanded(
|
||||
flex: 55,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
(_speedText),
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: currentTheme.speedText,
|
||||
fontFamily: 'DIN1451Alt',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
_unitText,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize * OverlayConfig.UNIT_FONT_RATIO,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: currentTheme.unitText,
|
||||
fontFamily: 'DIN1451Alt',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Direction section - right half (same as full-screen behavior)
|
||||
Expanded(
|
||||
flex: 45,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 5,
|
||||
child: Transform.rotate(
|
||||
angle: (_heading >= 0 && _heading < 360) ? (_heading * math.pi / 180.0) : 0,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Icon(
|
||||
Icons.navigation,
|
||||
size: fontSize * OverlayConfig.ICON_SIZE_RATIO,
|
||||
color: currentTheme.headingText,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
_headingText,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize * OverlayConfig.HEADING_FONT_RATIO,
|
||||
color: currentTheme.headingText,
|
||||
fontFamily: 'DIN1451Alt',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Transparent full-overlay gesture detection layer
|
||||
Positioned.fill(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent, // Ensure gestures are captured
|
||||
onPanStart: (details) {
|
||||
Logger.debug('Pan start detected - gestures are working!', 'Overlay');
|
||||
},
|
||||
onLongPress: () async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
Logger.info('Long press detected - closing overlay and bringing main app to front ($timestamp)', 'Overlay');
|
||||
try {
|
||||
// Skip haptic feedback in overlay - platform services not available
|
||||
Logger.debug('Skipping haptic feedback (overlay context limitation)', 'Overlay');
|
||||
|
||||
// Signal main app to bring to foreground when overlay closes (non-blocking)
|
||||
Logger.debug('Sending bring-to-front close signal...', 'Overlay');
|
||||
FlutterOverlayWindow.shareData(OverlayMessage.longPressClose().toMap()).then((_) {
|
||||
Logger.debug('Long press close signal sent successfully', 'Overlay');
|
||||
}).catchError((error) {
|
||||
Logger.warn('Long press close signal failed (expected): $error', 'Overlay');
|
||||
});
|
||||
|
||||
// Small delay to give signal a chance
|
||||
await Future.delayed(TimingConfig.LONG_PRESS_SIGNAL_DELAY);
|
||||
|
||||
// Close the overlay
|
||||
Logger.info('Attempting to close overlay...', 'Overlay');
|
||||
await FlutterOverlayWindow.closeOverlay();
|
||||
Logger.info('Overlay closed successfully via long press', 'Overlay');
|
||||
|
||||
} catch (e, stackTrace) {
|
||||
Logger.error('Long press close failed: $e', 'Overlay');
|
||||
Logger.error('Stack trace: $stackTrace', 'Overlay');
|
||||
// Fallback: try to close anyway
|
||||
try {
|
||||
Logger.debug('Attempting fallback close...', 'Overlay');
|
||||
await FlutterOverlayWindow.closeOverlay();
|
||||
Logger.info('Fallback close succeeded', 'Overlay');
|
||||
} catch (fallbackError) {
|
||||
Logger.error('Fallback close also failed: $fallbackError', 'Overlay');
|
||||
}
|
||||
}
|
||||
},
|
||||
// Tap to bring main app to front functionality removed per NOTES.txt
|
||||
// onTap: () async {
|
||||
// final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
// customDebugPrint('[Overlay] 👆 Tap detected - bringing main app to foreground ($timestamp)');
|
||||
// try {
|
||||
// // Try to signal main app to come to foreground (non-blocking)
|
||||
// customDebugPrint('[Overlay] 📤 Attempting to signal bring-to-front...');
|
||||
// FlutterOverlayWindow.shareData({
|
||||
// 'action': 'bringToFront',
|
||||
// }).catchError((error) {
|
||||
// customDebugPrint('[Overlay] ❌ Bring-to-front signal failed (expected): $error');
|
||||
// });
|
||||
//
|
||||
// customDebugPrint('[Overlay] ✅ Tap gesture completed (overlay stays open)');
|
||||
//
|
||||
// } catch (e, stackTrace) {
|
||||
// customDebugPrint('[Overlay] ❌ Tap gesture failed: $e');
|
||||
// customDebugPrint('[Overlay] 📚 Stack trace: $stackTrace');
|
||||
// }
|
||||
// },
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
color: Colors.transparent,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'GESTURE',
|
||||
style: TextStyle(
|
||||
color: Colors.transparent,
|
||||
fontSize: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math' as math;
|
||||
import 'package:flutter_overlay_window/flutter_overlay_window.dart';
|
||||
import '../config/color_themes.dart';
|
||||
import '../config/overlay_constants.dart';
|
||||
import '../models/overlay_message.dart';
|
||||
import '../services/logger.dart';
|
||||
|
||||
class OverlaySpeedometer extends StatefulWidget {
|
||||
const OverlaySpeedometer({super.key});
|
||||
|
||||
@override
|
||||
State<OverlaySpeedometer> createState() => _OverlaySpeedometerState();
|
||||
}
|
||||
|
||||
class _OverlaySpeedometerState extends State<OverlaySpeedometer> {
|
||||
String _speedText = '--';
|
||||
String _unitText = 'km/h';
|
||||
String _headingText = 'N/A';
|
||||
double _heading = -1.0;
|
||||
int _currentThemeIndex = 0;
|
||||
double _systemScreenWidth = 400;
|
||||
double _overlayWidth = 280;
|
||||
double _overlayHeight = 140;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Logger.info('CREATED - Floating window initialized (${DateTime.now().millisecondsSinceEpoch})', 'Overlay');
|
||||
_getSystemScreenSize();
|
||||
_listenToMainAppMessages();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Logger.info('DISPOSING - Overlay widget disposed (${DateTime.now().millisecondsSinceEpoch})', 'Overlay');
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _getSystemScreenSize() {
|
||||
try {
|
||||
// Get actual system screen resolution, not just app window size
|
||||
final window = WidgetsBinding.instance.platformDispatcher.views.first;
|
||||
final physicalSize = window.physicalSize;
|
||||
final devicePixelRatio = window.devicePixelRatio;
|
||||
final systemSize = physicalSize / devicePixelRatio;
|
||||
|
||||
Logger.debug('Screen detection:', 'Overlay');
|
||||
Logger.debug(' physicalSize: ${physicalSize.width.round()}x${physicalSize.height.round()}', 'Overlay');
|
||||
Logger.debug(' devicePixelRatio: $devicePixelRatio', 'Overlay');
|
||||
Logger.debug(' calculated systemSize: ${systemSize.width.round()}x${systemSize.height.round()}', 'Overlay');
|
||||
|
||||
setState(() {
|
||||
_systemScreenWidth = systemSize.width;
|
||||
});
|
||||
|
||||
Logger.debug('_systemScreenWidth set to: ${_systemScreenWidth.round()}', 'Overlay');
|
||||
} catch (e) {
|
||||
Logger.error('Error getting system screen size: $e', 'Overlay');
|
||||
// Fallback to reasonable default
|
||||
setState(() {
|
||||
_systemScreenWidth = OverlayConfig.DEFAULT_SCREEN_WIDTH;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _listenToMainAppMessages() {
|
||||
FlutterOverlayWindow.overlayListener.listen((data) {
|
||||
if (data is Map) {
|
||||
final message = OverlayMessage.fromMap(data);
|
||||
if (message.action == 'updateDisplay') {
|
||||
setState(() {
|
||||
_speedText = message.speedText ?? '--';
|
||||
_unitText = message.unitText ?? '';
|
||||
_headingText = message.headingText ?? 'N/A';
|
||||
_heading = message.heading ?? -1.0;
|
||||
_currentThemeIndex = message.themeIndex ?? 0;
|
||||
// Update overlay dimensions if provided by main app
|
||||
if (message.overlayWidth != null) {
|
||||
_overlayWidth = message.overlayWidth!;
|
||||
}
|
||||
if (message.overlayHeight != null) {
|
||||
_overlayHeight = message.overlayHeight!;
|
||||
}
|
||||
});
|
||||
|
||||
Logger.debug('UPDATE received:', 'Overlay');
|
||||
Logger.debug(' speedText: "$_speedText"', 'Overlay');
|
||||
Logger.debug(' headingText: "$_headingText"', 'Overlay');
|
||||
Logger.debug(' direction: ${_heading.toStringAsFixed(1)}°', 'Overlay');
|
||||
Logger.debug(' themeIndex: $_currentThemeIndex', 'Overlay');
|
||||
Logger.debug(' systemScreenWidth: ${_systemScreenWidth.round()}', 'Overlay');
|
||||
Logger.debug(' overlaySize from main: ${_overlayWidth.round()}x${_overlayHeight.round()}', 'Overlay');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final buildTimestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final currentTheme = ColorThemes.getTheme(_currentThemeIndex);
|
||||
|
||||
// Use overlay dimensions provided by main app (not calculated locally)
|
||||
final fontSize = (_overlayWidth * OverlayConfig.FONT_SIZE_RATIO);
|
||||
|
||||
Logger.debug('Building overlay widget ($buildTimestamp)', 'Overlay');
|
||||
Logger.debug('Window size: ${_overlayWidth.round()}x${_overlayHeight.round()}, fontSize: ${fontSize.round()}', 'Overlay');
|
||||
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: SizedBox(
|
||||
// Use SizedBox to fill the overlay window completely
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: currentTheme.background.withValues(alpha: OverlayConfig.BACKGROUND_OPACITY),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: currentTheme.speedText.withValues(alpha: OverlayConfig.BORDER_OPACITY),
|
||||
width: 1
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Main content - landscape layout (1:1 flex as per NOTES.txt)
|
||||
Row(
|
||||
children: [
|
||||
// Speed section - left half
|
||||
Expanded(
|
||||
flex: 55,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
(_speedText),
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: currentTheme.speedText,
|
||||
fontFamily: 'DIN1451Alt',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
_unitText,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize * OverlayConfig.UNIT_FONT_RATIO,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: currentTheme.unitText,
|
||||
fontFamily: 'DIN1451Alt',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Direction section - right half (same as full-screen behavior)
|
||||
Expanded(
|
||||
flex: 45,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 5,
|
||||
child: Transform.rotate(
|
||||
angle: (_heading >= 0 && _heading < 360) ? (_heading * math.pi / 180.0) : 0,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Icon(
|
||||
Icons.navigation,
|
||||
size: fontSize * OverlayConfig.ICON_SIZE_RATIO,
|
||||
color: currentTheme.headingText,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
_headingText,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize * OverlayConfig.HEADING_FONT_RATIO,
|
||||
color: currentTheme.headingText,
|
||||
fontFamily: 'DIN1451Alt',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Transparent full-overlay gesture detection layer
|
||||
Positioned.fill(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent, // Ensure gestures are captured
|
||||
onPanStart: (details) {
|
||||
Logger.debug('Pan start detected - gestures are working!', 'Overlay');
|
||||
},
|
||||
onLongPress: () async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
Logger.info('Long press detected - closing overlay and bringing main app to front ($timestamp)', 'Overlay');
|
||||
try {
|
||||
// Skip haptic feedback in overlay - platform services not available
|
||||
Logger.debug('Skipping haptic feedback (overlay context limitation)', 'Overlay');
|
||||
|
||||
// Signal main app to bring to foreground when overlay closes (non-blocking)
|
||||
Logger.debug('Sending bring-to-front close signal...', 'Overlay');
|
||||
FlutterOverlayWindow.shareData(OverlayMessage.longPressClose().toMap()).then((_) {
|
||||
Logger.debug('Long press close signal sent successfully', 'Overlay');
|
||||
}).catchError((error) {
|
||||
Logger.warn('Long press close signal failed (expected): $error', 'Overlay');
|
||||
});
|
||||
|
||||
// Small delay to give signal a chance
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
|
||||
// Close the overlay
|
||||
Logger.info('Attempting to close overlay...', 'Overlay');
|
||||
await FlutterOverlayWindow.closeOverlay();
|
||||
Logger.info('Overlay closed successfully via long press', 'Overlay');
|
||||
|
||||
} catch (e, stackTrace) {
|
||||
Logger.error('Long press close failed: $e', 'Overlay');
|
||||
Logger.error('Stack trace: $stackTrace', 'Overlay');
|
||||
// Fallback: try to close anyway
|
||||
try {
|
||||
Logger.debug('Attempting fallback close...', 'Overlay');
|
||||
await FlutterOverlayWindow.closeOverlay();
|
||||
Logger.info('Fallback close succeeded', 'Overlay');
|
||||
} catch (fallbackError) {
|
||||
Logger.error('Fallback close also failed: $fallbackError', 'Overlay');
|
||||
}
|
||||
}
|
||||
},
|
||||
// Tap to bring main app to front functionality removed per NOTES.txt
|
||||
// onTap: () async {
|
||||
// final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
// customDebugPrint('[Overlay] 👆 Tap detected - bringing main app to foreground ($timestamp)');
|
||||
// try {
|
||||
// // Try to signal main app to come to foreground (non-blocking)
|
||||
// customDebugPrint('[Overlay] 📤 Attempting to signal bring-to-front...');
|
||||
// FlutterOverlayWindow.shareData({
|
||||
// 'action': 'bringToFront',
|
||||
// }).catchError((error) {
|
||||
// customDebugPrint('[Overlay] ❌ Bring-to-front signal failed (expected): $error');
|
||||
// });
|
||||
//
|
||||
// customDebugPrint('[Overlay] ✅ Tap gesture completed (overlay stays open)');
|
||||
//
|
||||
// } catch (e, stackTrace) {
|
||||
// customDebugPrint('[Overlay] ❌ Tap gesture failed: $e');
|
||||
// customDebugPrint('[Overlay] 📚 Stack trace: $stackTrace');
|
||||
// }
|
||||
// },
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
color: Colors.transparent,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'GESTURE',
|
||||
style: TextStyle(
|
||||
color: Colors.transparent,
|
||||
fontSize: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user