189 lines
7.7 KiB
Markdown
189 lines
7.7 KiB
Markdown
|
|
# Traccar Client Fork - Agent Specification
|
||
|
|
|
||
|
|
This spec describes how to transform a fresh fork of [traccar/traccar-client](https://github.com/traccar/traccar-client) (Flutter) into a simplified, hardcoded tracking client. Apply all changes to the `main` branch.
|
||
|
|
|
||
|
|
## Goal
|
||
|
|
|
||
|
|
Create a minimal Traccar Client that:
|
||
|
|
- Hard-codes all server/tracking settings (no user configuration)
|
||
|
|
- Shows only a device ID and a tracking toggle in the UI
|
||
|
|
- Removes access to settings, status, manual send, QR scanning, and password protection
|
||
|
|
|
||
|
|
## Upstream Repository
|
||
|
|
|
||
|
|
```
|
||
|
|
https://github.com/traccar/traccar-client
|
||
|
|
```
|
||
|
|
|
||
|
|
The app is a Flutter project targeting iOS and Android from a single Dart codebase.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Configuration File: `lib/config.dart`
|
||
|
|
|
||
|
|
Create a new file `lib/config.dart` with compile-time constants. This is the single source of truth for all hardcoded settings. A developer forking this project only needs to edit this file to reconfigure the app.
|
||
|
|
|
||
|
|
```dart
|
||
|
|
class AppConfig {
|
||
|
|
AppConfig._();
|
||
|
|
|
||
|
|
/// Traccar server URL
|
||
|
|
static const String serverUrl = 'https://c.track.rs';
|
||
|
|
|
||
|
|
/// Location accuracy: 'highest', 'high', 'medium', or 'low'
|
||
|
|
static const String accuracy = 'highest';
|
||
|
|
|
||
|
|
/// Location update interval in seconds
|
||
|
|
static const int intervalSeconds = 60;
|
||
|
|
|
||
|
|
/// Distance filter in meters (0 = disabled)
|
||
|
|
static const int distanceFilter = 0;
|
||
|
|
|
||
|
|
/// Whether to enable stop detection
|
||
|
|
static const bool stopDetection = false;
|
||
|
|
|
||
|
|
/// Whether to buffer locations when offline
|
||
|
|
static const bool buffer = true;
|
||
|
|
|
||
|
|
/// Fastest location update interval in seconds (Android)
|
||
|
|
static const int fastestIntervalSeconds = 30;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
All other modified files must read from `AppConfig` instead of using inline literals.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Hardcoded Settings (via `AppConfig`)
|
||
|
|
|
||
|
|
These values are set in `lib/config.dart` and enforced at runtime:
|
||
|
|
|
||
|
|
| Setting | Constant | Default Value |
|
||
|
|
|--------------------|-----------------------------------|--------------------------|
|
||
|
|
| Server URL | `AppConfig.serverUrl` | `https://c.track.rs` |
|
||
|
|
| Location Accuracy | `AppConfig.accuracy` | `highest` |
|
||
|
|
| Interval | `AppConfig.intervalSeconds` | `60` |
|
||
|
|
| Distance Filter | `AppConfig.distanceFilter` | `0` (disabled) |
|
||
|
|
| Stop Detection | `AppConfig.stopDetection` | `false` (disabled) |
|
||
|
|
| Buffer | `AppConfig.buffer` | `true` |
|
||
|
|
| Fastest Interval | `AppConfig.fastestIntervalSeconds`| `30` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. File Changes
|
||
|
|
|
||
|
|
### 3.1 `lib/preferences.dart`
|
||
|
|
|
||
|
|
Add `import 'config.dart';` at the top.
|
||
|
|
|
||
|
|
#### `migrate()` method
|
||
|
|
After the existing migration logic and device ID generation, force-set values from `AppConfig`:
|
||
|
|
|
||
|
|
```dart
|
||
|
|
// After device ID generation
|
||
|
|
await instance.setString(url, AppConfig.serverUrl);
|
||
|
|
await instance.setString(accuracy, AppConfig.accuracy);
|
||
|
|
await instance.setInt(interval, AppConfig.intervalSeconds);
|
||
|
|
await instance.setInt(distance, AppConfig.distanceFilter);
|
||
|
|
await instance.setBool(buffer, instance.getBool(buffer) ?? AppConfig.buffer);
|
||
|
|
await instance.setBool(stopDetection, AppConfig.stopDetection);
|
||
|
|
await instance.setInt(fastestInterval, instance.getInt(fastestInterval) ?? AppConfig.fastestIntervalSeconds);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `geolocationConfig()` method
|
||
|
|
Replace dynamic preference reads with `AppConfig` references:
|
||
|
|
|
||
|
|
- `isHighestAccuracy` = `AppConfig.accuracy == 'highest'`
|
||
|
|
- `locationUpdateInterval` = `AppConfig.intervalSeconds * 1000` (but set to `0` in the config when highest accuracy)
|
||
|
|
- `desiredAccuracy`: Use `DESIRED_ACCURACY_NAVIGATION` on iOS, `DESIRED_ACCURACY_HIGH` on Android (when highest)
|
||
|
|
- `url`: `AppConfig.serverUrl` (passed through `_formatUrl`)
|
||
|
|
- `distanceFilter`: `AppConfig.distanceFilter.toDouble()`
|
||
|
|
- `locationUpdateInterval` (in config): `0` (when highest accuracy, for continuous tracking)
|
||
|
|
- `disableElasticity`: `true`
|
||
|
|
- `disableStopDetection`: `!AppConfig.stopDetection`
|
||
|
|
- `pausesLocationUpdatesAutomatically`: `false` on iOS, `null` on Android
|
||
|
|
- `fastestLocationUpdateInterval`: `0` when highest accuracy, else `AppConfig.fastestIntervalSeconds * 1000`
|
||
|
|
|
||
|
|
### 3.2 `lib/main_screen.dart`
|
||
|
|
|
||
|
|
**Complete rewrite.** Replace the entire file with a minimal screen containing:
|
||
|
|
|
||
|
|
1. **AppBar** with title `'Traccar Client'`
|
||
|
|
2. **Centered body** with two cards:
|
||
|
|
- **Device ID card**: Shows label "Device ID" and a `SelectableText` displaying the device ID in monospace bold (`headlineSmall`)
|
||
|
|
- **Tracking toggle card**: A `SwitchListTile` labeled "Continuous Tracking" with subtitle showing state ("Sending location updates" / "Location tracking disabled")
|
||
|
|
3. **Tracking toggle behavior**:
|
||
|
|
- On: calls `bg.BackgroundGeolocation.start()` then checks battery optimizations
|
||
|
|
- Off: calls `bg.BackgroundGeolocation.stop()`
|
||
|
|
- Track `isMoving` state; set `activeTrackColor` to error color when `isMoving == false` (stationary warning)
|
||
|
|
4. **State listeners**: Listen to `onEnabledChange` and `onMotionChange` from BackgroundGeolocation
|
||
|
|
5. **Battery optimization dialog**: Keep the `_checkBatteryOptimizations` method that shows a dialog using `bg.DeviceSettings`
|
||
|
|
|
||
|
|
**Remove entirely:**
|
||
|
|
- Settings button/navigation
|
||
|
|
- Status screen button/navigation
|
||
|
|
- "Send Location" button
|
||
|
|
- Password service import and usage
|
||
|
|
- Any reference to `SettingsScreen` or `StatusScreen` navigation
|
||
|
|
|
||
|
|
**Imports needed:** `flutter/material.dart`, `flutter/services.dart`, `traccar_client/main.dart` (for `messengerKey`), `traccar_client/preferences.dart`, `flutter_background_geolocation`, `l10n/app_localizations.dart`
|
||
|
|
|
||
|
|
### 3.3 `lib/settings_screen.dart`
|
||
|
|
|
||
|
|
**Complete rewrite.** Replace with a minimal read-only screen (not navigable from main UI, but kept for completeness):
|
||
|
|
|
||
|
|
Add `import 'config.dart';` at the top.
|
||
|
|
|
||
|
|
- Device ID display (read-only `ListTile`)
|
||
|
|
- Continuous Tracking `SwitchListTile` (functional)
|
||
|
|
- Read-only disabled `ListTile` entries displaying values from `AppConfig`:
|
||
|
|
- Server: `AppConfig.serverUrl`
|
||
|
|
- Location Accuracy: `AppConfig.accuracy`
|
||
|
|
- Distance: `AppConfig.distanceFilter` (show "Disabled" when 0)
|
||
|
|
- Interval: `'${AppConfig.intervalSeconds} seconds'`
|
||
|
|
- Stop Detection: `AppConfig.stopDetection` (show "Disabled"/"Enabled")
|
||
|
|
|
||
|
|
### 3.4 `ios/Runner.xcodeproj/project.pbxproj`
|
||
|
|
|
||
|
|
Find the build phase named `FlutterFire: "flutterfire upload-crashlytics-symbols"` and prepend `exit 0` to the shell script to skip it. This prevents `flutterfire: command not found` build failures.
|
||
|
|
|
||
|
|
The `shellScript` value should start with:
|
||
|
|
```
|
||
|
|
\n#!/bin/bash\n# Skip Firebase Crashlytics for now\nexit 0\n
|
||
|
|
```
|
||
|
|
followed by the original script content (which will never execute).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Files NOT Modified
|
||
|
|
|
||
|
|
These files remain unchanged from upstream:
|
||
|
|
- `lib/main.dart` - App entry point, Firebase init, app links, rate dialog
|
||
|
|
- `lib/geolocation_service.dart`
|
||
|
|
- `lib/configuration_service.dart`
|
||
|
|
- `lib/push_service.dart`
|
||
|
|
- `lib/quick_actions.dart`
|
||
|
|
- `lib/location_cache.dart`
|
||
|
|
- `lib/status_screen.dart` - Kept in codebase but not navigable
|
||
|
|
- `lib/password_service.dart` - Kept in codebase but unused
|
||
|
|
- `lib/qr_code_screen.dart` - Kept in codebase but not navigable
|
||
|
|
- `pubspec.yaml`
|
||
|
|
- All localization files (`lib/l10n/`)
|
||
|
|
- Android platform files
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Verification Checklist
|
||
|
|
|
||
|
|
After applying changes:
|
||
|
|
|
||
|
|
1. `flutter pub get` succeeds
|
||
|
|
2. `flutter build ios` succeeds (no flutterfire errors)
|
||
|
|
3. `flutter build apk --release` succeeds
|
||
|
|
4. App launches showing only device ID and tracking toggle
|
||
|
|
5. No settings, status, or send location buttons visible
|
||
|
|
6. Toggling tracking on starts background location reporting to `https://c.track.rs`
|
||
|
|
7. Device ID is auto-generated (8-digit random number) and persists across launches
|
||
|
|
8. Location updates use highest accuracy with 0 distance filter
|
||
|
|
9. Stop detection is disabled (tracking never auto-pauses)
|