import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; const _prefsKey = 'api_base_url'; /// Backend origin when the user has not chosen one. Override at build time: /// `flutter run --dart-define=API_BASE_URL=https://fin.example.com`. /// On web the default is the page's own origin (Caddy serves app and API together). String defaultApiBaseUrl() { const fromEnv = String.fromEnvironment('API_BASE_URL'); if (fromEnv.isNotEmpty) return fromEnv; if (kIsWeb) return Uri.base.origin; return 'http://127.0.0.1:8000'; } /// The address saved on this device, read in `main()` before `runApp`. Loading it up front, /// rather than lazily like the theme, matters: the session restore fires a request on /// startup and it must already go to the right server. Future loadStoredApiBaseUrl() async => (await SharedPreferences.getInstance()).getString(_prefsKey); /// Overridden in `main()` with [loadStoredApiBaseUrl]; null (tests, nothing saved) means default. final initialApiBaseUrlProvider = Provider((_) => null); /// Backend origin every client is built against. Watched by `apiProvider` and /// `authDioProvider`, so changing it rebuilds them. To switch servers use /// `switchApiBaseUrl`: tokens and cached data belong to the old one. final apiBaseUrlProvider = NotifierProvider( ApiBaseUrlController.new, ); class ApiBaseUrlController extends Notifier { @override String build() => ref.watch(initialApiBaseUrlProvider) ?? defaultApiBaseUrl(); /// [input] as an origin-like URL without a trailing slash, or null if it is not an /// absolute http(s) URL. static String? normalize(String input) { final uri = Uri.tryParse(input.trim()); if (uri == null || !uri.hasAuthority || uri.host.isEmpty) return null; if (uri.scheme != 'http' && uri.scheme != 'https') return null; final s = uri.toString(); return s.endsWith('/') ? s.substring(0, s.length - 1) : s; } /// Persists [url]; null goes back to [defaultApiBaseUrl]. Future save(String? url) async { final prefs = await SharedPreferences.getInstance(); if (url == null) { await prefs.remove(_prefsKey); state = defaultApiBaseUrl(); } else { await prefs.setString(_prefsKey, url); state = url; } } }