- 清理大量废弃的 barrel 导出文件,移除冗余的中间导出层 - 修复所有相对路径导入错误,统一调整为扁平化模块引用 - 更新多平台 pubspec 版本号与依赖库版本 - 补充后端功能问题管理后台与脚本工具 - 调整部分页面的快捷方式文案适配新功能 - 更新部分翻译覆盖率与API文档
107 lines
3.7 KiB
Dart
107 lines
3.7 KiB
Dart
/// ============================================================
|
||
/// 闲言APP — 认证感知Mixin
|
||
/// 创建时间: 2026-05-28
|
||
/// 更新时间: 2026-06-12
|
||
/// 作用: 统一401认证错误处理,监听auth状态变化自动重载数据
|
||
/// 上次更新: 从 mixins/ 子目录上移至 shared/ 目录
|
||
/// ============================================================
|
||
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:xianyan/core/theme/app_theme.dart';
|
||
import 'package:xianyan/core/theme/app_spacing.dart';
|
||
import 'package:xianyan/core/theme/app_typography.dart';
|
||
import 'package:xianyan/core/theme/app_radius.dart';
|
||
import 'package:xianyan/core/providers/auth_state.dart';
|
||
import 'package:xianyan/core/router/app_nav_extension.dart';
|
||
import 'package:xianyan/core/router/app_routes.dart';
|
||
|
||
mixin AuthAwareMixin<T extends ConsumerStatefulWidget> on ConsumerState<T> {
|
||
bool _authInitialized = false;
|
||
ProviderSubscription<AuthState>? _authSubscription;
|
||
|
||
/// 子类重写此方法,在登录状态变化时重新加载数据
|
||
void onAuthChanged(bool isLoggedIn);
|
||
|
||
/// 构建认证错误引导界面
|
||
Widget buildAuthErrorView({
|
||
String title = '需要登录查看',
|
||
String subtitle = '登录后即可查看专属内容',
|
||
String actionLabel = '登录',
|
||
}) {
|
||
final ext = AppTheme.ext(context);
|
||
return Center(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(AppSpacing.xl),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Container(
|
||
width: 64,
|
||
height: 64,
|
||
decoration: BoxDecoration(
|
||
color: ext.accent.withValues(alpha: 0.1),
|
||
borderRadius: BorderRadius.circular(20),
|
||
),
|
||
child: const Center(
|
||
child: Text('🔒', style: TextStyle(fontSize: 28)),
|
||
),
|
||
),
|
||
const SizedBox(height: AppSpacing.md),
|
||
Text(
|
||
title,
|
||
style: AppTypography.title3.copyWith(
|
||
color: ext.textPrimary,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
const SizedBox(height: AppSpacing.xs),
|
||
Text(
|
||
subtitle,
|
||
style: AppTypography.subhead.copyWith(color: ext.textSecondary),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
const SizedBox(height: AppSpacing.lg),
|
||
SizedBox(
|
||
width: 200,
|
||
child: CupertinoButton(
|
||
color: ext.accent,
|
||
borderRadius: AppRadius.lgBorder,
|
||
padding: const EdgeInsets.symmetric(vertical: AppSpacing.sm),
|
||
onPressed: () => context.appPush(AppRoutes.login),
|
||
child: Text(
|
||
actionLabel,
|
||
style: AppTypography.subhead.copyWith(
|
||
color: ext.textInverse,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 自动关闭认证监听器,子类dispose时无需手动调用
|
||
/// 若子类也override dispose,必须调用super.dispose()
|
||
@override
|
||
void dispose() {
|
||
_authSubscription?.close();
|
||
_authSubscription = null;
|
||
super.dispose();
|
||
}
|
||
|
||
/// 初始化认证监听,应在initState的addPostFrameCallback中调用
|
||
void initAuthListener() {
|
||
if (_authInitialized) return;
|
||
_authInitialized = true;
|
||
_authSubscription = ref.listenManual(authStateProvider, (prev, next) {
|
||
if (prev?.isLoggedIn != next.isLoggedIn) {
|
||
onAuthChanged(next.isLoggedIn);
|
||
}
|
||
}, fireImmediately: false);
|
||
}
|
||
}
|