refactor: make compass button dynamic - only show when map is rotated

- Convert CompassMapPluginWidget from StatelessWidget to StatefulWidget
- Add periodic rotation monitoring (every 100ms) to detect map rotation changes
- Button only appears when rotation != 0 (map is rotated away from north)
- Button automatically disappears when map is reset to north (rotation = 0)
- Improves UX by reducing visual clutter when map is already north-aligned
- Add tooltip 'Go to North' for better user guidance
- Gracefully handle errors and only update state when widget is mounted
This commit is contained in:
vjrj 2026-03-06 09:08:28 +01:00
parent f39bdbfaef
commit d04064d17a

View file

@ -1,28 +1,90 @@
import 'dart:async';
import 'package:comunes_flutter/comunes_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
/// Compass button widget for resetting map rotation to north
class CompassMapPluginWidget extends StatelessWidget {
/// Only visible when map is rotated (rotation != 0)
class CompassMapPluginWidget extends StatefulWidget {
@override
_CompassMapPluginWidgetState createState() => _CompassMapPluginWidgetState();
}
class _CompassMapPluginWidgetState extends State<CompassMapPluginWidget> {
late MapController _mapController;
bool _isRotated = false;
late Timer _rotationCheckTimer;
@override
void didChangeDependencies() {
super.didChangeDependencies();
try {
_mapController = MapController.of(context);
_initRotationMonitoring();
} catch (e) {
print('Error getting map controller: $e');
}
}
void _initRotationMonitoring() {
// Check rotation periodically (every 100ms) to detect changes
_rotationCheckTimer = Timer.periodic(Duration(milliseconds: 100), (_) {
_checkRotation();
});
// Initial state check
_checkRotation();
}
void _checkRotation() {
try {
if (!mounted) return;
final rotation = _mapController.camera.rotation;
final isRotated = rotation.abs() > 0.0;
if (isRotated != _isRotated) {
setState(() {
_isRotated = isRotated;
});
}
} catch (e) {
// Silently ignore errors (controller may not be ready)
}
}
void _resetRotation() {
try {
final controller = MapController.of(context);
controller.rotate(0);
} catch (e) {
print('Error resetting rotation: $e');
}
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) =>
Stack(fit: StackFit.expand, children: <Widget>[
Positioned(
top: 10.0,
right: 10.0,
child: new CenteredRow(
children: <Widget>[
new Column(
builder: (context, constraints) => Stack(
fit: StackFit.expand,
children: <Widget>[
if (_isRotated)
Positioned(
top: 10.0,
right: 10.0,
child: CenteredRow(
children: <Widget>[
_compassButton(context),
Column(
children: <Widget>[
_compassButton(context),
],
)
],
)
],
),
)
]));
),
)
],
));
}
FloatingActionButton _compassButton(BuildContext context) {
@ -30,12 +92,15 @@ class CompassMapPluginWidget extends StatelessWidget {
backgroundColor: Colors.black26,
mini: true,
heroTag: 'compass_button',
onPressed: () {
final controller = MapController.of(context);
// Reset rotation to 0 (north) while keeping center and zoom
controller.rotate(0);
},
tooltip: 'Go to North',
onPressed: _resetRotation,
child: Icon(Icons.explore),
);
}
@override
void dispose() {
_rotationCheckTimer.cancel();
super.dispose();
}
}