Initial commit: monorepo Match Live TV.

Rails API, app Flutter, infrastruttura Docker/MediaMTX, sito marketing e documentazione di deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-26 17:45:37 +02:00
commit bba6df52c0
381 changed files with 20599 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
import 'package:shared_preferences/shared_preferences.dart';
import '../shared/models/user.dart';
class AuthStorage {
static const _keyAccess = 'auth_access_token';
static const _keyRefresh = 'auth_refresh_token';
static const _keyUserId = 'auth_user_id';
static const _keyUserEmail = 'auth_user_email';
static const _keyUserName = 'auth_user_name';
static const _keyUserRole = 'auth_user_role';
static Future<({User user, String accessToken, String refreshToken})?> load() async {
final prefs = await SharedPreferences.getInstance();
final access = prefs.getString(_keyAccess);
final refresh = prefs.getString(_keyRefresh);
final userId = prefs.getString(_keyUserId);
final email = prefs.getString(_keyUserEmail);
final name = prefs.getString(_keyUserName);
if (access == null ||
access.isEmpty ||
refresh == null ||
refresh.isEmpty ||
userId == null ||
email == null ||
name == null) {
return null;
}
return (
user: User(
id: userId,
email: email,
name: name,
role: prefs.getString(_keyUserRole) ?? 'coach',
),
accessToken: access,
refreshToken: refresh,
);
}
static Future<void> save({
required User user,
required String accessToken,
required String refreshToken,
}) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_keyAccess, accessToken);
await prefs.setString(_keyRefresh, refreshToken);
await prefs.setString(_keyUserId, user.id);
await prefs.setString(_keyUserEmail, user.email);
await prefs.setString(_keyUserName, user.name);
await prefs.setString(_keyUserRole, user.role);
}
static Future<void> clear() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_keyAccess);
await prefs.remove(_keyRefresh);
await prefs.remove(_keyUserId);
await prefs.remove(_keyUserEmail);
await prefs.remove(_keyUserName);
await prefs.remove(_keyUserRole);
}
}

View File

@@ -0,0 +1,24 @@
/// Configurazione globale dell'app Match Live TV.
class AppConfig {
AppConfig._();
/// URL base API Rails. Default emulatore Android → host localhost.
static const String apiBaseUrl = String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'http://10.0.2.2:3000',
);
static String get apiV1 => '$apiBaseUrl/api/v1';
static String get cableUrl {
final uri = Uri.parse(apiBaseUrl);
final wsScheme = uri.scheme == 'https' ? 'wss' : 'ws';
final defaultPort = uri.scheme == 'https' ? 443 : 80;
final port = uri.hasPort ? uri.port : defaultPort;
// Evita :443/:80 espliciti — alcuni client WebSocket/NPM li gestiscono male
if (port == defaultPort) {
return '$wsScheme://${uri.host}/cable';
}
return '$wsScheme://${uri.host}:$port/cable';
}
}