Stabilizza live YouTube/RTMP e fix crash rotazione mobile.
Pipeline YouTube con relay, overlay e publisher sync lato backend; fix GL pauseGlDuringRotation su Android per evitare crash in rotazione durante lo streaming Flutter. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../core/auth_storage.dart';
|
||||
import '../core/team_selection_storage.dart';
|
||||
import '../shared/api_client.dart';
|
||||
import '../shared/models/user.dart';
|
||||
|
||||
class AuthState {
|
||||
@@ -72,6 +74,53 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Dopo restore: verifica token o rinnova con refresh (evita 401 su /teams).
|
||||
Future<bool> validateOrRefreshSession() async {
|
||||
if (!state.isAuthenticated) return false;
|
||||
|
||||
final client = ApiClient(accessToken: state.accessToken);
|
||||
try {
|
||||
final user = await client.me();
|
||||
state = state.copyWith(user: user);
|
||||
await AuthStorage.save(
|
||||
user: user,
|
||||
accessToken: state.accessToken!,
|
||||
refreshToken: state.refreshToken!,
|
||||
);
|
||||
return true;
|
||||
} on DioException catch (e) {
|
||||
if (e.response?.statusCode != 401) {
|
||||
return true;
|
||||
}
|
||||
} catch (_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return refreshSession();
|
||||
}
|
||||
|
||||
Future<bool> refreshSession() async {
|
||||
final refreshToken = state.refreshToken;
|
||||
if (refreshToken == null || refreshToken.isEmpty) {
|
||||
logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final client = ApiClient();
|
||||
final result = await client.refreshSession(refreshToken);
|
||||
setSession(
|
||||
user: result.user,
|
||||
accessToken: result.tokens.accessToken,
|
||||
refreshToken: result.tokens.refreshToken,
|
||||
);
|
||||
return true;
|
||||
} catch (_) {
|
||||
logout();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void setLoading(bool loading) {
|
||||
state = state.copyWith(loading: loading, clearError: true);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,12 @@ class SessionNotifier extends StateNotifier<SessionState> {
|
||||
SessionNotifier() : super(const SessionState());
|
||||
|
||||
void setSession(StreamSession session, {MatchModel? match}) {
|
||||
state = state.copyWith(session: session, match: match);
|
||||
final prevId = state.session?.id;
|
||||
state = state.copyWith(
|
||||
session: session,
|
||||
match: match,
|
||||
elapsed: prevId != null && prevId != session.id ? Duration.zero : state.elapsed,
|
||||
);
|
||||
}
|
||||
|
||||
void updateYoutubeLinks({
|
||||
@@ -111,8 +116,6 @@ class SessionNotifier extends StateNotifier<SessionState> {
|
||||
state = state.copyWith(cameraDevice: device);
|
||||
return;
|
||||
}
|
||||
final startedAt = s.startedAt ??
|
||||
((incoming == 'live' || incoming == 'reconnecting') ? DateTime.now() : null);
|
||||
state = state.copyWith(
|
||||
session: StreamSession(
|
||||
id: s.id,
|
||||
@@ -129,7 +132,7 @@ class SessionNotifier extends StateNotifier<SessionState> {
|
||||
privacyStatus: s.privacyStatus,
|
||||
qualityPreset: s.qualityPreset,
|
||||
targetBitrate: s.targetBitrate,
|
||||
startedAt: startedAt,
|
||||
startedAt: s.startedAt,
|
||||
disconnectionCount: s.disconnectionCount,
|
||||
score: s.score,
|
||||
devices: s.devices,
|
||||
|
||||
Reference in New Issue
Block a user