pumaguard 21.post29__py3-none-any.whl → 21.post83__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. pumaguard/presets.py +1 -0
  2. pumaguard/pumaguard-ui/.last_build_id +1 -1
  3. pumaguard/pumaguard-ui/assets/NOTICES +621 -71
  4. pumaguard/pumaguard-ui/assets/fonts/MaterialIcons-Regular.otf +0 -0
  5. pumaguard/pumaguard-ui/flutter_bootstrap.js +1 -1
  6. pumaguard/pumaguard-ui/main.dart.js +28869 -28787
  7. pumaguard/web_routes/dhcp.py +311 -54
  8. pumaguard/web_routes/diagnostics.py +6 -0
  9. pumaguard/web_routes/settings.py +13 -0
  10. pumaguard/web_ui.py +29 -0
  11. {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/METADATA +1 -1
  12. pumaguard-21.post83.dist-info/RECORD +254 -0
  13. pumaguard-ui/.gitignore +48 -0
  14. pumaguard-ui/.metadata +45 -0
  15. pumaguard-ui/API_REFERENCE.md +717 -0
  16. pumaguard-ui/LICENSE +201 -0
  17. pumaguard-ui/Makefile +36 -0
  18. pumaguard-ui/README.md +371 -0
  19. pumaguard-ui/UI_DEVELOPMENT_CONTEXT.md +427 -0
  20. pumaguard-ui/analysis_options.yaml +28 -0
  21. pumaguard-ui/android/.gitignore +14 -0
  22. pumaguard-ui/android/app/build.gradle.kts +44 -0
  23. pumaguard-ui/android/app/src/debug/AndroidManifest.xml +7 -0
  24. pumaguard-ui/android/app/src/main/AndroidManifest.xml +45 -0
  25. pumaguard-ui/android/app/src/main/kotlin/com/example/pumaguard_ui/MainActivity.kt +5 -0
  26. pumaguard-ui/android/app/src/main/res/drawable/launch_background.xml +12 -0
  27. pumaguard-ui/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  28. pumaguard-ui/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  29. pumaguard-ui/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  30. pumaguard-ui/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  31. pumaguard-ui/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  32. pumaguard-ui/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  33. pumaguard-ui/android/app/src/main/res/values/styles.xml +18 -0
  34. pumaguard-ui/android/app/src/main/res/values-night/styles.xml +18 -0
  35. pumaguard-ui/android/app/src/profile/AndroidManifest.xml +7 -0
  36. pumaguard-ui/android/build.gradle.kts +24 -0
  37. pumaguard-ui/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  38. pumaguard-ui/android/gradle.properties +2 -0
  39. pumaguard-ui/android/settings.gradle.kts +26 -0
  40. pumaguard-ui/fonts/README.md +38 -0
  41. pumaguard-ui/fonts/Roboto-Bold.ttf +0 -0
  42. pumaguard-ui/fonts/Roboto-Light.ttf +0 -0
  43. pumaguard-ui/fonts/Roboto-Medium.ttf +0 -0
  44. pumaguard-ui/fonts/Roboto-Regular.ttf +0 -0
  45. pumaguard-ui/fonts/RobotoMono-Bold.ttf +0 -0
  46. pumaguard-ui/fonts/RobotoMono-Medium.ttf +0 -0
  47. pumaguard-ui/fonts/RobotoMono-Regular.ttf +0 -0
  48. pumaguard-ui/fonts/download_fonts.sh +76 -0
  49. pumaguard-ui/ios/.gitignore +34 -0
  50. pumaguard-ui/ios/Flutter/AppFrameworkInfo.plist +26 -0
  51. pumaguard-ui/ios/Flutter/Debug.xcconfig +1 -0
  52. pumaguard-ui/ios/Flutter/Release.xcconfig +1 -0
  53. pumaguard-ui/ios/Runner/AppDelegate.swift +13 -0
  54. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +122 -0
  55. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +0 -0
  56. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +0 -0
  57. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +0 -0
  58. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +0 -0
  59. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +0 -0
  60. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +0 -0
  61. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +0 -0
  62. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +0 -0
  63. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +0 -0
  64. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +0 -0
  65. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +0 -0
  66. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +0 -0
  67. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +0 -0
  68. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +0 -0
  69. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +0 -0
  70. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +23 -0
  71. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
  72. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
  73. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
  74. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +5 -0
  75. pumaguard-ui/ios/Runner/Base.lproj/LaunchScreen.storyboard +37 -0
  76. pumaguard-ui/ios/Runner/Base.lproj/Main.storyboard +26 -0
  77. pumaguard-ui/ios/Runner/Info.plist +49 -0
  78. pumaguard-ui/ios/Runner/Runner-Bridging-Header.h +1 -0
  79. pumaguard-ui/ios/Runner.xcodeproj/project.pbxproj +616 -0
  80. pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  81. pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  82. pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  83. pumaguard-ui/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +101 -0
  84. pumaguard-ui/ios/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  85. pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  86. pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  87. pumaguard-ui/ios/RunnerTests/RunnerTests.swift +12 -0
  88. pumaguard-ui/lib/main.dart +56 -0
  89. pumaguard-ui/lib/models/camera.dart +45 -0
  90. pumaguard-ui/lib/models/plug.dart +45 -0
  91. pumaguard-ui/lib/models/settings.dart +112 -0
  92. pumaguard-ui/lib/models/status.dart +58 -0
  93. pumaguard-ui/lib/screens/directories_screen.dart +319 -0
  94. pumaguard-ui/lib/screens/home_screen.dart +545 -0
  95. pumaguard-ui/lib/screens/image_browser_screen.dart +1248 -0
  96. pumaguard-ui/lib/screens/server_discovery_screen.dart +390 -0
  97. pumaguard-ui/lib/screens/settings_screen.dart +1162 -0
  98. pumaguard-ui/lib/screens/wifi_settings_screen.dart +671 -0
  99. pumaguard-ui/lib/services/api_service.dart +717 -0
  100. pumaguard-ui/lib/services/camera_events_service.dart +195 -0
  101. pumaguard-ui/lib/services/mdns_service.dart +4 -0
  102. pumaguard-ui/lib/services/mdns_service_impl.dart +282 -0
  103. pumaguard-ui/lib/services/mdns_service_io.dart +1 -0
  104. pumaguard-ui/lib/services/mdns_service_web.dart +106 -0
  105. pumaguard-ui/lib/utils/download_helper.dart +2 -0
  106. pumaguard-ui/lib/utils/download_helper_stub.dart +6 -0
  107. pumaguard-ui/lib/utils/download_helper_web.dart +14 -0
  108. pumaguard-ui/lib/utils/platform_url.dart +10 -0
  109. pumaguard-ui/lib/utils/platform_url_stub.dart +11 -0
  110. pumaguard-ui/lib/utils/platform_url_web.dart +16 -0
  111. pumaguard-ui/linux/.gitignore +1 -0
  112. pumaguard-ui/linux/CMakeLists.txt +128 -0
  113. pumaguard-ui/linux/flutter/CMakeLists.txt +88 -0
  114. pumaguard-ui/linux/flutter/generated_plugin_registrant.cc +15 -0
  115. pumaguard-ui/linux/flutter/generated_plugin_registrant.h +15 -0
  116. pumaguard-ui/linux/flutter/generated_plugins.cmake +24 -0
  117. pumaguard-ui/linux/runner/CMakeLists.txt +26 -0
  118. pumaguard-ui/linux/runner/main.cc +6 -0
  119. pumaguard-ui/linux/runner/my_application.cc +148 -0
  120. pumaguard-ui/linux/runner/my_application.h +21 -0
  121. pumaguard-ui/macos/.gitignore +7 -0
  122. pumaguard-ui/macos/Flutter/Flutter-Debug.xcconfig +1 -0
  123. pumaguard-ui/macos/Flutter/Flutter-Release.xcconfig +1 -0
  124. pumaguard-ui/macos/Flutter/GeneratedPluginRegistrant.swift +16 -0
  125. pumaguard-ui/macos/Runner/AppDelegate.swift +13 -0
  126. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  127. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  128. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  129. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  130. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  131. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  132. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  133. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  134. pumaguard-ui/macos/Runner/Base.lproj/MainMenu.xib +343 -0
  135. pumaguard-ui/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  136. pumaguard-ui/macos/Runner/Configs/Debug.xcconfig +2 -0
  137. pumaguard-ui/macos/Runner/Configs/Release.xcconfig +2 -0
  138. pumaguard-ui/macos/Runner/Configs/Warnings.xcconfig +13 -0
  139. pumaguard-ui/macos/Runner/DebugProfile.entitlements +12 -0
  140. pumaguard-ui/macos/Runner/Info.plist +32 -0
  141. pumaguard-ui/macos/Runner/MainFlutterWindow.swift +15 -0
  142. pumaguard-ui/macos/Runner/Release.entitlements +8 -0
  143. pumaguard-ui/macos/Runner.xcodeproj/project.pbxproj +705 -0
  144. pumaguard-ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  145. pumaguard-ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  146. pumaguard-ui/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  147. pumaguard-ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  148. pumaguard-ui/macos/RunnerTests/RunnerTests.swift +12 -0
  149. pumaguard-ui/pubspec.lock +882 -0
  150. pumaguard-ui/pubspec.yaml +125 -0
  151. pumaguard-ui/test/models/camera_test.dart +515 -0
  152. pumaguard-ui/test/models/plug_test.dart +499 -0
  153. pumaguard-ui/test/models/settings_test.dart +903 -0
  154. pumaguard-ui/test/models/status_test.dart +707 -0
  155. pumaguard-ui/test/screens/image_browser_grouping_test.dart +555 -0
  156. pumaguard-ui/test/services/api_service_cameras_test.dart +580 -0
  157. pumaguard-ui/test/services/api_service_image_browser_test.dart +512 -0
  158. pumaguard-ui/test/widget_test.dart.skip +38 -0
  159. pumaguard-ui/web/favicon.png +0 -0
  160. pumaguard-ui/web/icons/Icon-192.png +0 -0
  161. pumaguard-ui/web/icons/Icon-512.png +0 -0
  162. pumaguard-ui/web/icons/Icon-maskable-192.png +0 -0
  163. pumaguard-ui/web/icons/Icon-maskable-512.png +0 -0
  164. pumaguard-ui/web/index.html +38 -0
  165. pumaguard-ui/web/manifest.json +35 -0
  166. pumaguard-ui/windows/.gitignore +17 -0
  167. pumaguard-ui/windows/CMakeLists.txt +108 -0
  168. pumaguard-ui/windows/flutter/CMakeLists.txt +109 -0
  169. pumaguard-ui/windows/flutter/generated_plugin_registrant.cc +14 -0
  170. pumaguard-ui/windows/flutter/generated_plugin_registrant.h +15 -0
  171. pumaguard-ui/windows/flutter/generated_plugins.cmake +24 -0
  172. pumaguard-ui/windows/runner/CMakeLists.txt +40 -0
  173. pumaguard-ui/windows/runner/Runner.rc +121 -0
  174. pumaguard-ui/windows/runner/flutter_window.cpp +71 -0
  175. pumaguard-ui/windows/runner/flutter_window.h +33 -0
  176. pumaguard-ui/windows/runner/main.cpp +43 -0
  177. pumaguard-ui/windows/runner/resource.h +16 -0
  178. pumaguard-ui/windows/runner/resources/app_icon.ico +0 -0
  179. pumaguard-ui/windows/runner/runner.exe.manifest +14 -0
  180. pumaguard-ui/windows/runner/utils.cpp +65 -0
  181. pumaguard-ui/windows/runner/utils.h +19 -0
  182. pumaguard-ui/windows/runner/win32_window.cpp +288 -0
  183. pumaguard-ui/windows/runner/win32_window.h +102 -0
  184. pumaguard-21.post29.dist-info/RECORD +0 -83
  185. {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/WHEEL +0 -0
  186. {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/entry_points.txt +0 -0
  187. {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/licenses/LICENSE +0 -0
  188. {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,427 @@
1
+ # PumaGuard UI Development Context
2
+
3
+ This document provides context for AI assistants (like GitHub Copilot) working on the PumaGuard Flutter UI in the `pumaguard-ui` repository.
4
+
5
+ ## Project Overview
6
+
7
+ **PumaGuard** is an AI-powered wildlife monitoring system that uses computer vision to detect pumas/mountain lions from trail camera images. The system consists of:
8
+
9
+ 1. **Backend (Python/Flask)**: Image processing, YOLO object detection, TensorFlow classification
10
+ 2. **Frontend (Flutter)**: Cross-platform UI (Web, Desktop, Mobile) for configuration and monitoring
11
+
12
+ You are working on the **Flutter UI** which communicates with the Python backend via REST API.
13
+
14
+ ## Architecture
15
+
16
+ ```
17
+ ┌─────────────────────────────────────────────────────────┐
18
+ │ Flutter UI (This Repo) │
19
+ │ ┌────────────┬────────────┬────────────┬─────────────┐ │
20
+ │ │ Home │ Settings │ Directories│ Images │ │
21
+ │ │ Screen │ Screen │ Screen │ Browser │ │
22
+ │ └────────────┴────────────┴────────────┴─────────────┘ │
23
+ │ │ │
24
+ │ API Service │
25
+ │ │ │
26
+ └─────────────────────────┼────────────────────────────────┘
27
+ │ HTTP/REST
28
+
29
+ ┌─────────────────────────┼────────────────────────────────┐
30
+ │ │ │
31
+ │ Flask Backend │
32
+ │ ┌────────────┬────────────┬────────────┬─────────────┐ │
33
+ │ │ YOLO │Classifier │ Folder │ Web │ │
34
+ │ │ Detection │ Model │ Monitor │ UI │ │
35
+ │ └────────────┴────────────┴────────────┴─────────────┘ │
36
+ │ Python/TensorFlow/Flask │
37
+ └──────────────────────────────────────────────────────────┘
38
+ ```
39
+
40
+ ## Backend API
41
+
42
+ The Flask backend runs on `http://localhost:5000` (or server IP) and provides these endpoints:
43
+
44
+ ### Core Endpoints
45
+
46
+ | Endpoint | Method | Purpose |
47
+ |----------|--------|---------|
48
+ | `/api/status` | GET | Server status and info |
49
+ | `/api/settings` | GET/PUT | Get/update detection settings |
50
+ | `/api/directories` | GET/POST/DELETE | Manage watched folders |
51
+ | `/api/photos` | GET | List all captured photos |
52
+ | `/api/photos/{path}` | GET/DELETE | Access/delete specific photo |
53
+ | `/api/folders` | GET | List folders with image counts |
54
+ | `/api/folders/{path}/images` | GET | List images in folder |
55
+ | `/api/sync/checksums` | POST | Compare checksums for smart sync |
56
+ | `/api/sync/download` | POST | Download files (ZIP or single) |
57
+
58
+ **See `API_REFERENCE.md` for complete API documentation.**
59
+
60
+ ## Key Configuration
61
+
62
+ ### Detection Settings (via API)
63
+
64
+ ```json
65
+ {
66
+ "YOLO-min-size": 0.02, // Min object size (0.0-1.0)
67
+ "YOLO-conf-thresh": 0.25, // Confidence threshold (0.0-1.0)
68
+ "YOLO-max-dets": 12, // Max detections per image
69
+ "YOLO-model-filename": "yolov8s_101425.pt",
70
+ "classifier-model-filename": "colorbw_111325.h5",
71
+ "play-sound": true // Play deterrent sound
72
+ }
73
+ ```
74
+
75
+ ### Settings Storage
76
+
77
+ - **Backend**: Uses XDG Base Directory specification
78
+ - **Default location**: `~/.config/pumaguard/settings.yaml`
79
+ - **Legacy location**: `./pumaguard-settings.yaml`
80
+
81
+ ## Flutter Project Structure
82
+
83
+ ```
84
+ lib/
85
+ ├── main.dart # App entry point
86
+ ├── models/ # Data models
87
+ │ ├── status.dart # Server status
88
+ │ └── settings.dart # Settings model
89
+ ├── screens/ # UI screens
90
+ │ ├── home_screen.dart # Main dashboard
91
+ │ ├── settings_screen.dart # Settings configuration
92
+ │ ├── directories_screen.dart # Folder management
93
+ │ ├── image_browser_screen.dart # Image browsing & download
94
+ │ └── server_discovery_screen.dart # mDNS discovery
95
+ ├── services/ # Business logic
96
+ │ └── api_service.dart # API communication
97
+ └── utils/ # Utilities
98
+ ```
99
+
100
+ ## Key Features
101
+
102
+ ### 1. Home Screen
103
+ - Display server status
104
+ - Quick access to settings, directories, image browser
105
+ - Connection status indicator
106
+
107
+ ### 2. Settings Screen
108
+ - Configure YOLO detection parameters
109
+ - Configure classifier settings
110
+ - Enable/disable sound playback
111
+ - Save/load settings to/from file
112
+
113
+ ### 3. Directories Screen
114
+ - Add/remove watched folders
115
+ - View list of monitored directories
116
+ - Integration with backend folder observer
117
+
118
+ ### 4. Image Browser Screen (NEW)
119
+ - Browse watched folders
120
+ - View image thumbnails in grid
121
+ - Select multiple images
122
+ - Smart sync download (rsync-like)
123
+ - Download as ZIP or individual files
124
+
125
+ ## API Service Pattern
126
+
127
+ All API calls go through `ApiService`:
128
+
129
+ ```dart
130
+ // Example usage
131
+ final apiService = Provider.of<ApiService>(context);
132
+
133
+ // Get status
134
+ final status = await apiService.getStatus();
135
+
136
+ // Update settings
137
+ await apiService.updateSettings(newSettings);
138
+
139
+ // Get folders for image browser
140
+ final folders = await apiService.getFolders();
141
+
142
+ // Download images with smart sync
143
+ final filesToDownload = await apiService.getFilesToSync(localChecksums);
144
+ final zipBytes = await apiService.downloadFiles(filePaths);
145
+ ```
146
+
147
+ ## Smart Sync Feature
148
+
149
+ The UI implements rsync-like functionality:
150
+
151
+ 1. **User selects images** to download
152
+ 2. **Calculate local checksums** (SHA256) of existing files
153
+ 3. **POST to `/api/sync/checksums`** with local checksums
154
+ 4. **Server compares** and returns list of files to download
155
+ 5. **Download only changed/new files** via `/api/sync/download`
156
+ 6. **Extract ZIP** if multiple files
157
+
158
+ ```dart
159
+ // Smart sync workflow
160
+ Map<String, String> localChecksums = {}; // path: checksum
161
+ for (var file in selectedFiles) {
162
+ if (await localFileExists(file)) {
163
+ localChecksums[file] = await calculateChecksum(file);
164
+ } else {
165
+ localChecksums[file] = ""; // Empty = doesn't exist
166
+ }
167
+ }
168
+
169
+ // Get files that need downloading
170
+ final toDownload = await apiService.getFilesToSync(localChecksums);
171
+
172
+ // Download only necessary files
173
+ if (toDownload.isNotEmpty) {
174
+ final bytes = await apiService.downloadFiles(
175
+ toDownload.map((f) => f['path']).toList()
176
+ );
177
+ await saveFiles(bytes);
178
+ }
179
+ ```
180
+
181
+ ## State Management
182
+
183
+ - **Provider** for dependency injection (ApiService)
184
+ - **StatefulWidget** for screen-level state
185
+ - Reload data after navigation (`.then((_) => _loadData())`)
186
+
187
+ ## Dependencies
188
+
189
+ Key packages in `pubspec.yaml`:
190
+
191
+ ```yaml
192
+ dependencies:
193
+ flutter:
194
+ sdk: flutter
195
+ http: ^1.1.0 # HTTP requests
196
+ provider: ^6.1.0 # State management
197
+ crypto: ^3.0.3 # SHA256 checksums
198
+ file_picker: ^8.0.0+1 # File/folder selection
199
+ multicast_dns: ^0.3.2+7 # mDNS server discovery
200
+ intl: ^0.19.0 # Date formatting
201
+ web: ^1.1.0 # Web APIs (dart:html replacement)
202
+ ```
203
+
204
+ ## Platform Considerations
205
+
206
+ ### Web
207
+ - Uses `Uri.base.origin` to auto-detect server URL
208
+ - Downloads via browser download API
209
+ - Limited file system access
210
+
211
+ ### Desktop/Mobile
212
+ - Configurable server URL
213
+ - Full file system access for smart sync
214
+ - Can store local file database
215
+ - File picker for destination selection
216
+
217
+ ## Security
218
+
219
+ - **No authentication** currently (local network only)
220
+ - **Path validation**: All file paths validated server-side
221
+ - **CORS enabled**: For web UI from any origin
222
+ - **Path traversal protection**: Server blocks `../` attempts
223
+
224
+ ## Common Patterns
225
+
226
+ ### Making API Calls
227
+
228
+ ```dart
229
+ Future<void> _loadData() async {
230
+ setState(() {
231
+ _isLoading = true;
232
+ _error = null;
233
+ });
234
+
235
+ try {
236
+ final apiService = Provider.of<ApiService>(context, listen: false);
237
+ final data = await apiService.getSomething();
238
+ setState(() {
239
+ _data = data;
240
+ _isLoading = false;
241
+ });
242
+ } catch (e) {
243
+ setState(() {
244
+ _error = e.toString();
245
+ _isLoading = false;
246
+ });
247
+ }
248
+ }
249
+ ```
250
+
251
+ ### Error Handling
252
+
253
+ ```dart
254
+ if (_error != null) {
255
+ return Center(
256
+ child: Column(
257
+ mainAxisAlignment: MainAxisAlignment.center,
258
+ children: [
259
+ Icon(Icons.error_outline, size: 48, color: Colors.red),
260
+ SizedBox(height: 16),
261
+ Text('Error: $_error'),
262
+ ElevatedButton(
263
+ onPressed: _loadData,
264
+ child: Text('Retry'),
265
+ ),
266
+ ],
267
+ ),
268
+ );
269
+ }
270
+ ```
271
+
272
+ ### Navigation
273
+
274
+ ```dart
275
+ Navigator.push(
276
+ context,
277
+ MaterialPageRoute(
278
+ builder: (context) => const SettingsScreen(),
279
+ ),
280
+ ).then((_) => _loadStatus()); // Reload after returning
281
+ ```
282
+
283
+ ## Image File Types
284
+
285
+ Supported formats:
286
+ - `.jpg`, `.jpeg`
287
+ - `.png`
288
+ - `.gif`
289
+ - `.bmp`
290
+ - `.webp`
291
+
292
+ ## Testing
293
+
294
+ ### Manual Testing
295
+ 1. Start backend: `cd .. && make run-server`
296
+ 2. Run Flutter: `flutter run -d chrome` (web) or `flutter run` (desktop)
297
+ 3. Access: `http://localhost:5000`
298
+
299
+ ### Automated Tests
300
+ ```bash
301
+ flutter test
302
+ ```
303
+
304
+ ## Theme
305
+
306
+ Material 3 with custom color scheme:
307
+ - Seed color: `#8B4513` (brown/puma color)
308
+ - Light and dark mode support
309
+ - System theme mode
310
+
311
+ ## mDNS Discovery
312
+
313
+ The app can discover PumaGuard servers on the network:
314
+ - Service type: `_pumaguard._tcp.local.`
315
+ - Default port: `5000`
316
+ - Use `multicast_dns` package for discovery
317
+
318
+ ## Best Practices
319
+
320
+ 1. **Always use ApiService** for backend communication
321
+ 2. **Handle errors gracefully** with user-friendly messages
322
+ 3. **Show loading states** during async operations
323
+ 4. **Reload data** after navigation or updates
324
+ 5. **Use Provider** for dependency injection
325
+ 6. **Follow Material 3** design guidelines
326
+ 7. **Support both platforms** (web and native)
327
+
328
+ ## Development Workflow
329
+
330
+ 1. Make UI changes in `pumaguard-ui/` repository
331
+ 2. Test with local backend: `cd ../pumaguard && make run-server`
332
+ 3. Build for web: `flutter build web --wasm`
333
+ 4. Backend auto-serves built UI from `pumaguard-ui/build/web/`
334
+
335
+ ## Common Tasks
336
+
337
+ ### Add New API Endpoint
338
+ 1. Add method to `lib/services/api_service.dart`
339
+ 2. Follow existing patterns (error handling, JSON parsing)
340
+ 3. Use the endpoint in screens
341
+
342
+ ### Add New Screen
343
+ 1. Create `lib/screens/new_screen.dart`
344
+ 2. Add navigation from home screen
345
+ 3. Reload parent data after navigation
346
+
347
+ ### Add New Setting
348
+ 1. Update `lib/models/settings.dart`
349
+ 2. Add UI control in `lib/screens/settings_screen.dart`
350
+ 3. Use `ApiService.updateSettings()` to save
351
+
352
+ ## Troubleshooting
353
+
354
+ ### Cannot Connect to Server
355
+ - Check backend is running: `cd ../pumaguard && make run-server`
356
+ - Check URL is correct (localhost:5000 or server IP)
357
+ - Check CORS is enabled (should be by default)
358
+ - Try mDNS discovery if on same network
359
+
360
+ ### Images Not Loading
361
+ - Check paths are correct (use `apiService.getPhotoUrl(path)`)
362
+ - Verify files exist in watched folders
363
+ - Check browser console for network errors
364
+ - Ensure files are in allowed directories
365
+
366
+ ### Downloads Not Working
367
+ - Web: Check browser download permissions
368
+ - Native: Check file picker permissions
369
+ - Verify selected files are in watched folders
370
+ - Check server logs for errors
371
+
372
+ ## Related Documentation
373
+
374
+ - **API_REFERENCE.md**: Complete API documentation
375
+ - **IMAGE_BROWSER.md**: Image browser feature details
376
+ - **XDG_MIGRATION.md**: Settings file location
377
+ - **LXC_TESTING.md**: Container testing
378
+ - **TESTING.md**: General testing guide
379
+
380
+ ## Support
381
+
382
+ - GitHub: https://github.com/PEEC-Nature-Youth-Group/pumaguard
383
+ - Documentation: http://pumaguard.rtfd.io/
384
+
385
+ ## Quick Reference
386
+
387
+ ### Server Status Response
388
+ ```json
389
+ {
390
+ "status": "running",
391
+ "version": "1.0.0",
392
+ "uptime": 3600,
393
+ "monitored_directories": ["..."],
394
+ "total_images": 150
395
+ }
396
+ ```
397
+
398
+ ### Folder List Response
399
+ ```json
400
+ {
401
+ "folders": [
402
+ {
403
+ "path": "/path/to/folder",
404
+ "name": "folder",
405
+ "image_count": 42
406
+ }
407
+ ]
408
+ }
409
+ ```
410
+
411
+ ### Image List Response
412
+ ```json
413
+ {
414
+ "images": [
415
+ {
416
+ "filename": "image.jpg",
417
+ "path": "/full/path/image.jpg",
418
+ "size": 1024000,
419
+ "modified": 1234567890.0,
420
+ "created": 1234567890.0
421
+ }
422
+ ],
423
+ "folder": "/path/to/folder"
424
+ }
425
+ ```
426
+
427
+ This context should help you understand how the PumaGuard UI interacts with the backend and guide your development work!
@@ -0,0 +1,28 @@
1
+ # This file configures the analyzer, which statically analyzes Dart code to
2
+ # check for errors, warnings, and lints.
3
+ #
4
+ # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5
+ # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6
+ # invoked from the command line by running `flutter analyze`.
7
+
8
+ # The following line activates a set of recommended lints for Flutter apps,
9
+ # packages, and plugins designed to encourage good coding practices.
10
+ include: package:flutter_lints/flutter.yaml
11
+
12
+ linter:
13
+ # The lint rules applied to this project can be customized in the
14
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15
+ # included above or to enable additional rules. A list of all available lints
16
+ # and their documentation is published at https://dart.dev/lints.
17
+ #
18
+ # Instead of disabling a lint rule for the entire project in the
19
+ # section below, it can also be suppressed for a single line of code
20
+ # or a specific dart file by using the `// ignore: name_of_lint` and
21
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
22
+ # producing the lint.
23
+ rules:
24
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
25
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
26
+
27
+ # Additional information about this file can be found at
28
+ # https://dart.dev/guides/language/analysis-options
@@ -0,0 +1,14 @@
1
+ gradle-wrapper.jar
2
+ /.gradle
3
+ /captures/
4
+ /gradlew
5
+ /gradlew.bat
6
+ /local.properties
7
+ GeneratedPluginRegistrant.java
8
+ .cxx/
9
+
10
+ # Remember to never publicly share your keystore.
11
+ # See https://flutter.dev/to/reference-keystore
12
+ key.properties
13
+ **/*.keystore
14
+ **/*.jks
@@ -0,0 +1,44 @@
1
+ plugins {
2
+ id("com.android.application")
3
+ id("kotlin-android")
4
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
5
+ id("dev.flutter.flutter-gradle-plugin")
6
+ }
7
+
8
+ android {
9
+ namespace = "com.example.pumaguard_ui"
10
+ compileSdk = flutter.compileSdkVersion
11
+ ndkVersion = flutter.ndkVersion
12
+
13
+ compileOptions {
14
+ sourceCompatibility = JavaVersion.VERSION_17
15
+ targetCompatibility = JavaVersion.VERSION_17
16
+ }
17
+
18
+ kotlinOptions {
19
+ jvmTarget = JavaVersion.VERSION_17.toString()
20
+ }
21
+
22
+ defaultConfig {
23
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
24
+ applicationId = "com.example.pumaguard_ui"
25
+ // You can update the following values to match your application needs.
26
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
27
+ minSdk = flutter.minSdkVersion
28
+ targetSdk = flutter.targetSdkVersion
29
+ versionCode = flutter.versionCode
30
+ versionName = flutter.versionName
31
+ }
32
+
33
+ buildTypes {
34
+ release {
35
+ // TODO: Add your own signing config for the release build.
36
+ // Signing with the debug keys for now, so `flutter run --release` works.
37
+ signingConfig = signingConfigs.getByName("debug")
38
+ }
39
+ }
40
+ }
41
+
42
+ flutter {
43
+ source = "../.."
44
+ }
@@ -0,0 +1,7 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <!-- The INTERNET permission is required for development. Specifically,
3
+ the Flutter tool needs it to communicate with the running application
4
+ to allow setting breakpoints, to provide hot reload, etc.
5
+ -->
6
+ <uses-permission android:name="android.permission.INTERNET"/>
7
+ </manifest>
@@ -0,0 +1,45 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application
3
+ android:label="pumaguard_ui"
4
+ android:name="${applicationName}"
5
+ android:icon="@mipmap/ic_launcher">
6
+ <activity
7
+ android:name=".MainActivity"
8
+ android:exported="true"
9
+ android:launchMode="singleTop"
10
+ android:taskAffinity=""
11
+ android:theme="@style/LaunchTheme"
12
+ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
13
+ android:hardwareAccelerated="true"
14
+ android:windowSoftInputMode="adjustResize">
15
+ <!-- Specifies an Android theme to apply to this Activity as soon as
16
+ the Android process has started. This theme is visible to the user
17
+ while the Flutter UI initializes. After that, this theme continues
18
+ to determine the Window background behind the Flutter UI. -->
19
+ <meta-data
20
+ android:name="io.flutter.embedding.android.NormalTheme"
21
+ android:resource="@style/NormalTheme"
22
+ />
23
+ <intent-filter>
24
+ <action android:name="android.intent.action.MAIN"/>
25
+ <category android:name="android.intent.category.LAUNCHER"/>
26
+ </intent-filter>
27
+ </activity>
28
+ <!-- Don't delete the meta-data below.
29
+ This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
30
+ <meta-data
31
+ android:name="flutterEmbedding"
32
+ android:value="2" />
33
+ </application>
34
+ <!-- Required to query activities that can process text, see:
35
+ https://developer.android.com/training/package-visibility and
36
+ https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
37
+
38
+ In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
39
+ <queries>
40
+ <intent>
41
+ <action android:name="android.intent.action.PROCESS_TEXT"/>
42
+ <data android:mimeType="text/plain"/>
43
+ </intent>
44
+ </queries>
45
+ </manifest>
@@ -0,0 +1,5 @@
1
+ package com.example.pumaguard_ui
2
+
3
+ import io.flutter.embedding.android.FlutterActivity
4
+
5
+ class MainActivity : FlutterActivity()
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Modify this file to customize your launch splash screen -->
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
4
+ <item android:drawable="@android:color/white" />
5
+
6
+ <!-- You can insert your own image assets here -->
7
+ <!-- <item>
8
+ <bitmap
9
+ android:gravity="center"
10
+ android:src="@mipmap/launch_image" />
11
+ </item> -->
12
+ </layer-list>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Modify this file to customize your launch splash screen -->
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
4
+ <item android:drawable="?android:colorBackground" />
5
+
6
+ <!-- You can insert your own image assets here -->
7
+ <!-- <item>
8
+ <bitmap
9
+ android:gravity="center"
10
+ android:src="@mipmap/launch_image" />
11
+ </item> -->
12
+ </layer-list>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
4
+ <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
5
+ <!-- Show a splash screen on the activity. Automatically removed when
6
+ the Flutter engine draws its first frame -->
7
+ <item name="android:windowBackground">@drawable/launch_background</item>
8
+ </style>
9
+ <!-- Theme applied to the Android Window as soon as the process has started.
10
+ This theme determines the color of the Android Window while your
11
+ Flutter UI initializes, as well as behind your Flutter UI while its
12
+ running.
13
+
14
+ This Theme is only used starting with V2 of Flutter's Android embedding. -->
15
+ <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
16
+ <item name="android:windowBackground">?android:colorBackground</item>
17
+ </style>
18
+ </resources>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
4
+ <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
5
+ <!-- Show a splash screen on the activity. Automatically removed when
6
+ the Flutter engine draws its first frame -->
7
+ <item name="android:windowBackground">@drawable/launch_background</item>
8
+ </style>
9
+ <!-- Theme applied to the Android Window as soon as the process has started.
10
+ This theme determines the color of the Android Window while your
11
+ Flutter UI initializes, as well as behind your Flutter UI while its
12
+ running.
13
+
14
+ This Theme is only used starting with V2 of Flutter's Android embedding. -->
15
+ <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
16
+ <item name="android:windowBackground">?android:colorBackground</item>
17
+ </style>
18
+ </resources>
@@ -0,0 +1,7 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <!-- The INTERNET permission is required for development. Specifically,
3
+ the Flutter tool needs it to communicate with the running application
4
+ to allow setting breakpoints, to provide hot reload, etc.
5
+ -->
6
+ <uses-permission android:name="android.permission.INTERNET"/>
7
+ </manifest>