Files
flutterApp/lib/components/language_selection_dialog.dart

94 lines
3.2 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 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:maibu_satabot_v2/core/localization/locale_cubit.dart';
/// 可选语言项:tag 对应 assets/languages/{tag}.json,nativeName 用该语言本地写法展示。
class LanguageItem {
final Locale locale;
final String nativeName;
const LanguageItem(this.locale, this.nativeName);
String get tag => locale.countryCode == null || locale.countryCode!.isEmpty
? locale.languageCode
: '${locale.languageCode}-${locale.countryCode}';
}
/// 全局唯一的“可选语言列表”来源。
/// 后续接入“接口下载语言包”时,只需在这里扩展(例如把已下载的语言追加进来),
/// 登录强制弹窗与设置页入口都会自动同步,无需改多处。
class AppLanguages {
AppLanguages._();
static final AppLanguages instance = AppLanguages._();
final List<LanguageItem> items = const [
LanguageItem(Locale('zh', 'CN'), '简体中文'),
LanguageItem(Locale('en', 'US'), 'English'),
];
String nameOf(Locale locale) {
final tag = locale.countryCode == null || locale.countryCode!.isEmpty
? locale.languageCode
: '${locale.languageCode}-${locale.countryCode}';
for (final item in items) {
if (item.tag == tag) return item.nativeName;
}
return tag;
}
}
/// 语言选择弹窗。
/// [mandatory] = true:登录时强制选择,不可返回/点外部关闭;
/// [mandatory] = false:设置页中可随时关闭。
class LanguageSelectionDialog extends StatelessWidget {
final bool mandatory;
const LanguageSelectionDialog({super.key, this.mandatory = true});
Future<void> _onSelect(BuildContext context, Locale locale) async {
await context.read<LocaleCubit>().setLocale(locale);
if (context.mounted) Navigator.of(context).pop();
}
@override
Widget build(BuildContext context) {
final current = context.select<LocaleCubit, Locale>(
(c) => c.state,
);
return PopScope(
// 强制弹窗时拦截返回键,必须选一个才能继续使用
canPop: !mandatory,
child: AlertDialog(
title: const Text('选择语言 / Select Language'),
content: SizedBox(
width: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
for (final item in AppLanguages.instance.items)
RadioListTile<String>(
value: item.tag,
// 高亮当前语言:按 languageCode 匹配,兼容国家码为空的历史值
groupValue: current.countryCode == null ||
current.countryCode!.isEmpty
? current.languageCode
: '${current.languageCode}-${current.countryCode}',
title: Text(item.nativeName),
onChanged: (_) => _onSelect(context, item.locale),
),
],
),
),
actions: mandatory
? null
: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
],
),
);
}
}