Files
ttstd_family_care/lib/features/auth/presentation/auth_controller.dart

138 lines
3.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/storage/token_storage.dart';
import '../data/auth_providers.dart';
import '../domain/auth_models.dart';
import '../domain/auth_state.dart';
/// 认证控制器。
///
/// 承载登录 / 注册 / 发送验证码 / 倒计时等全部业务逻辑UI 仅触发动作并消费状态。
/// 使用 keepAlive避免登录流程中页面切换导致状态丢失。
class AuthController extends Notifier<AuthState> {
AuthController();
Timer? _countdownTimer;
@override
AuthState build() {
ref.keepAlive();
ref.onDispose(() => _countdownTimer?.cancel());
return const AuthState();
}
String get _deviceId => TokenStorage.deviceId;
/// 密码登录。
Future<bool> loginByPassword({
required String phone,
required String password,
}) async {
return _run(() => ref.read(authRepositoryProvider).loginByPassword(
phone: phone,
password: password,
deviceId: _deviceId,
));
}
/// 短信登录。
Future<bool> loginBySms({
required String phone,
required String code,
}) async {
return _run(() => ref.read(authRepositoryProvider).loginBySms(
phone: phone,
code: code,
deviceId: _deviceId,
));
}
/// 注册。
Future<bool> register({
required String phone,
required String code,
required String password,
}) async {
return _run(() => ref.read(authRepositoryProvider).register(
phone: phone,
code: code,
password: password,
deviceId: _deviceId,
));
}
/// 发送短信验证码并启动 60s 倒计时。
Future<void> sendSmsCode({
required String phone,
required SmsScene scene,
}) async {
if (state.isSendingCode || state.countdownSeconds > 0) return;
state = state.copyWith(isSendingCode: true, clearAlert: true);
try {
await ref.read(authRepositoryProvider).sendSmsCode(
phone: phone,
scene: scene,
);
_startCountdown();
} catch (e) {
state = state.copyWith(
isSendingCode: false,
alert: _messageOf(e),
);
}
}
/// 消费一次性提示。
void consumeAlert() {
if (state.alert != null) {
state = state.copyWith(clearAlert: true);
}
}
/// 登出。
void logout() {
_countdownTimer?.cancel();
TokenStorage.clear();
state = const AuthState();
}
Future<bool> _run(Future<LoginResult> Function() action) async {
state = state.copyWith(isLoading: true, clearAlert: true);
try {
await action();
state = state.copyWith(isLoading: false);
return true;
} catch (e) {
state = state.copyWith(isLoading: false, alert: _messageOf(e));
return false;
}
}
void _startCountdown() {
state = state.copyWith(isSendingCode: false, countdownSeconds: 60);
_countdownTimer?.cancel();
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
final left = state.countdownSeconds - 1;
if (left <= 0) {
timer.cancel();
state = state.copyWith(countdownSeconds: 0);
} else {
state = state.copyWith(countdownSeconds: left);
}
});
}
String _messageOf(Object e) {
if (e is Exception) {
return e.toString().replaceFirst('Exception: ', '');
}
return '操作失败,请稍后重试';
}
}
/// 认证控制器 Provider会话级 keepAlive 在 build 内通过 ref.keepAlive 实现)。
final authControllerProvider =
NotifierProvider<AuthController, AuthState>(AuthController.new);