You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
5.7 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../core/theme/app_colors.dart';
/// 通用语言选择栏组件
/// - 统一源/目标语言胶囊样式与交换按钮样式
/// - 通过函数读取语言显示文本,以便模块内保持最小改动
/// - 文案默认走 .tr,本地化显示语言名称(翻译键代表的中文文本内容)
class LanguageSelectorBar extends StatelessWidget {
const LanguageSelectorBar({
Key? key,
required this.sourceText,
required this.targetText,
required this.onTapSource,
required this.onTapTarget,
required this.onSwap,
this.translateLanguageNames = true,
this.fontSizeSp = 15,
this.sourceSuffix,
this.targetSuffix,
}) : super(key: key);
/// 返回源语言显示文本(建议返回语言中文名或翻译键)
final String Function() sourceText;
/// 返回目标语言显示文本(建议返回语言中文名或翻译键)
final String Function() targetText;
/// 源语言点击事件(打开语言选择弹窗)
final VoidCallback onTapSource;
/// 目标语言点击事件(打开语言选择弹窗)
final VoidCallback onTapTarget;
/// 语言交换事件
final VoidCallback onSwap;
/// 是否将语言名称作为翻译键进行翻译(翻译键代表的中文文本内容)
final bool translateLanguageNames;
/// 字号(sp单位),默认 15,与语音翻译一致
final double fontSizeSp;
/// 源语言后缀(可选),用于追加图标等
final Widget? sourceSuffix;
/// 目标语言后缀(可选),用于追加图标等
final Widget? targetSuffix;
@override
Widget build(BuildContext context) {
final isDarkMode = Get.isDarkMode;
final capsuleBg =
isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100];
final textColor = isDarkMode ? Colors.white : Colors.black;
final swapBg =
isDarkMode ? AppColors.primary.withOpacity(0.2) : Colors.blue[50];
final swapIconColor = isDarkMode ? AppColors.primary : Colors.blue;
// 规范化特殊项的翻译键,例如:自动检测 -> autoDetect(对应中文:自动检测)
String _normalizeKey(String text) {
switch (text) {
case '自动检测':
return 'autoDetect';
default:
return text; // 其他保持原值,由 .tr 决定是否命中
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 源语言胶囊
Expanded(
child: GestureDetector(
onTap: onTapSource,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: capsuleBg,
borderRadius: BorderRadius.circular(16.r),
),
child: Obx(() {
final raw = sourceText();
final text = translateLanguageNames ? _normalizeKey(raw) : raw;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
translateLanguageNames ? text.tr : text,
style: TextStyle(
fontSize: fontSizeSp.sp,
fontWeight: FontWeight.w600,
color: textColor,
),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
if (sourceSuffix != null) ...[
SizedBox(width: 4.w),
sourceSuffix!,
],
],
);
}),
),
),
),
// 语言互换按钮
GestureDetector(
onTap: onSwap,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 8.w),
padding: EdgeInsets.all(4.r),
decoration: BoxDecoration(
color: swapBg,
shape: BoxShape.circle,
),
child: Icon(
Icons.swap_horiz,
color: swapIconColor,
size: 20.sp,
),
),
),
// 目标语言胶囊
Expanded(
child: GestureDetector(
onTap: onTapTarget,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: capsuleBg,
borderRadius: BorderRadius.circular(16.r),
),
child: Obx(() {
final raw = targetText();
final text = translateLanguageNames ? _normalizeKey(raw) : raw;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
translateLanguageNames ? text.tr : text,
style: TextStyle(
fontSize: fontSizeSp.sp,
fontWeight: FontWeight.w600,
color: textColor,
),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
if (targetSuffix != null) ...[
SizedBox(width: 4.w),
targetSuffix!,
],
],
);
}),
),
),
),
],
);
}
}