62 lines
1.8 KiB
Dart
62 lines
1.8 KiB
Dart
import 'package:freezed_annotation/freezed_annotation.dart';
|
||
|
||
part 'login_state.freezed.dart';
|
||
|
||
/// 登录流程的当前步骤
|
||
enum LoginStep {
|
||
/// 步骤 1:输入手机号
|
||
phone,
|
||
|
||
/// 步骤 2:输入验证码
|
||
otp,
|
||
}
|
||
|
||
/// 登录页面状态(@freezed 自动生成 copyWith / == / toString)
|
||
///
|
||
/// ViewModel 通过 `state = state.copyWith(...)` 更新状态,
|
||
/// View 通过 `ref.watch(loginViewModelProvider)` 自动响应变化。
|
||
///
|
||
/// ## 状态流转
|
||
///
|
||
/// ```
|
||
/// 初始
|
||
/// → LoginState() step: phone, isLoading: false
|
||
/// 点击"获取验证码"
|
||
/// → state.copyWith(isLoading: true)
|
||
/// → 成功: state.copyWith(step: otp, contact: phone, isLoading: false)
|
||
/// → 失败: state.copyWith(error: '...', isLoading: false)
|
||
/// 点击"登录"
|
||
/// → state.copyWith(isLoading: true)
|
||
/// → 成功: authNotifierProvider.login() → 路由守卫重定向
|
||
/// → 失败: state.copyWith(error: '...', isLoading: false)
|
||
/// ```
|
||
@freezed
|
||
sealed class LoginState with _$LoginState {
|
||
const LoginState._();
|
||
|
||
const factory LoginState({
|
||
/// 当前步骤(手机号输入 or 验证码输入)
|
||
@Default(LoginStep.phone) LoginStep step,
|
||
|
||
/// 国家代码(默认 +65,暂不支持切换)
|
||
@Default('+65') String countryCode,
|
||
|
||
/// 已提交的手机号(步骤 2 用于显示和构建请求)
|
||
@Default('') String contact,
|
||
|
||
/// 是否正在请求中
|
||
@Default(false) bool isLoading,
|
||
|
||
/// 错误信息(null = 无错误)
|
||
String? error,
|
||
}) = _LoginState;
|
||
|
||
/// 步骤 2 显示的脱敏手机号,如 "138****0000"
|
||
String get maskedContact {
|
||
if (contact.length <= 4) return contact;
|
||
final tail = contact.substring(contact.length - 4);
|
||
final stars = '*' * (contact.length - 4);
|
||
return '$stars$tail';
|
||
}
|
||
}
|