# Flutter App Implementation Guide

## What's needed to make live tracking work

Based on your existing code (`AdminDashboardController`, `AgentWebSocketService`, `LocationService`), here are the exact changes needed.

---

## 1. Fix Admin Drawer — Add "Live Tracking" Menu Item

**File:** `lib/admin/admin_dashboard.dart`

Your drawer currently has items at indices 0, 2, 4, 6, 7, 8. Index 1 is missing. Add it:

```dart
// Find the drawer items list (around line 300-350)
// Add this item BEFORE the "Track" item (index 2):

_navigationItems.add(
  DrawerItem(
    index: 1,
    icon: Icons.live_tv_rounded,
    title: _tr('live_tracking'),  // or hardcode "Live Tracking"
  ),
);
```

**Important:** Insert at `index: 1` so the case statement in your controller matches:

```dart
// lib/controllers/admin_dashboard_controller.dart
case 1:
  Get.to(() => const LiveAgentTrackingPage());
  break;
```

---

## 2. Fix "Track" Quick Action Button

**File:** `lib/admin/admin_dashboard.dart` (around line 893)

Change the Track button to open the live map instead of `AgentsListPage`:

```dart
// BEFORE (current):
onTap: () => Get.to(() => const AgentsListPage()),

// AFTER:
onTap: () => Get.to(() => const LiveAgentTrackingPage()),
```

Or add both (agents list + live tracking button):

```dart
// Add a new Quick Action button:
Expanded(
  child: _buildAnimatedActionButton(
    context,
    index: 1,  // match the new drawer index
    icon: Icons.live_tv_rounded,
    label: 'Live',
    color: const Color(0xFF10B981),
    onTap: () => Get.to(() => const LiveAgentTrackingPage()),
  ),
),
```

---

## 3. WebSocket Connection Flow (Agent Side)

Your `AgentWebSocketService` needs to connect when the Agent Dashboard opens. Here's the exact flow:

**File:** `lib/services/agent_websocket_service.dart`

```dart
class AgentWebSocketService {
  static late AgentSocketClient client;
  static bool _initialized = false;

  static Future<void> connect(String jwtToken) async {
    debugPrint('🔌 WS connect() called');
    
    client = AgentSocketClient(
      serverUrl: 'https://dayloan.agniplay.com',
      jwtToken: jwtToken,
      deviceInfo: '${Platform.operatingSystem}/${Platform.operatingSystemVersion}',
      appVersion: '1.0.0',
    );

    client.onStateChange.listen((state) {
      debugPrint('🔌 WS state: $state');
      if (state == ConnectionState.connected) {
        _initialized = true;
        _startGpsTracking();
      }
    });

    client.onAck.listen((ack) {
      debugPrint('📍 GPS SENDING -> ACK: ${ack.status} seq: ${ack.sequence}');
    });

    client.enableOfflineBuffer(flushSeconds: 30);
    client.connect();
  }

  static void _startGpsTracking() {
    debugPrint('📍 GPS _startGpsTracking() called');
    _startBackgroundLocation();
  }

  static Future<void> disconnect() {
    client.dispose();
    _initialized = false;
  }
}
```

---

## 4. Fix LocationService Permission Issue

**File:** `lib/services/location_service.dart`

Your current code checks flags before starting the stream (line 272-274). The problem: flags might be `false` even after permission was granted, because the flag update is async.

**Fix:** Always try to start the stream — don't check flags first:

```dart
// BEFORE:
Stream<Position>? startTracking() {
  if (!isLocationEnabled.value || !hasLocationPermission.value) {
    return null;
  }
  return Geolocator.getPositionStream(
    locationSettings: const LocationSettings(
      accuracy: LocationAccuracy.high,
      distanceFilter: 20,
    ),
  );
}

// AFTER:
Stream<Position>? startTracking() {
  try {
    final stream = Geolocator.getPositionStream(
      locationSettings: const LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 20,
      ),
    );
    debugPrint('📍 GPS stream obtained, listening...');
    return stream;
  } catch (e) {
    debugPrint('📍 GPS stream error: $e');
    return null;
  }
}
```

