From e0cdf69674898c1075101f760110c1e02d8dba0b Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Mon, 8 Dec 2025 22:58:43 +0100 Subject: [PATCH] feat: add settings API service and IPTV settings provider with configurable options. --- bin/api/settings_handler.dart | 15 +++-- lib/core/services/settings_api_service.dart | 65 +++++++++++-------- .../iptv/providers/settings_provider.dart | 9 ++- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/bin/api/settings_handler.dart b/bin/api/settings_handler.dart index febeed0..f3876ea 100644 --- a/bin/api/settings_handler.dart +++ b/bin/api/settings_handler.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import '../database/database.dart'; -import '../models/user.dart'; class SettingsHandler { final AppDatabase db; @@ -14,12 +13,13 @@ class SettingsHandler { // GET /api/settings router.get('/', (Request req) { - final user = req.context['user'] as User?; - if (user == null) { + // Get userId from context (set by auth middleware) + final userId = req.context['userId'] as String?; + if (userId == null) { return Response.forbidden(jsonEncode({'error': 'Authentication required'})); } - final settingsJson = db.getUserSettings(user.id); + final settingsJson = db.getUserSettings(userId); // If no settings exist, return empty object or default return Response.ok( @@ -30,8 +30,9 @@ class SettingsHandler { // POST /api/settings router.post('/', (Request req) async { - final user = req.context['user'] as User?; - if (user == null) { + // Get userId from context (set by auth middleware) + final userId = req.context['userId'] as String?; + if (userId == null) { return Response.forbidden(jsonEncode({'error': 'Authentication required'})); } @@ -44,7 +45,7 @@ class SettingsHandler { return Response.badRequest(body: jsonEncode({'error': 'Invalid JSON'})); } - db.updateUserSettings(user.id, body); + db.updateUserSettings(userId, body); return Response.ok( body, diff --git a/lib/core/services/settings_api_service.dart b/lib/core/services/settings_api_service.dart index 0ff1045..06d7a14 100644 --- a/lib/core/services/settings_api_service.dart +++ b/lib/core/services/settings_api_service.dart @@ -1,50 +1,59 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'dart:html' as html; -import '../models/app_user.dart'; +import '../api/api_client.dart'; +/// Service for user settings API class SettingsApiService { - final String _baseUrl = html.window.location.origin; + final ApiClient _api = ApiClient(); + /// Get settings from API Future?> getSettings() async { - final token = html.window.localStorage['auth_token']; - if (token == null) return null; + // Restore token from localStorage before making the request + _api.restoreToken(); + + if (_api.getStoredToken() == null) { + print('[SettingsAPI] getSettings: No auth token found'); + return null; + } try { - final response = await http.get( - Uri.parse('$_baseUrl/api/settings'), - headers: { - 'Authorization': 'Bearer $token', - 'Content-Type': 'application/json', - }, - ); - + print('[SettingsAPI] getSettings: Fetching settings...'); + final response = await _api.get('/api/settings'); + + print('[SettingsAPI] getSettings: Response status ${response.statusCode}'); if (response.statusCode == 200) { - if (response.body.isEmpty) return {}; - return jsonDecode(response.body) as Map; + if (response.data == null) return {}; + final decoded = response.data as Map; + print('[SettingsAPI] getSettings: Loaded ${decoded.length} settings'); + return decoded; } + print('[SettingsAPI] getSettings: Failed with data: ${response.data}'); return null; } catch (e) { + print('[SettingsAPI] getSettings: Exception: $e'); return null; } } + /// Save settings to API Future saveSettings(Map settings) async { - final token = html.window.localStorage['auth_token']; - if (token == null) return false; + // Restore token from localStorage before making the request + _api.restoreToken(); + + if (_api.getStoredToken() == null) { + print('[SettingsAPI] saveSettings: No auth token found'); + return false; + } try { - final response = await http.post( - Uri.parse('$_baseUrl/api/settings'), - headers: { - 'Authorization': 'Bearer $token', - 'Content-Type': 'application/json', - }, - body: jsonEncode(settings), - ); - + print('[SettingsAPI] saveSettings: Saving ${settings.length} settings...'); + final response = await _api.post('/api/settings', data: settings); + + print('[SettingsAPI] saveSettings: Response status ${response.statusCode}'); + if (response.statusCode != 200) { + print('[SettingsAPI] saveSettings: Failed with data: ${response.data}'); + } return response.statusCode == 200; } catch (e) { + print('[SettingsAPI] saveSettings: Exception: $e'); return false; } } diff --git a/lib/features/iptv/providers/settings_provider.dart b/lib/features/iptv/providers/settings_provider.dart index 00c0780..3fc1d0b 100644 --- a/lib/features/iptv/providers/settings_provider.dart +++ b/lib/features/iptv/providers/settings_provider.dart @@ -295,7 +295,10 @@ class IptvSettingsNotifier extends StateNotifier { Future _saveToApi() async { final authState = _ref.read(authProvider); - if (!authState.isAuthenticated) return; + if (!authState.isAuthenticated) { + print('[SettingsProvider] _saveToApi: Not authenticated, skipping save'); + return; + } // Create map from state final settingsMap = { @@ -313,7 +316,9 @@ class IptvSettingsNotifier extends StateNotifier { _SettingsKeys.preferredAspectRatio: state.preferredAspectRatio, }; - await _apiService.saveSettings(settingsMap); + print('[SettingsProvider] _saveToApi: Saving settings...'); + final success = await _apiService.saveSettings(settingsMap); + print('[SettingsProvider] _saveToApi: Save result: $success'); } // ===== Setters with Auto-Save =====