// Expected API: // POST /api/auth/login body: {"token":"..."} → {"user_id":"..."} // GET /api/channels header: Authorization: Bearer TOKEN // → [{"id":"1","name":"Alpha","member_count":3}] // POST /api/channels/join body: {"key":"..."} → {"id":"...","name":"..."} // GET /api/channels/{id}/livekit-token → {"url":"wss://...","token":"eyJ..."} import 'dart:convert'; import 'package:http/http.dart' as http; import '../config/app_config.dart'; import '../models/channel.dart'; import 'auth_service.dart'; // ── LiveKit credentials model ───────────────────────────────────────────── class LivekitCredentials { final String url; final String token; const LivekitCredentials({required this.url, required this.token}); } // ── Fake data (only used when AppConfig.debug == true) ──────────────────── const _fakeChannels = [ {'id': '1', 'name': 'تیم آلفا', 'member_count': 4}, {'id': '2', 'name': 'پشتیبانی میدانی', 'member_count': 2}, {'id': '3', 'name': 'فرماندهی', 'member_count': 7}, {'id': '4', 'name': 'گروه لجستیک', 'member_count': 3}, {'id': '5', 'name': 'واحد امنیت', 'member_count': 5}, ]; // ───────────────────────────────────────────────────────────────────────── class ApiService { final AuthService _auth; ApiService(this._auth); Future> _headers() async { final token = await _auth.getToken(); return { 'Content-Type': 'application/json', if (token != null) 'Authorization': 'Bearer $token', }; } Future login(String token) async { if (AppConfig.debug) { await Future.delayed(const Duration(milliseconds: 600)); await _auth.saveAuth(token: token, userId: 'debug_user'); return true; } try { final res = await http .post( Uri.parse('${AppConfig.baseUrl}/api/auth/login'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'token': token}), ) .timeout(const Duration(seconds: 10)); if (res.statusCode == 200) { final data = jsonDecode(res.body) as Map; await _auth.saveAuth( token: token, userId: data['user_id']?.toString(), ); return true; } return false; } catch (_) { return false; } } Future> getChannels() async { if (AppConfig.debug) { await Future.delayed(const Duration(milliseconds: 500)); return _fakeChannels .map((e) => Channel.fromJson(e as Map)) .toList(); } try { final res = await http .get( Uri.parse('${AppConfig.baseUrl}/api/channels'), headers: await _headers(), ) .timeout(const Duration(seconds: 10)); if (res.statusCode == 200) { final list = jsonDecode(res.body) as List; return list .map((e) => Channel.fromJson(e as Map)) .toList(); } return []; } catch (_) { return []; } } Future joinPrivateChannel(String key) async { if (AppConfig.debug) { await Future.delayed(const Duration(milliseconds: 700)); // کلید صحیح در حالت دیباگ: هر چیزی غیر از "wrong" if (key.toLowerCase() == 'wrong') return null; return Channel( id: 'private_${key.hashCode}', name: 'کانال خصوصی ($key)', memberCount: 1, ); } try { final res = await http .post( Uri.parse('${AppConfig.baseUrl}/api/channels/join'), headers: await _headers(), body: jsonEncode({'key': key}), ) .timeout(const Duration(seconds: 10)); if (res.statusCode == 200) { return Channel.fromJson( jsonDecode(res.body) as Map); } return null; } catch (_) { return null; } } Future getLivekitToken(String channelId) async { if (AppConfig.debug) { await Future.delayed(const Duration(milliseconds: 300)); return const LivekitCredentials( url: 'wss://fake.livekit.io', token: 'debug_livekit_token', ); } try { final res = await http .get( Uri.parse( '${AppConfig.baseUrl}/api/channels/$channelId/livekit-token'), headers: await _headers(), ) .timeout(const Duration(seconds: 10)); if (res.statusCode == 200) { final data = jsonDecode(res.body) as Map; return LivekitCredentials( url: data['url'] as String, token: data['token'] as String, ); } return null; } catch (_) { return null; } } }