Then in your consuming code:

```dart
final stream = locationService.startTracking();
if (stream == null) {
  debugPrint('📍 GPS stream is NULL');
  return;
}
stream.listen((Position pos) {
  AgentWebSocketService.client.sendLocation(
    LocationData(
      latitude: pos.latitude,
      longitude: pos.longitude,
      accuracy: pos.accuracy,
      altitude: pos.altitude,
      heading: pos.heading,
      speed: pos.speed,
    ),
  );
});
```

---

## 5. Agent Dashboard Card Status

**File:** `lib/agent/agent_dashboard.dart`

The green "Live location sharing active" card should show/hide based on WebSocket state:

```dart
Obx(() {
  if (AgentWebSocketService.client.state == ConnectionState.connected) {
    return Card(
      color: Colors.green.shade50,
      child: ListTile(
        leading: Icon(Icons.location_on, color: Colors.green),
        title: Text('Live location sharing active'),
        subtitle: Text('Movement detected — sending updates'),
      ),
    );
  } else if (AgentWebSocketService.client.state == ConnectionState.connecting) {
    return Card(
      child: ListTile(
        leading: CircularProgressIndicator(strokeWidth: 2),
        title: Text('Connecting...'),
      ),
    );
  } else {
    return SizedBox.shrink(); // hidden when disconnected
  }
}),
```

---

## 6. Debugging Checklist

### Agent side

Open the agent dashboard and watch the console:

```
🔌 WS connect() called                              ← Dashboard onInit ran
🔌 WS creating client...                            ← Service instantiated
🔌 WS state: ConnectionState.connecting             ← Socket.IO handshake
🔌 WS state: ConnectionState.connected              ← Auth OK, joined room
📍 GPS _startGpsTracking() called                   ← Connected, starting GPS
📍 GPS stream obtained, listening...                ← Geolocator stream OK
📍 GPS SENDING -> ACK: ok seq: 1                    ← Location saved on server
```

**If you don't see `🔌 WS` lines** → Dashboard `onInit` isn't calling connect.

**If you see `connected` but no `📍 GPS SENDING`** → Movement < 20m or stream not set up.

**If you see `authError`** → JWT token is wrong or expired.

**If you're on Web** → WebSocket may fail silently. Test on a physical Android/iOS device.

### Admin side

Open the admin dashboard:

```
Admin WebSocket connects automatically
Snackbar: "Agent 5 (Rajesh) is now ONLINE"          ← When agent connects
```

Then open Live Agent Tracking:
```
Green dot in app bar                                 ← WS connected
Agent count updates                                   ← Receiving location:update
Map markers appear                                    ← Location data arriving
```

**If no green dot** → WebSocket not connected. Check JWT.

**If green dot but no markers** → No agents are streaming. Check agent side sends location.

---

## 7. Testing Setup

| Component | Device | Action |
|-----------|--------|--------|
| Backend | Server | Already running on port 3000/3002 |
| Agent app | Physical phone A | Login → Check in → Dashboard → Walk 30m |
| Admin app | Physical phone B | Login → Live Agent Tracking |

**Emulator testing:** Use Android emulator with location mocking:
```
Extended controls → Location → Set GPS coordinates → Send
```

---

## 8. File Checklist

| File | Status |
|------|--------|
| `lib/services/ws_packet.dart` | Copy from `flutter_websocket/ws_packet.dart` |
| `lib/services/agent_client.dart` | Copy from `flutter_websocket/agent_client.dart` |
| `lib/services/admin_client.dart` | Copy from `flutter_websocket/admin_client.dart` |
| `lib/services/agent_websocket_service.dart` | Wire up as shown in section 3 |
| `lib/services/location_service.dart` | Fix `startTracking()` as shown in section 4 |
| `lib/admin/admin_dashboard.dart` | Add drawer item index 1 + fix Track button |
| `lib/agent/agent_dashboard.dart` | Add connection status card (section 5) |
| `pubspec.yaml` | Add `socket_io_client: ^3.0.2`, `uuid: ^4.5.1` |
