From bb3d398c9ca6cd881751f5f4a54e9030c45c52d5 Mon Sep 17 00:00:00 2001 From: stopflock Date: Tue, 2 Dec 2025 21:17:07 -0600 Subject: [PATCH] More camera -> node --- REFACTORING_ROUND_1_SUMMARY.md | 19 ++++++++ lib/app_state.dart | 4 +- lib/services/prefetch_area_service.dart | 4 +- lib/state/upload_queue_state.dart | 18 ++++---- lib/widgets/map/map_data_manager.dart | 4 +- lib/widgets/map/marker_layer_builder.dart | 6 +-- ...{camera_markers.dart => node_markers.dart} | 30 ++++++------ ...ller.dart => node_refresh_controller.dart} | 46 +++++++++---------- lib/widgets/map_view.dart | 20 ++++---- ...che.dart => node_provider_with_cache.dart} | 12 ++--- 10 files changed, 91 insertions(+), 72 deletions(-) rename lib/widgets/map/{camera_markers.dart => node_markers.dart} (84%) rename lib/widgets/map/{camera_refresh_controller.dart => node_refresh_controller.dart} (67%) rename lib/widgets/{camera_provider_with_cache.dart => node_provider_with_cache.dart} (93%) diff --git a/REFACTORING_ROUND_1_SUMMARY.md b/REFACTORING_ROUND_1_SUMMARY.md index 708039d..182b7c2 100644 --- a/REFACTORING_ROUND_1_SUMMARY.md +++ b/REFACTORING_ROUND_1_SUMMARY.md @@ -10,6 +10,14 @@ Successfully refactored the largest file in the codebase (MapView, 880 lines) by - **Total new code**: 4 new focused manager classes (351 lines total) - **Net complexity reduction**: Converted monolithic widget into clean orchestrator + specialized managers +### Step 1.5: Terminology Update (Camera → Node) +- **Renamed 3 core files** to use "node" instead of "camera" terminology +- **Updated all class names** to reflect current multi-device scope (not just cameras) +- **Updated all method names** and comments for consistency +- **Updated all imports/references** across the entire codebase +- **Benefits**: Consistent terminology that reflects the app's expansion beyond just cameras to all surveillance devices +======= + ### New Manager Classes Created #### 1. MapDataManager (`lib/widgets/map/map_data_manager.dart`) - 92 lines @@ -158,9 +166,20 @@ Expected reduction: ~400-500 lines - `lib/widgets/map/map_interaction_manager.dart` - `lib/widgets/map/marker_layer_builder.dart` - `lib/widgets/map/overlay_layer_builder.dart` +- `lib/widgets/node_provider_with_cache.dart` (renamed from camera_provider_with_cache.dart) +- `lib/widgets/map/node_refresh_controller.dart` (renamed from camera_refresh_controller.dart) +- `lib/widgets/map/node_markers.dart` (renamed from camera_markers.dart) ### Modified Files - `lib/widgets/map_view.dart` (880 → 572 lines) +- `lib/app_state.dart` (updated imports and references) +- `lib/state/upload_queue_state.dart` (updated all references) +- `lib/services/prefetch_area_service.dart` (updated references) + +### Removed Files +- `lib/widgets/camera_provider_with_cache.dart` (renamed to node_provider_with_cache.dart) +- `lib/widgets/map/camera_refresh_controller.dart` (renamed to node_refresh_controller.dart) +- `lib/widgets/map/camera_markers.dart` (renamed to node_markers.dart) ### Total Impact - **Lines removed**: 308 from MapView diff --git a/lib/app_state.dart b/lib/app_state.dart index 8b8d11f..c5508f7 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -18,7 +18,7 @@ import 'services/node_cache.dart'; import 'services/tile_preview_service.dart'; import 'services/changelog_service.dart'; import 'services/operator_profile_service.dart'; -import 'widgets/camera_provider_with_cache.dart'; +import 'widgets/node_provider_with_cache.dart'; import 'services/profile_service.dart'; import 'widgets/proximity_warning_dialog.dart'; import 'widgets/reauth_messages_dialog.dart'; @@ -214,7 +214,7 @@ class AppState extends ChangeNotifier { await _authState.init(_settingsState.uploadMode); // Set up callback to repopulate pending nodes after cache clears - CameraProviderWithCache.instance.setOnCacheClearedCallback(() { + NodeProviderWithCache.instance.setOnCacheClearedCallback(() { _uploadQueueState.repopulateCacheFromQueue(); }); diff --git a/lib/services/prefetch_area_service.dart b/lib/services/prefetch_area_service.dart index 13168f6..d442caa 100644 --- a/lib/services/prefetch_area_service.dart +++ b/lib/services/prefetch_area_service.dart @@ -10,7 +10,7 @@ import '../dev_config.dart'; import 'map_data_submodules/nodes_from_overpass.dart'; import 'node_cache.dart'; import 'network_status.dart'; -import '../widgets/camera_provider_with_cache.dart'; +import '../widgets/node_provider_with_cache.dart'; /// Manages pre-fetching larger areas to reduce Overpass API calls. /// Uses zoom level 10 areas and automatically splits if hitting node limits. @@ -143,7 +143,7 @@ class PrefetchAreaService { // We just need to handle the successful result here // Notify UI that cache has been updated with fresh data - CameraProviderWithCache.instance.refreshDisplay(); + NodeProviderWithCache.instance.refreshDisplay(); } catch (e) { debugPrint('[PrefetchAreaService] Pre-fetch failed: $e'); diff --git a/lib/state/upload_queue_state.dart b/lib/state/upload_queue_state.dart index 541bd16..ce69548 100644 --- a/lib/state/upload_queue_state.dart +++ b/lib/state/upload_queue_state.dart @@ -9,7 +9,7 @@ import '../models/osm_node.dart'; import '../models/node_profile.dart'; import '../services/node_cache.dart'; import '../services/uploader.dart'; -import '../widgets/camera_provider_with_cache.dart'; +import '../widgets/node_provider_with_cache.dart'; import 'settings_state.dart'; import 'session_state.dart'; @@ -113,7 +113,7 @@ class UploadQueueState extends ChangeNotifier { _saveQueue(); // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); } } @@ -150,7 +150,7 @@ class UploadQueueState extends ChangeNotifier { NodeCache.instance.addOrUpdate([tempNode]); // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); notifyListeners(); } @@ -238,7 +238,7 @@ class UploadQueueState extends ChangeNotifier { NodeCache.instance.addOrUpdate([originalNode, editedNode]); } // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); notifyListeners(); } @@ -269,7 +269,7 @@ class UploadQueueState extends ChangeNotifier { NodeCache.instance.addOrUpdate([nodeWithDeletionTag]); // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); notifyListeners(); } @@ -284,7 +284,7 @@ class UploadQueueState extends ChangeNotifier { _saveQueue(); // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); notifyListeners(); } @@ -296,7 +296,7 @@ class UploadQueueState extends ChangeNotifier { _saveQueue(); // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); notifyListeners(); } @@ -665,7 +665,7 @@ class UploadQueueState extends ChangeNotifier { } // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); } // Handle successful deletion by removing the node from cache @@ -675,7 +675,7 @@ class UploadQueueState extends ChangeNotifier { NodeCache.instance.removeNodeById(item.originalNodeId!); // Notify node provider to update the map - CameraProviderWithCache.instance.notifyListeners(); + NodeProviderWithCache.instance.notifyListeners(); } } diff --git a/lib/widgets/map/map_data_manager.dart b/lib/widgets/map/map_data_manager.dart index 740897c..9a660bf 100644 --- a/lib/widgets/map/map_data_manager.dart +++ b/lib/widgets/map/map_data_manager.dart @@ -5,7 +5,7 @@ import 'package:latlong2/latlong.dart'; import '../../models/osm_node.dart'; import '../../app_state.dart'; -import '../camera_provider_with_cache.dart'; +import '../node_provider_with_cache.dart'; import '../../dev_config.dart'; /// Manages data fetching, filtering, and node limit logic for the map. @@ -41,7 +41,7 @@ class MapDataManager { if (currentZoom >= minZoom) { // Above minimum zoom - get cached nodes directly (no Provider needed) allNodes = (mapBounds != null) - ? CameraProviderWithCache.instance.getCachedNodesForBounds(mapBounds) + ? NodeProviderWithCache.instance.getCachedNodesForBounds(mapBounds) : []; // Filter out invalid coordinates before applying limit diff --git a/lib/widgets/map/marker_layer_builder.dart b/lib/widgets/map/marker_layer_builder.dart index 21b1941..c51bfcb 100644 --- a/lib/widgets/map/marker_layer_builder.dart +++ b/lib/widgets/map/marker_layer_builder.dart @@ -10,7 +10,7 @@ import '../../state/session_state.dart'; import '../../dev_config.dart'; import '../camera_icon.dart'; import '../provisional_pin.dart'; -import 'camera_markers.dart'; +import 'node_markers.dart'; import 'suspected_location_markers.dart'; /// Enumeration for different pin types in navigation @@ -65,8 +65,8 @@ class MarkerLayerBuilder { // Determine if we should dim node markers (when suspected location is selected) final shouldDimNodes = appState.selectedSuspectedLocation != null; - final markers = CameraMarkersBuilder.buildCameraMarkers( - cameras: nodesToRender, + final markers = NodeMarkersBuilder.buildNodeMarkers( + nodes: nodesToRender, mapController: mapController.mapController, userLocation: userLocation, selectedNodeId: selectedNodeId, diff --git a/lib/widgets/map/camera_markers.dart b/lib/widgets/map/node_markers.dart similarity index 84% rename from lib/widgets/map/camera_markers.dart rename to lib/widgets/map/node_markers.dart index 031f42d..237d722 100644 --- a/lib/widgets/map/camera_markers.dart +++ b/lib/widgets/map/node_markers.dart @@ -8,13 +8,13 @@ import '../../models/osm_node.dart'; import '../node_tag_sheet.dart'; import '../camera_icon.dart'; -/// Smart marker widget for camera with single/double tap distinction -class CameraMapMarker extends StatefulWidget { +/// Smart marker widget for surveillance node with single/double tap distinction +class NodeMapMarker extends StatefulWidget { final OsmNode node; final MapController mapController; final void Function(OsmNode)? onNodeTap; - const CameraMapMarker({ + const NodeMapMarker({ required this.node, required this.mapController, this.onNodeTap, @@ -22,10 +22,10 @@ class CameraMapMarker extends StatefulWidget { }) : super(key: key); @override - State createState() => _CameraMapMarkerState(); + State createState() => _NodeMapMarkerState(); } -class _CameraMapMarkerState extends State { +class _NodeMapMarkerState extends State { Timer? _tapTimer; // From dev_config.dart for build-time parameters static const Duration tapTimeout = kMarkerTapTimeout; @@ -60,7 +60,7 @@ class _CameraMapMarkerState extends State { @override Widget build(BuildContext context) { - // Check camera state + // Check node state final isPendingUpload = widget.node.tags.containsKey('_pending_upload') && widget.node.tags['_pending_upload'] == 'true'; final isPendingEdit = widget.node.tags.containsKey('_pending_edit') && @@ -87,10 +87,10 @@ class _CameraMapMarkerState extends State { } } -/// Helper class to build marker layers for cameras and user location -class CameraMarkersBuilder { - static List buildCameraMarkers({ - required List cameras, +/// Helper class to build marker layers for surveillance nodes and user location +class NodeMarkersBuilder { + static List buildNodeMarkers({ + required List nodes, required MapController mapController, LatLng? userLocation, int? selectedNodeId, @@ -98,9 +98,9 @@ class CameraMarkersBuilder { bool shouldDim = false, }) { final markers = [ - // Camera markers - ...cameras - .where(_isValidCameraCoordinate) + // Node markers + ...nodes + .where(_isValidNodeCoordinate) .map((n) { // Check if this node should be highlighted (selected) or dimmed final isSelected = selectedNodeId == n.id; @@ -112,7 +112,7 @@ class CameraMarkersBuilder { height: kNodeIconDiameter, child: Opacity( opacity: shouldDimNode ? 0.5 : 1.0, - child: CameraMapMarker( + child: NodeMapMarker( node: n, mapController: mapController, onNodeTap: onNodeTap, @@ -134,7 +134,7 @@ class CameraMarkersBuilder { return markers; } - static bool _isValidCameraCoordinate(OsmNode node) { + static bool _isValidNodeCoordinate(OsmNode node) { return (node.coord.latitude != 0 || node.coord.longitude != 0) && node.coord.latitude.abs() <= 90 && node.coord.longitude.abs() <= 180; diff --git a/lib/widgets/map/camera_refresh_controller.dart b/lib/widgets/map/node_refresh_controller.dart similarity index 67% rename from lib/widgets/map/camera_refresh_controller.dart rename to lib/widgets/map/node_refresh_controller.dart index 381eefa..3c525a5 100644 --- a/lib/widgets/map/camera_refresh_controller.dart +++ b/lib/widgets/map/node_refresh_controller.dart @@ -6,31 +6,31 @@ import 'package:latlong2/latlong.dart'; import '../../models/node_profile.dart'; import '../../app_state.dart' show UploadMode; import '../../services/prefetch_area_service.dart'; -import '../camera_provider_with_cache.dart'; +import '../node_provider_with_cache.dart'; import '../../dev_config.dart'; -/// Manages camera data refreshing, profile change detection, and camera cache operations. -/// Handles debounced camera fetching and profile-based cache invalidation. -class CameraRefreshController { - late final CameraProviderWithCache _cameraProvider; +/// Manages node data refreshing, profile change detection, and node cache operations. +/// Handles debounced node fetching and profile-based cache invalidation. +class NodeRefreshController { + late final NodeProviderWithCache _nodeProvider; List? _lastEnabledProfiles; - VoidCallback? _onCamerasUpdated; + VoidCallback? _onNodesUpdated; - /// Initialize the camera refresh controller - void initialize({required VoidCallback onCamerasUpdated}) { - _cameraProvider = CameraProviderWithCache.instance; - _onCamerasUpdated = onCamerasUpdated; - _cameraProvider.addListener(_onCamerasUpdated!); + /// Initialize the node refresh controller + void initialize({required VoidCallback onNodesUpdated}) { + _nodeProvider = NodeProviderWithCache.instance; + _onNodesUpdated = onNodesUpdated; + _nodeProvider.addListener(_onNodesUpdated!); } /// Dispose of resources and listeners void dispose() { - if (_onCamerasUpdated != null) { - _cameraProvider.removeListener(_onCamerasUpdated!); + if (_onNodesUpdated != null) { + _nodeProvider.removeListener(_onNodesUpdated!); } } - /// Check if camera profiles changed and handle cache clearing if needed. + /// Check if node profiles changed and handle cache clearing if needed. /// Returns true if profiles changed (triggering a refresh). bool checkAndHandleProfileChanges({ required List currentEnabledProfiles, @@ -42,13 +42,13 @@ class CameraRefreshController { // Handle profile change with cache clearing and refresh WidgetsBinding.instance.addPostFrameCallback((_) { - // Clear camera cache to ensure fresh data for new profile combination - _cameraProvider.clearCache(); + // Clear node cache to ensure fresh data for new profile combination + _nodeProvider.clearCache(); // Clear pre-fetch area since profiles changed PrefetchAreaService().clearPreFetchedArea(); // Force display refresh first (for immediate UI update) - _cameraProvider.refreshDisplay(); - // Notify that profiles changed (triggers camera refresh) + _nodeProvider.refreshDisplay(); + // Notify that profiles changed (triggers node refresh) onProfilesChanged(); }); @@ -57,8 +57,8 @@ class CameraRefreshController { return false; } - /// Refresh cameras from provider for the current map view - void refreshCamerasFromProvider({ + /// Refresh nodes from provider for the current map view + void refreshNodesFromProvider({ required AnimatedMapController controller, required List enabledProfiles, required UploadMode uploadMode, @@ -85,15 +85,15 @@ class CameraRefreshController { return; } - _cameraProvider.fetchAndUpdate( + _nodeProvider.fetchAndUpdate( bounds: bounds, profiles: enabledProfiles, uploadMode: uploadMode, ); } - /// Get the camera provider instance for external access - CameraProviderWithCache get cameraProvider => _cameraProvider; + /// Get the node provider instance for external access + NodeProviderWithCache get nodeProvider => _nodeProvider; /// Helper to check if two profile lists are equal by comparing IDs bool _profileListsEqual(List list1, List list2) { diff --git a/lib/widgets/map_view.dart b/lib/widgets/map_view.dart index 4a0f886..ac970b6 100644 --- a/lib/widgets/map_view.dart +++ b/lib/widgets/map_view.dart @@ -14,11 +14,11 @@ import '../models/suspected_location.dart'; import '../models/tile_provider.dart'; import '../state/session_state.dart'; import 'debouncer.dart'; -import 'camera_provider_with_cache.dart'; +import 'node_provider_with_cache.dart'; import 'map/map_overlays.dart'; import 'map/map_position_manager.dart'; import 'map/tile_layer_manager.dart'; -import 'map/camera_refresh_controller.dart'; +import 'map/node_refresh_controller.dart'; import 'map/gps_controller.dart'; import 'map/map_data_manager.dart'; import 'map/map_interaction_manager.dart'; @@ -69,7 +69,7 @@ class MapViewState extends State { late final MapPositionManager _positionManager; late final TileLayerManager _tileManager; - late final CameraRefreshController _cameraController; + late final NodeRefreshController _nodeController; late final GpsController _gpsController; late final MapDataManager _dataManager; late final MapInteractionManager _interactionManager; @@ -93,8 +93,8 @@ class MapViewState extends State { _positionManager = MapPositionManager(); _tileManager = TileLayerManager(); _tileManager.initialize(); - _cameraController = CameraRefreshController(); - _cameraController.initialize(onCamerasUpdated: _onNodesUpdated); + _nodeController = NodeRefreshController(); + _nodeController.initialize(onNodesUpdated: _onNodesUpdated); _gpsController = GpsController(); _dataManager = MapDataManager(); _interactionManager = MapInteractionManager(); @@ -167,7 +167,7 @@ class MapViewState extends State { return []; } return mapBounds != null - ? CameraProviderWithCache.instance.getCachedNodesForBounds(mapBounds) + ? NodeProviderWithCache.instance.getCachedNodesForBounds(mapBounds) : []; } catch (e) { debugPrint('[MapView] Could not get nearby nodes: $e'); @@ -209,7 +209,7 @@ class MapViewState extends State { _cameraDebounce.dispose(); _tileDebounce.dispose(); _mapPositionDebounce.dispose(); - _cameraController.dispose(); + _nodeController.dispose(); _tileManager.dispose(); _gpsController.dispose(); PrefetchAreaService().dispose(); @@ -241,7 +241,7 @@ class MapViewState extends State { void _refreshNodesFromProvider() { final appState = context.read(); - _cameraController.refreshCamerasFromProvider( + _nodeController.refreshNodesFromProvider( controller: _controller, enabledProfiles: appState.enabledProfiles, uploadMode: appState.uploadMode, @@ -273,8 +273,8 @@ class MapViewState extends State { final session = appState.session; final editSession = appState.editSession; - // Check if enabled profiles changed and refresh cameras if needed - _cameraController.checkAndHandleProfileChanges( + // Check if enabled profiles changed and refresh nodes if needed + _nodeController.checkAndHandleProfileChanges( currentEnabledProfiles: appState.enabledProfiles, onProfilesChanged: _refreshNodesFromProvider, ); diff --git a/lib/widgets/camera_provider_with_cache.dart b/lib/widgets/node_provider_with_cache.dart similarity index 93% rename from lib/widgets/camera_provider_with_cache.dart rename to lib/widgets/node_provider_with_cache.dart index 07bcef1..560dd3b 100644 --- a/lib/widgets/camera_provider_with_cache.dart +++ b/lib/widgets/node_provider_with_cache.dart @@ -12,10 +12,10 @@ import '../app_state.dart'; /// Provides surveillance nodes for a map view, using an in-memory cache and optionally /// merging in new results from Overpass via MapDataProvider when not offline. -class CameraProviderWithCache extends ChangeNotifier { - static final CameraProviderWithCache instance = CameraProviderWithCache._internal(); - factory CameraProviderWithCache() => instance; - CameraProviderWithCache._internal(); +class NodeProviderWithCache extends ChangeNotifier { + static final NodeProviderWithCache instance = NodeProviderWithCache._internal(); + factory NodeProviderWithCache() => instance; + NodeProviderWithCache._internal(); Timer? _debounceTimer; @@ -61,7 +61,7 @@ class CameraProviderWithCache extends ChangeNotifier { notifyListeners(); } } catch (e) { - debugPrint('[CameraProviderWithCache] Node fetch failed: $e'); + debugPrint('[NodeProviderWithCache] Node fetch failed: $e'); // Cache already holds whatever is available for the view } }); @@ -114,4 +114,4 @@ class CameraProviderWithCache extends ChangeNotifier { } return true; } -} +} \ No newline at end of file