mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-02-13 09:12:56 +00:00
Compare commits
4 Commits
v1.8.1-rc
...
v2.0.0-rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ed30dcff8 | ||
|
|
98e7e499d4 | ||
|
|
7fb467872a | ||
|
|
405ec220d0 |
166
V1.8.2_SHEET_POSITIONING_FIX.md
Normal file
166
V1.8.2_SHEET_POSITIONING_FIX.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# v1.8.2 Sheet Positioning Fix
|
||||
|
||||
## Problem Identified
|
||||
The node tags sheet and suspected location sheet were not properly adjusting the map positioning to keep the visual center in the middle of the viewable area above the sheet, unlike the working add/edit node sheets.
|
||||
|
||||
## Root Cause Analysis
|
||||
Upon investigation, the infrastructure was already in place and should have been working:
|
||||
1. Both sheets use `MeasuredSheet` wrapper to track height
|
||||
2. Both sheets call `SheetCoordinator.updateTagSheetHeight()`
|
||||
3. `SheetCoordinator.activeSheetHeight` includes tag sheet height as the lowest priority
|
||||
4. `SheetAwareMap` receives this height and positions the map accordingly
|
||||
|
||||
However, a **race condition** was discovered in the sheet transition logic when moving from tag sheet to edit sheet:
|
||||
|
||||
### The Race Condition
|
||||
1. User taps "Edit" in NodeTagSheet
|
||||
2. `appState.startEditSession(node)` is called
|
||||
3. Auto-show logic calls `_openEditNodeSheet()`
|
||||
4. `_openEditNodeSheet()` calls `Navigator.of(context).pop()` to close the tag sheet
|
||||
5. **The tag sheet's `.closed.then(...)` callback runs and calls `resetTagSheetHeight` because `_transitioningToEdit` is still false**
|
||||
6. **Only THEN** does `_openEditNodeSheet()` call `_sheetCoordinator.openEditNodeSheet()` which sets `_transitioningToEdit = true`
|
||||
|
||||
This caused the map to bounce during edit sheet transitions, and potentially interfered with proper height coordination.
|
||||
|
||||
## Solution Implemented
|
||||
|
||||
### 1. Fixed Race Condition in Sheet Transitions
|
||||
**File**: `lib/screens/home_screen.dart`
|
||||
- Set `_transitioningToEdit = true` **BEFORE** closing the tag sheet
|
||||
- This prevents the tag sheet's close callback from resetting the height prematurely
|
||||
- Ensures smooth transitions without map bounce
|
||||
|
||||
```dart
|
||||
void _openEditNodeSheet() {
|
||||
// Set transition flag BEFORE closing tag sheet to prevent map bounce
|
||||
_sheetCoordinator.setTransitioningToEdit(true);
|
||||
|
||||
// Close any existing tag sheet first...
|
||||
```
|
||||
|
||||
### 2. Enhanced Debugging and Monitoring
|
||||
**Files**:
|
||||
- `lib/widgets/measured_sheet.dart` - Added optional debug labels and height change logging
|
||||
- `lib/screens/coordinators/sheet_coordinator.dart` - Added debug logging for height updates and active height calculation
|
||||
- `lib/screens/home_screen.dart` - Added debug labels to all MeasuredSheet instances
|
||||
|
||||
**Debug Labels Added**:
|
||||
- `NodeTag` - For node tag sheets
|
||||
- `SuspectedLocation` - For suspected location sheets
|
||||
- `AddNode` - For add node sheets
|
||||
- `EditNode` - For edit node sheets
|
||||
- `Navigation` - For navigation sheets
|
||||
|
||||
### 3. Improved Fallback Robustness
|
||||
**Files**:
|
||||
- `lib/widgets/map/node_markers.dart`
|
||||
- `lib/widgets/map/suspected_location_markers.dart`
|
||||
|
||||
Added warning messages to fallback behavior to help identify if callbacks are not being provided properly (though this should not happen under normal operation).
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Sheet Height Priority Order
|
||||
The `activeSheetHeight` calculation follows this priority:
|
||||
1. Add sheet height (highest priority)
|
||||
2. Edit sheet height
|
||||
3. Navigation sheet height
|
||||
4. Tag sheet height (lowest priority - used for both node tags and suspected locations)
|
||||
|
||||
This ensures that session-based sheets (add/edit) always take precedence over informational sheets (tag/suspected location).
|
||||
|
||||
### Debugging Output
|
||||
When debugging is enabled, you'll see console output like:
|
||||
```
|
||||
[MeasuredSheet-NodeTag] Height changed: 0.0 -> 320.0
|
||||
[SheetCoordinator] Updating tag sheet height: 0.0 -> 364.0
|
||||
[SheetCoordinator] Active sheet height: 364.0 (add: 0.0, edit: 0.0, nav: 0.0, tag: 364.0)
|
||||
```
|
||||
|
||||
This helps trace the height measurement and coordination flow.
|
||||
|
||||
### SheetAwareMap Behavior
|
||||
The `SheetAwareMap` widget:
|
||||
- Moves the map up by `sheetHeight` pixels (`top: -sheetHeight`)
|
||||
- Extends the map rendering area by the same amount (`height: availableHeight + sheetHeight`)
|
||||
- This keeps the visual center in the middle of the area above the sheet
|
||||
- Uses smooth animation (300ms duration with `Curves.easeOut`)
|
||||
|
||||
## Files Modified
|
||||
|
||||
### Core Fix
|
||||
- `lib/screens/home_screen.dart` - Fixed race condition in `_openEditNodeSheet()`
|
||||
|
||||
### Enhanced Debugging
|
||||
- `lib/widgets/measured_sheet.dart` - Added debug labels and logging
|
||||
- `lib/screens/coordinators/sheet_coordinator.dart` - Added debug logging for height coordination
|
||||
- `lib/widgets/map/node_markers.dart` - Enhanced fallback robustness
|
||||
- `lib/widgets/map/suspected_location_markers.dart` - Enhanced fallback robustness
|
||||
|
||||
### Version & Release
|
||||
- `pubspec.yaml` - Updated version to 1.8.2+32
|
||||
- `assets/changelog.json` - Added v1.8.2 changelog entry
|
||||
|
||||
## Expected Behavior After Fix
|
||||
|
||||
### Node Tag Sheets
|
||||
1. Tap a surveillance device marker
|
||||
2. Tag sheet opens with smooth animation
|
||||
3. **Map shifts up so the device marker appears in the center of the visible area above the sheet**
|
||||
4. Tap "Edit" button
|
||||
5. Transition to edit sheet is smooth without map bounce
|
||||
6. Map remains properly positioned during edit session
|
||||
|
||||
### Suspected Location Sheets
|
||||
1. Tap a suspected location marker (yellow diamond)
|
||||
2. Sheet opens with smooth animation
|
||||
3. **Map shifts up so the suspected location appears in the center of the visible area above the sheet**
|
||||
4. Tap "Close"
|
||||
5. Map returns to original position with smooth animation
|
||||
|
||||
### Consistency
|
||||
Both tag sheets now behave identically to the add/edit node sheets in terms of map positioning.
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
### Basic Functionality
|
||||
1. **Node tag sheets**: Tap various surveillance device markers and verify map positioning
|
||||
2. **Suspected location sheets**: Tap suspected location markers and verify map positioning
|
||||
3. **Sheet transitions**: Open tag sheet → tap Edit → verify smooth transition without bounce
|
||||
4. **Different devices**: Test on both phones and tablets in portrait/landscape
|
||||
5. **Different sheet heights**: Test with nodes having many tags vs few tags
|
||||
|
||||
### Edge Cases
|
||||
1. **Quick transitions**: Rapidly tap Edit button to test race condition fix
|
||||
2. **Orientation changes**: Rotate device while sheets are open
|
||||
3. **Background/foreground**: Send app to background and return
|
||||
4. **Memory pressure**: Test with multiple apps running
|
||||
|
||||
### Debug Console Monitoring
|
||||
Monitor console output for:
|
||||
- Height measurement logging from `MeasuredSheet-*` components
|
||||
- Height coordination logging from `SheetCoordinator`
|
||||
- Any warning messages from fallback behavior (should not appear)
|
||||
|
||||
## Brutalist Code Principles Applied
|
||||
|
||||
### 1. Simple, Explicit Solution
|
||||
- Fixed the race condition with one clear line: set the flag before the operation that depends on it
|
||||
- No complex state machine or coordination logic
|
||||
|
||||
### 2. Enhanced Debugging Without Complexity
|
||||
- Added simple debug labels and logging
|
||||
- Minimal overhead, easy to enable/disable
|
||||
- Helps troubleshoot without changing behavior
|
||||
|
||||
### 3. Robust Fallbacks
|
||||
- Enhanced existing fallback behavior with warning messages
|
||||
- Maintains functionality even if something goes wrong
|
||||
- Clear indication in logs if fallback is used
|
||||
|
||||
### 4. Consistent Pattern Application
|
||||
- All MeasuredSheet instances now have debug labels
|
||||
- All sheet types follow the same coordination pattern
|
||||
- Uniform debugging approach across components
|
||||
|
||||
This fix maintains the project's brutalist philosophy by solving the core problem simply and directly while adding appropriate safeguards and debugging capabilities.
|
||||
69
V1.8.3_NODE_LIMIT_INDICATOR_FIX.md
Normal file
69
V1.8.3_NODE_LIMIT_INDICATOR_FIX.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# V1.8.3 Node Limit Indicator Fix
|
||||
|
||||
## Problem
|
||||
The node limit indicator would disappear when the navigation sheet opened during search/routing, particularly noticeable on Android. The indicator would appear correctly when just the search bar showed, but disappear when the navigation sheet auto-opened.
|
||||
|
||||
## Root Cause
|
||||
The issue was in the **map positioning architecture**, specifically with `SheetAwareMap`. Here's what happens:
|
||||
|
||||
1. **Search activated**: Search bar appears → node limit indicator shifts down 60px (works correctly)
|
||||
2. **Navigation sheet opens**: Navigation sheet auto-opens → `sheetHeight` changes from 0 to ~300px
|
||||
3. **Map repositioning**: `SheetAwareMap` uses `AnimatedPositioned` with `top: -sheetHeight` to move the entire map up
|
||||
4. **Indicator disappears**: The node limit indicator, positioned at `top: 8.0 + searchBarOffset`, gets moved up by 300px along with the map, placing it off-screen
|
||||
|
||||
The indicators were positioned relative to the map's coordinate system, but when the sheet opened, the entire map (including indicators) was moved up by the sheet height to keep the center visible above the sheet.
|
||||
|
||||
## Solution
|
||||
**Brutalist fix**: Move the node limit indicator out of the map coordinate system and into screen coordinates alongside other UI overlays.
|
||||
|
||||
### Files Changed
|
||||
- **map_view.dart**: Moved node limit indicator from inside SheetAwareMap to main Stack
|
||||
- **pubspec.yaml**: Version bump to 1.8.3+33
|
||||
- **changelog.json**: Added release notes
|
||||
|
||||
### Architecture Changes
|
||||
```dart
|
||||
// BEFORE - mixed coordinate systems (confusing!)
|
||||
return Stack([
|
||||
SheetAwareMap( // Map coordinates
|
||||
child: FlutterMap([
|
||||
cameraLayers: Stack([
|
||||
NodeLimitIndicator(...) // ❌ Map coordinates (moves with map)
|
||||
])
|
||||
])
|
||||
),
|
||||
NetworkStatusIndicator(...), // ✅ Screen coordinates (fixed to screen)
|
||||
]);
|
||||
|
||||
// AFTER - consistent coordinate system (clean!)
|
||||
return Stack([
|
||||
SheetAwareMap( // Map coordinates
|
||||
child: FlutterMap([
|
||||
cameraLayers: Stack([
|
||||
// Only map data (nodes, overlays) - no UI indicators
|
||||
])
|
||||
])
|
||||
),
|
||||
NodeLimitIndicator(...), // ✅ Screen coordinates (fixed to screen)
|
||||
NetworkStatusIndicator(...), // ✅ Screen coordinates (fixed to screen)
|
||||
]);
|
||||
```
|
||||
|
||||
## Architecture Insight
|
||||
The fix revealed a **mixed coordinate system anti-pattern**. All UI overlays (compass, search box, zoom buttons, indicators) should use screen coordinates for consistency. Only map data (nodes, overlays, FOV cones) should be in map coordinates.
|
||||
|
||||
## Result
|
||||
- Node limit indicator stays visible when navigation sheets open
|
||||
- Network status indicator also fixed for consistency
|
||||
- Indicators maintain correct screen position during all sheet transitions
|
||||
- Consistent behavior across iOS and Android
|
||||
|
||||
## Testing Notes
|
||||
To test this fix:
|
||||
1. Start app and wait for nodes to load (node limit indicator should appear if >max nodes)
|
||||
2. Tap search button → search bar appears, indicator shifts down 60px
|
||||
3. Navigation sheet auto-opens → indicator stays visible in screen position (no longer affected by map movement)
|
||||
4. Cancel search → indicator returns to original position
|
||||
5. Repeat workflow → should work reliably every time
|
||||
|
||||
The fix ensures indicators stay in their intended screen positions using consistent coordinate system architecture.
|
||||
@@ -1,4 +1,17 @@
|
||||
{
|
||||
"1.8.3": {
|
||||
"content": [
|
||||
"• Fixed node limit indicator disappearing when navigation sheet opens during search/routing",
|
||||
"• Improved indicator architecture - moved node limit indicator to screen coordinates for consistency with other UI overlays"
|
||||
]
|
||||
},
|
||||
"1.8.2": {
|
||||
"content": [
|
||||
"• Fixed map positioning for node tags and suspected location sheets - map now correctly centers above sheet when opened",
|
||||
"• Improved sheet transition coordination - prevents map bounce when transitioning from tag sheet to edit sheet",
|
||||
"• Enhanced debugging for sheet height measurement and coordination"
|
||||
]
|
||||
},
|
||||
"1.8.0": {
|
||||
"content": [
|
||||
"• Better performance and reduced memory usage when using suspected location data by using a database"
|
||||
|
||||
@@ -239,12 +239,14 @@ class SheetCoordinator {
|
||||
|
||||
/// Update tag sheet height (called externally)
|
||||
void updateTagSheetHeight(double height, VoidCallback onStateChanged) {
|
||||
debugPrint('[SheetCoordinator] Updating tag sheet height: $_tagSheetHeight -> $height');
|
||||
_tagSheetHeight = height;
|
||||
onStateChanged();
|
||||
}
|
||||
|
||||
/// Reset tag sheet height
|
||||
void resetTagSheetHeight(VoidCallback onStateChanged) {
|
||||
debugPrint('[SheetCoordinator] Resetting tag sheet height from: $_tagSheetHeight');
|
||||
_tagSheetHeight = 0.0;
|
||||
onStateChanged();
|
||||
}
|
||||
|
||||
@@ -114,6 +114,9 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
void _openEditNodeSheet() {
|
||||
// Set transition flag BEFORE closing tag sheet to prevent map bounce
|
||||
_sheetCoordinator.setTransitioningToEdit(true);
|
||||
|
||||
// Close any existing tag sheet first
|
||||
if (_sheetCoordinator.tagSheetHeight > 0) {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
@@ -42,6 +42,9 @@ class _NodeMapMarkerState extends State<NodeMapMarker> {
|
||||
if (widget.onNodeTap != null) {
|
||||
widget.onNodeTap!(widget.node);
|
||||
} else {
|
||||
// Fallback: This should not happen if callbacks are properly provided,
|
||||
// but if it does, at least open the sheet (without map coordination)
|
||||
debugPrint('[NodeMapMarker] Warning: onNodeTap callback not provided, using fallback');
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (_) => NodeTagSheet(node: widget.node),
|
||||
|
||||
@@ -40,6 +40,9 @@ class _SuspectedLocationMapMarkerState extends State<SuspectedLocationMapMarker>
|
||||
if (widget.onLocationTap != null) {
|
||||
widget.onLocationTap!(widget.location);
|
||||
} else {
|
||||
// Fallback: This should not happen if callbacks are properly provided,
|
||||
// but if it does, at least open the sheet (without map coordination)
|
||||
debugPrint('[SuspectedLocationMapMarker] Warning: onLocationTap callback not provided, using fallback');
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (_) => SuspectedLocationSheet(location: widget.location),
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:flutter_map_animations/flutter_map_animations.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../app_state.dart';
|
||||
import '../app_state.dart' show AppState, FollowMeMode, UploadMode;
|
||||
import '../services/offline_area_service.dart';
|
||||
import '../services/network_status.dart';
|
||||
import '../services/prefetch_area_service.dart';
|
||||
@@ -28,7 +28,6 @@ import 'network_status_indicator.dart';
|
||||
import 'node_limit_indicator.dart';
|
||||
import 'proximity_alert_banner.dart';
|
||||
import '../dev_config.dart';
|
||||
import '../app_state.dart' show FollowMeMode;
|
||||
import '../services/proximity_alert_service.dart';
|
||||
import 'sheet_aware_map.dart';
|
||||
|
||||
@@ -249,6 +248,11 @@ class MapViewState extends State<MapView> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Calculate search bar offset for screen-positioned indicators
|
||||
double _calculateScreenIndicatorSearchOffset(AppState appState) {
|
||||
return (!appState.offlineMode && appState.isInSearchMode) ? 60.0 : 0.0;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant MapView oldWidget) {
|
||||
@@ -370,23 +374,6 @@ class MapViewState extends State<MapView> {
|
||||
children: [
|
||||
...overlayLayers,
|
||||
markerLayer,
|
||||
|
||||
// Node limit indicator (top-left) - shown when limit is active
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final appState = context.read<AppState>();
|
||||
// Add search bar offset when search bar is visible
|
||||
final searchBarOffset = (!appState.offlineMode && appState.isInSearchMode) ? 60.0 : 0.0;
|
||||
|
||||
return NodeLimitIndicator(
|
||||
isActive: nodeData.isLimitActive,
|
||||
renderedCount: nodeData.nodesToRender.length,
|
||||
totalCount: nodeData.validNodesCount,
|
||||
top: 8.0 + searchBarOffset,
|
||||
left: 8.0,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -540,12 +527,28 @@ class MapViewState extends State<MapView> {
|
||||
onSearchPressed: widget.onSearchPressed,
|
||||
),
|
||||
|
||||
// Node limit indicator (top-left) - shown when limit is active
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final appState = context.watch<AppState>();
|
||||
final searchBarOffset = _calculateScreenIndicatorSearchOffset(appState);
|
||||
|
||||
return NodeLimitIndicator(
|
||||
isActive: nodeData.isLimitActive,
|
||||
renderedCount: nodeData.nodesToRender.length,
|
||||
totalCount: nodeData.validNodesCount,
|
||||
top: 8.0 + searchBarOffset,
|
||||
left: 8.0,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
// Network status indicator (top-left) - conditionally shown
|
||||
if (appState.networkStatusIndicatorEnabled)
|
||||
Builder(
|
||||
builder: (context) {
|
||||
// Calculate position based on node limit indicator presence and search bar
|
||||
final searchBarOffset = (!appState.offlineMode && appState.isInSearchMode) ? 60.0 : 0.0;
|
||||
final appState = context.watch<AppState>();
|
||||
final searchBarOffset = _calculateScreenIndicatorSearchOffset(appState);
|
||||
final nodeLimitOffset = nodeData.isLimitActive ? 48.0 : 0.0; // Height of node limit indicator + spacing
|
||||
|
||||
return NetworkStatusIndicator(
|
||||
|
||||
@@ -29,6 +29,8 @@ class SheetAwareMap extends StatelessWidget {
|
||||
// Use the actual available height from constraints, not full screen height
|
||||
final availableHeight = constraints.maxHeight;
|
||||
|
||||
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
AnimatedPositioned(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: deflockapp
|
||||
description: Map public surveillance infrastructure with OpenStreetMap
|
||||
publish_to: "none"
|
||||
version: 1.8.1+31 # The thing after the + is the version code, incremented with each release
|
||||
version: 2.0.0+33 # The thing after the + is the version code, incremented with each release
|
||||
|
||||
environment:
|
||||
sdk: ">=3.5.0 <4.0.0" # oauth2_client 4.x needs Dart 3.5+
|
||||
|
||||
Reference in New Issue
Block a user