Files
ReelShort/lib/pages/mine/widgets/mine_header.dart
T

180 lines
6.0 KiB
Dart

// Author: fruit.com.cn
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../../../core/data/services/auth_controller.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_dimens.dart';
import '../../../core/widgets/centered_toast.dart';
import '../../../core/widgets/remote_image.dart';
import '../../../l10n/app_localizations.dart';
const double _buttonHeight = 34;
const double _buttonRadius = 20;
/// 「我的」页用户区。
class MineHeader extends StatelessWidget {
const MineHeader({super.key, required this.onLogin, required this.onEdit});
final VoidCallback onLogin;
final VoidCallback onEdit;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final auth = context.watch<AuthController>();
final user = auth.user;
final signedIn = auth.isSignedIn;
final nickname = signedIn && (user?.nickname.trim().isNotEmpty ?? false)
? user!.nickname.trim()
: l10n.visitor;
final uid = signedIn ? user?.uid.trim() ?? '' : '';
return Padding(
key: const Key('mine-user-row'),
padding: const EdgeInsets.symmetric(vertical: AppDimens.spaceMd),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_avatar(user?.avatarUrl ?? ''),
const SizedBox(width: AppDimens.spaceMd),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
nickname,
key: const Key('mine-nickname'),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: 'Outfit',
color: AppColors.textPrimary,
fontSize: AppDimens.mineUserName,
fontWeight: FontWeight.w700,
height: AppDimens.mineUserNameLineHeight,
),
),
const SizedBox(height: AppDimens.mineUserNameUidGap),
SizedBox(
key: const Key('mine-uid'),
height: AppDimens.mineUidRowHeight,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
child: Text(
'${l10n.accountUid}: ${uid.isEmpty ? '--' : uid}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.textTertiary,
fontSize: AppDimens.mineUid,
),
),
),
Semantics(
button: true,
label: l10n.copyUid,
child: GestureDetector(
key: const Key('mine-uid-copy'),
behavior: HitTestBehavior.opaque,
onTap: uid.isEmpty
? null
: () => unawaited(
_copyUid(context, uid, l10n.uidCopied),
),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 4),
child: Icon(
Icons.copy_rounded,
color: AppColors.textTertiary,
size: AppDimens.mineCopyIcon,
),
),
),
),
],
),
),
],
),
),
const SizedBox(width: AppDimens.spaceSm),
_accountButton(
key: signedIn ? const Key('mine-edit') : const Key('mine-login'),
label: signedIn ? l10n.edit : l10n.logIn,
onTap: signedIn ? onEdit : onLogin,
),
],
),
);
}
Widget _avatar(String path) {
return Container(
key: const Key('mine-avatar'),
width: AppDimens.mineAvatar,
height: AppDimens.mineAvatar,
decoration: const BoxDecoration(
color: AppColors.contentSurface,
shape: BoxShape.circle,
),
clipBehavior: Clip.antiAlias,
child: path.isEmpty
? const Icon(
Icons.person_rounded,
color: AppColors.textPrimary,
size: 28,
)
: RemoteImage(path, fit: BoxFit.cover),
);
}
Widget _accountButton({
required Key key,
required String label,
required VoidCallback onTap,
}) {
return OutlinedButton(
key: key,
onPressed: onTap,
style: OutlinedButton.styleFrom(
minimumSize: const Size(0, _buttonHeight),
padding: const EdgeInsets.symmetric(horizontal: AppDimens.spaceMd),
foregroundColor: AppColors.textPrimary,
side: const BorderSide(color: AppColors.mineOutline),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(_buttonRadius),
),
textStyle: const TextStyle(
fontSize: AppDimens.body,
fontWeight: FontWeight.w500,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(label),
const SizedBox(width: 2),
const Icon(Icons.chevron_right_rounded, size: 17),
],
),
);
}
Future<void> _copyUid(
BuildContext context,
String uid,
String message,
) async {
await Clipboard.setData(ClipboardData(text: uid));
if (context.mounted) showCenteredToast(context, message);
}
}