96 lines
2.7 KiB
Dart
96 lines
2.7 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'package:equatable/equatable.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import 'auth_repository.dart';
|
|
|
|
enum AuthStatus { initial, loading, otpSent, authenticated, error }
|
|
|
|
class AuthState extends Equatable {
|
|
final AuthStatus status;
|
|
final String mobile;
|
|
final bool needsProfile; // پس از ورود، آیا کاربر باید نام/آواتار انتخاب کند
|
|
final String? error;
|
|
|
|
const AuthState({
|
|
this.status = AuthStatus.initial,
|
|
this.mobile = '',
|
|
this.needsProfile = false,
|
|
this.error,
|
|
});
|
|
|
|
AuthState copyWith(
|
|
{AuthStatus? status,
|
|
String? mobile,
|
|
bool? needsProfile,
|
|
String? error}) =>
|
|
AuthState(
|
|
status: status ?? this.status,
|
|
mobile: mobile ?? this.mobile,
|
|
needsProfile: needsProfile ?? this.needsProfile,
|
|
error: error,
|
|
);
|
|
|
|
@override
|
|
List<Object?> get props => [status, mobile, needsProfile, error];
|
|
}
|
|
|
|
class AuthCubit extends Cubit<AuthState> {
|
|
final AuthRepository _repo;
|
|
AuthCubit(this._repo) : super(const AuthState());
|
|
|
|
Future<void> requestOtp(String mobile) async {
|
|
emit(state.copyWith(status: AuthStatus.loading, mobile: mobile));
|
|
try {
|
|
await _repo.requestOtp(mobile);
|
|
emit(state.copyWith(status: AuthStatus.otpSent, mobile: mobile));
|
|
} catch (e) {
|
|
emit(state.copyWith(status: AuthStatus.error, error: _msg(e)));
|
|
}
|
|
}
|
|
|
|
Future<void> verifyOtp(String code) async {
|
|
emit(state.copyWith(status: AuthStatus.loading));
|
|
try {
|
|
final hasName = await _repo.verifyOtp(state.mobile, code);
|
|
emit(state.copyWith(
|
|
status: AuthStatus.authenticated, needsProfile: !hasName));
|
|
} catch (e) {
|
|
emit(state.copyWith(status: AuthStatus.error, error: _msg(e)));
|
|
}
|
|
}
|
|
|
|
/// ذخیرهی نام و آواتار؛ سپس نیازی به صفحهی پروفایل نیست.
|
|
Future<bool> saveProfile(String name, String avatar) async {
|
|
try {
|
|
await _repo.updateProfile(name, avatar);
|
|
emit(state.copyWith(needsProfile: false));
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<void> logout() async {
|
|
await _repo.logout();
|
|
emit(const AuthState());
|
|
}
|
|
|
|
/// بازنشانی وضعیت خطا به حالت مناسب فرم.
|
|
void resetError({required bool onOtpScreen}) {
|
|
emit(state.copyWith(
|
|
status: onOtpScreen ? AuthStatus.otpSent : AuthStatus.initial));
|
|
}
|
|
|
|
String _msg(Object e) {
|
|
if (e is DioException) {
|
|
final data = e.response?.data;
|
|
if (data is Map && data['message'] != null) {
|
|
return data['message'].toString();
|
|
}
|
|
return 'خطا در ارتباط با سرور';
|
|
}
|
|
return 'خطای نامشخص';
|
|
}
|
|
}
|