pumaguard 21.post27__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.
- pumaguard/presets.py +1 -0
- pumaguard/pumaguard-ui/.last_build_id +1 -1
- pumaguard/pumaguard-ui/assets/NOTICES +621 -71
- pumaguard/pumaguard-ui/assets/fonts/MaterialIcons-Regular.otf +0 -0
- pumaguard/pumaguard-ui/flutter_bootstrap.js +1 -1
- pumaguard/pumaguard-ui/main.dart.js +28869 -28787
- pumaguard/web_routes/dhcp.py +311 -54
- pumaguard/web_routes/diagnostics.py +6 -0
- pumaguard/web_routes/settings.py +13 -0
- pumaguard/web_ui.py +29 -0
- {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/METADATA +1 -1
- pumaguard-21.post83.dist-info/RECORD +254 -0
- pumaguard-ui/.gitignore +48 -0
- pumaguard-ui/.metadata +45 -0
- pumaguard-ui/API_REFERENCE.md +717 -0
- pumaguard-ui/LICENSE +201 -0
- pumaguard-ui/Makefile +36 -0
- pumaguard-ui/README.md +371 -0
- pumaguard-ui/UI_DEVELOPMENT_CONTEXT.md +427 -0
- pumaguard-ui/analysis_options.yaml +28 -0
- pumaguard-ui/android/.gitignore +14 -0
- pumaguard-ui/android/app/build.gradle.kts +44 -0
- pumaguard-ui/android/app/src/debug/AndroidManifest.xml +7 -0
- pumaguard-ui/android/app/src/main/AndroidManifest.xml +45 -0
- pumaguard-ui/android/app/src/main/kotlin/com/example/pumaguard_ui/MainActivity.kt +5 -0
- pumaguard-ui/android/app/src/main/res/drawable/launch_background.xml +12 -0
- pumaguard-ui/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
- pumaguard-ui/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/values/styles.xml +18 -0
- pumaguard-ui/android/app/src/main/res/values-night/styles.xml +18 -0
- pumaguard-ui/android/app/src/profile/AndroidManifest.xml +7 -0
- pumaguard-ui/android/build.gradle.kts +24 -0
- pumaguard-ui/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- pumaguard-ui/android/gradle.properties +2 -0
- pumaguard-ui/android/settings.gradle.kts +26 -0
- pumaguard-ui/fonts/README.md +38 -0
- pumaguard-ui/fonts/Roboto-Bold.ttf +0 -0
- pumaguard-ui/fonts/Roboto-Light.ttf +0 -0
- pumaguard-ui/fonts/Roboto-Medium.ttf +0 -0
- pumaguard-ui/fonts/Roboto-Regular.ttf +0 -0
- pumaguard-ui/fonts/RobotoMono-Bold.ttf +0 -0
- pumaguard-ui/fonts/RobotoMono-Medium.ttf +0 -0
- pumaguard-ui/fonts/RobotoMono-Regular.ttf +0 -0
- pumaguard-ui/fonts/download_fonts.sh +76 -0
- pumaguard-ui/ios/.gitignore +34 -0
- pumaguard-ui/ios/Flutter/AppFrameworkInfo.plist +26 -0
- pumaguard-ui/ios/Flutter/Debug.xcconfig +1 -0
- pumaguard-ui/ios/Flutter/Release.xcconfig +1 -0
- pumaguard-ui/ios/Runner/AppDelegate.swift +13 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +122 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +23 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +5 -0
- pumaguard-ui/ios/Runner/Base.lproj/LaunchScreen.storyboard +37 -0
- pumaguard-ui/ios/Runner/Base.lproj/Main.storyboard +26 -0
- pumaguard-ui/ios/Runner/Info.plist +49 -0
- pumaguard-ui/ios/Runner/Runner-Bridging-Header.h +1 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.pbxproj +616 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- pumaguard-ui/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +101 -0
- pumaguard-ui/ios/Runner.xcworkspace/contents.xcworkspacedata +7 -0
- pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- pumaguard-ui/ios/RunnerTests/RunnerTests.swift +12 -0
- pumaguard-ui/lib/main.dart +56 -0
- pumaguard-ui/lib/models/camera.dart +45 -0
- pumaguard-ui/lib/models/plug.dart +45 -0
- pumaguard-ui/lib/models/settings.dart +112 -0
- pumaguard-ui/lib/models/status.dart +58 -0
- pumaguard-ui/lib/screens/directories_screen.dart +319 -0
- pumaguard-ui/lib/screens/home_screen.dart +545 -0
- pumaguard-ui/lib/screens/image_browser_screen.dart +1248 -0
- pumaguard-ui/lib/screens/server_discovery_screen.dart +390 -0
- pumaguard-ui/lib/screens/settings_screen.dart +1162 -0
- pumaguard-ui/lib/screens/wifi_settings_screen.dart +671 -0
- pumaguard-ui/lib/services/api_service.dart +717 -0
- pumaguard-ui/lib/services/camera_events_service.dart +195 -0
- pumaguard-ui/lib/services/mdns_service.dart +4 -0
- pumaguard-ui/lib/services/mdns_service_impl.dart +282 -0
- pumaguard-ui/lib/services/mdns_service_io.dart +1 -0
- pumaguard-ui/lib/services/mdns_service_web.dart +106 -0
- pumaguard-ui/lib/utils/download_helper.dart +2 -0
- pumaguard-ui/lib/utils/download_helper_stub.dart +6 -0
- pumaguard-ui/lib/utils/download_helper_web.dart +14 -0
- pumaguard-ui/lib/utils/platform_url.dart +10 -0
- pumaguard-ui/lib/utils/platform_url_stub.dart +11 -0
- pumaguard-ui/lib/utils/platform_url_web.dart +16 -0
- pumaguard-ui/linux/.gitignore +1 -0
- pumaguard-ui/linux/CMakeLists.txt +128 -0
- pumaguard-ui/linux/flutter/CMakeLists.txt +88 -0
- pumaguard-ui/linux/flutter/generated_plugin_registrant.cc +15 -0
- pumaguard-ui/linux/flutter/generated_plugin_registrant.h +15 -0
- pumaguard-ui/linux/flutter/generated_plugins.cmake +24 -0
- pumaguard-ui/linux/runner/CMakeLists.txt +26 -0
- pumaguard-ui/linux/runner/main.cc +6 -0
- pumaguard-ui/linux/runner/my_application.cc +148 -0
- pumaguard-ui/linux/runner/my_application.h +21 -0
- pumaguard-ui/macos/.gitignore +7 -0
- pumaguard-ui/macos/Flutter/Flutter-Debug.xcconfig +1 -0
- pumaguard-ui/macos/Flutter/Flutter-Release.xcconfig +1 -0
- pumaguard-ui/macos/Flutter/GeneratedPluginRegistrant.swift +16 -0
- pumaguard-ui/macos/Runner/AppDelegate.swift +13 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
- pumaguard-ui/macos/Runner/Base.lproj/MainMenu.xib +343 -0
- pumaguard-ui/macos/Runner/Configs/AppInfo.xcconfig +14 -0
- pumaguard-ui/macos/Runner/Configs/Debug.xcconfig +2 -0
- pumaguard-ui/macos/Runner/Configs/Release.xcconfig +2 -0
- pumaguard-ui/macos/Runner/Configs/Warnings.xcconfig +13 -0
- pumaguard-ui/macos/Runner/DebugProfile.entitlements +12 -0
- pumaguard-ui/macos/Runner/Info.plist +32 -0
- pumaguard-ui/macos/Runner/MainFlutterWindow.swift +15 -0
- pumaguard-ui/macos/Runner/Release.entitlements +8 -0
- pumaguard-ui/macos/Runner.xcodeproj/project.pbxproj +705 -0
- pumaguard-ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
- pumaguard-ui/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
- pumaguard-ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/macos/RunnerTests/RunnerTests.swift +12 -0
- pumaguard-ui/pubspec.lock +882 -0
- pumaguard-ui/pubspec.yaml +125 -0
- pumaguard-ui/test/models/camera_test.dart +515 -0
- pumaguard-ui/test/models/plug_test.dart +499 -0
- pumaguard-ui/test/models/settings_test.dart +903 -0
- pumaguard-ui/test/models/status_test.dart +707 -0
- pumaguard-ui/test/screens/image_browser_grouping_test.dart +555 -0
- pumaguard-ui/test/services/api_service_cameras_test.dart +580 -0
- pumaguard-ui/test/services/api_service_image_browser_test.dart +512 -0
- pumaguard-ui/test/widget_test.dart.skip +38 -0
- pumaguard-ui/web/favicon.png +0 -0
- pumaguard-ui/web/icons/Icon-192.png +0 -0
- pumaguard-ui/web/icons/Icon-512.png +0 -0
- pumaguard-ui/web/icons/Icon-maskable-192.png +0 -0
- pumaguard-ui/web/icons/Icon-maskable-512.png +0 -0
- pumaguard-ui/web/index.html +38 -0
- pumaguard-ui/web/manifest.json +35 -0
- pumaguard-ui/windows/.gitignore +17 -0
- pumaguard-ui/windows/CMakeLists.txt +108 -0
- pumaguard-ui/windows/flutter/CMakeLists.txt +109 -0
- pumaguard-ui/windows/flutter/generated_plugin_registrant.cc +14 -0
- pumaguard-ui/windows/flutter/generated_plugin_registrant.h +15 -0
- pumaguard-ui/windows/flutter/generated_plugins.cmake +24 -0
- pumaguard-ui/windows/runner/CMakeLists.txt +40 -0
- pumaguard-ui/windows/runner/Runner.rc +121 -0
- pumaguard-ui/windows/runner/flutter_window.cpp +71 -0
- pumaguard-ui/windows/runner/flutter_window.h +33 -0
- pumaguard-ui/windows/runner/main.cpp +43 -0
- pumaguard-ui/windows/runner/resource.h +16 -0
- pumaguard-ui/windows/runner/resources/app_icon.ico +0 -0
- pumaguard-ui/windows/runner/runner.exe.manifest +14 -0
- pumaguard-ui/windows/runner/utils.cpp +65 -0
- pumaguard-ui/windows/runner/utils.h +19 -0
- pumaguard-ui/windows/runner/win32_window.cpp +288 -0
- pumaguard-ui/windows/runner/win32_window.h +102 -0
- pumaguard-21.post27.dist-info/RECORD +0 -83
- {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/WHEEL +0 -0
- {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/entry_points.txt +0 -0
- {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/licenses/LICENSE +0 -0
- {pumaguard-21.post27.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,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>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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>
|