rework-onboarding (#7)

Onboarding completato, ora super rapido e top

Reviewed-on: http://catelliub.zapto.org:3000/brontomark/flux/pulls/7
Co-authored-by: Mark M2 Macbook <marco@catelli.it>
Co-committed-by: Mark M2 Macbook <marco@catelli.it>
This commit is contained in:
2026-04-22 11:06:02 +02:00
committed by brontomark
parent c5b5b76bd6
commit 90bd5ecacf
47 changed files with 1742 additions and 516 deletions

View File

@@ -1,58 +0,0 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
part 'auth_events.dart';
part 'auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final _supabase = GetIt.instance<SupabaseClient>();
AuthBloc()
: super(const AuthState(status: AuthStatus.initial, isLoginMode: true)) {
on<ToggleAuthMode>(
(event, emit) => emit(state.copyWith(isLoginMode: !state.isLoginMode)),
);
on<LoginRequested>((event, emit) async {
emit(state.copyWith(status: AuthStatus.loading));
try {
if (state.isLoginMode) {
// --- LOGICA LOGIN ---
await _supabase.auth.signInWithPassword(
email: event.email,
password: event.password,
);
// Non serve emettere success qui, ci pensa il SessionBloc!
} else {
// --- LOGICA SIGNUP ---
await _supabase.auth.signUp(
email: event.email,
password: event.password,
);
// Nota: Se Supabase richiede conferma email, l'utente non sarà
// loggato subito. Gestiamolo con un messaggio.
emit(
state.copyWith(
status: AuthStatus.success,
error: "Controlla la tua email per confermare l'account!",
),
);
}
} on AuthException catch (e) {
emit(state.copyWith(status: AuthStatus.failure, error: e.message));
} catch (e) {
emit(
state.copyWith(
status: AuthStatus.failure,
error: "Errore imprevisto: $e",
),
);
}
});
on<LogoutRequested>((event, emit) async {
await _supabase.auth.signOut();
});
}
}

View File

@@ -0,0 +1,71 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
part 'auth_state.dart';
class AuthCubit extends Cubit<AuthState> {
final _supabase = GetIt.instance<SupabaseClient>();
AuthCubit() : super(const AuthState());
void toggleMode() {
emit(state.copyWith(isLoginMode: !state.isLoginMode));
}
Future<void> submitAuth(String email, String password) async {
// Partiamo puliti: via vecchi messaggi ed errori
emit(state.copyWith(status: AuthStatus.loading));
try {
if (state.isLoginMode) {
// --- LOGICA LOGIN ---
await _supabase.auth.signInWithPassword(
email: email,
password: password,
);
// NESSUN EMIT DI SUCCESS!
// Supabase lancerà l'evento 'signedIn', il SessionCubit lo catturerà
// e il GoRouter ci cambierà pagina. Noi stiamo a guardare il caricamento.
} else {
// --- LOGICA SIGNUP ---
final AuthResponse res = await _supabase.auth.signUp(
email: email,
password: password,
);
if (res.session == null) {
// Caso: Conferma Email attivata su Supabase
emit(
state.copyWith(
status: AuthStatus.initial,
infoMessage: "Controlla la tua email per confermare l'account!",
),
);
} else {
// Caso: Autologin post-registrazione (Conferma email disattivata)
// 1. Fermiamo il frullino!
emit(state.copyWith(status: AuthStatus.initial));
// 2. Svegliamo il SessionCubit!
GetIt.I<SessionCubit>().initializeSession();
}
// Se non è null, ha fatto il login automatico. Stessa cosa di sopra, ci pensa il SessionCubit.
}
} on AuthException catch (e) {
emit(state.copyWith(status: AuthStatus.failure, errorMessage: e.message));
} catch (e) {
emit(
state.copyWith(
status: AuthStatus.failure,
errorMessage: "Errore imprevisto: $e",
),
);
}
}
Future<void> requestLogout() async {
await _supabase.auth.signOut();
emit(state.copyWith(status: AuthStatus.initial));
}
}

View File

@@ -1,21 +0,0 @@
part of 'auth_bloc.dart';
abstract class AuthEvent extends Equatable {
const AuthEvent();
@override
List<Object?> get props => [];
}
class ToggleAuthMode extends AuthEvent {} // Passa da Login a Registrazione
class LoginRequested extends AuthEvent {
final String email;
final String password;
const LoginRequested({required this.email, required this.password});
@override
List<Object?> get props => [email, password];
}
class LogoutRequested extends AuthEvent {} // Logout

View File

@@ -1,26 +1,35 @@
part of 'auth_bloc.dart';
part of 'auth_cubit.dart';
enum AuthStatus { initial, loading, success, failure }
enum AuthStatus { initial, loading, failure }
class AuthState extends Equatable {
final AuthStatus status;
final bool isLoginMode;
final String? errorMessage;
final String? infoMessage;
const AuthState({
required this.status,
this.error,
required this.isLoginMode,
this.status = AuthStatus.initial,
this.isLoginMode = true,
this.errorMessage,
this.infoMessage,
});
final AuthStatus status;
final String? error;
final bool isLoginMode;
@override
List<Object?> get props => [status, error, isLoginMode];
AuthState copyWith({AuthStatus? status, String? error, bool? isLoginMode}) {
AuthState copyWith({
AuthStatus? status,
bool? isLoginMode,
String? errorMessage,
String? infoMessage,
}) {
return AuthState(
status: status ?? this.status,
error: error,
isLoginMode: isLoginMode ?? this.isLoginMode,
// Se non passo esplicitamente un errore, lo resetto per evitare che rimanga bloccato a schermo
errorMessage: errorMessage,
infoMessage: infoMessage,
);
}
@override
List<Object?> get props => [status, isLoginMode, errorMessage, infoMessage];
}