Files
Dmitry a559d6de3e feat(app): смена сервера API и очистка данных устройства при выходе
Адрес бэкенда хранится в shared_preferences и читается до runApp; switchApiBaseUrl сбрасывает токены и кэш старого сервера. Выход стирает refresh-токен и sqlite-кэш ответов. Экран настроек переделан под разделы.
2026-09-19 22:14:14 +03:00

59 lines
2.4 KiB
Dart

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<String?> loadStoredApiBaseUrl() async =>
(await SharedPreferences.getInstance()).getString(_prefsKey);
/// Overridden in `main()` with [loadStoredApiBaseUrl]; null (tests, nothing saved) means default.
final initialApiBaseUrlProvider = Provider<String?>((_) => 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, String>(
ApiBaseUrlController.new,
);
class ApiBaseUrlController extends Notifier<String> {
@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<void> 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;
}
}
}