app/lib/ui/home/localization/advanced_localization_ui.dart

344 lines
13 KiB
Dart
Raw Normal View History

2024-05-03 22:35:31 +08:00
import 'package:fluent_ui/fluent_ui.dart';
2024-05-05 14:59:07 +08:00
import 'package:flutter_hooks/flutter_hooks.dart';
2024-05-03 22:35:31 +08:00
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
2024-05-05 14:59:07 +08:00
import 'package:go_router/go_router.dart';
2024-05-03 22:35:31 +08:00
import 'package:hooks_riverpod/hooks_riverpod.dart';
2024-05-05 14:59:07 +08:00
import 'package:re_editor/re_editor.dart';
import 'package:re_highlight/languages/ini.dart';
import 'package:re_highlight/styles/vs2015.dart';
2024-05-07 21:08:16 +08:00
import 'package:starcitizen_doctor/api/analytics.dart';
2024-05-05 14:59:07 +08:00
import 'package:starcitizen_doctor/data/app_advanced_localization_data.dart';
2024-05-03 22:35:31 +08:00
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:starcitizen_doctor/ui/home/localization/advanced_localization_ui_model.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:super_sliver_list/super_sliver_list.dart';
2024-05-05 20:58:58 +08:00
import 'localization_form_file_dialog_ui.dart';
2024-05-03 22:35:31 +08:00
class AdvancedLocalizationUI extends HookConsumerWidget {
const AdvancedLocalizationUI({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(advancedLocalizationUIModelProvider);
2024-05-05 14:59:07 +08:00
final model = ref.read(advancedLocalizationUIModelProvider.notifier);
2024-05-03 22:35:31 +08:00
final homeUIState = ref.watch(homeUIModelProvider);
2024-05-05 20:58:58 +08:00
onSwitchFile() async {
final sb = await showDialog(
context: context,
builder: (BuildContext context) => const LocalizationFromFileDialogUI(),
);
if (sb is StringBuffer) {
model.setCustomizeGlobalIni(sb.toString());
}
}
2024-05-07 21:08:16 +08:00
useEffect(() {
AnalyticsApi.touch("advanced_localization_launch");
return null;
}, const []);
2024-05-03 22:35:31 +08:00
return makeDefaultPage(
2024-05-05 16:34:38 +08:00
title: S.current.home_localization_advanced_title(
homeUIState.scInstalledPath ?? "-"),
2024-05-03 22:35:31 +08:00
context,
content: state.workingText.isNotEmpty
? Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ProgressRing(),
const SizedBox(height: 12),
Text(state.workingText),
],
),
)
2024-05-05 14:59:07 +08:00
: Column(
children: [
if (state.errorMessage.isNotEmpty)
2024-09-04 17:18:13 +08:00
ErrorMessageWidget(
errorMessage: state.errorMessage,
)
else ...[
Row(
children: [
const SizedBox(width: 12),
Expanded(
child: Row(
children: [
Text(
S.current.home_localization_advanced_msg_version(
state.apiLocalizationData?.versionName ??
"-"),
),
2024-05-05 20:58:58 +08:00
const SizedBox(width: 12),
Button(
onPressed: onSwitchFile,
2024-05-05 20:58:58 +08:00
child: const Padding(
padding: EdgeInsets.symmetric(
horizontal: 6, vertical: 3),
child: Icon(FluentIcons.switch_widget),
2024-05-05 20:58:58 +08:00
)),
if (state.customizeGlobalIni != null) ...[
const SizedBox(width: 12),
Button(
onPressed: () {
model.setCustomizeGlobalIni(null);
},
child: const Padding(
padding: EdgeInsets.symmetric(
horizontal: 6, vertical: 3),
child: Icon(FluentIcons.delete),
)),
]
],
)),
Text(S.current.home_localization_advanced_title_msg(
state.serverGlobalIniLines,
state.p4kGlobalIniLines)),
const SizedBox(width: 32),
Button(
child: Padding(
padding: const EdgeInsets.only(
left: 12, right: 12, top: 4, bottom: 4),
child: Text(S.current
.home_localization_advanced_action_install),
),
onPressed: () async {
await model.doInstall().unwrap(context: context);
}),
const SizedBox(width: 12),
],
),
Expanded(
child:
_makeBody(context, homeUIState, state, ref, model)),
]
2024-05-05 14:59:07 +08:00
],
));
2024-05-03 22:35:31 +08:00
}
2024-05-05 14:59:07 +08:00
Widget _makeBody(
BuildContext context,
HomeUIModelState homeUIState,
AdvancedLocalizationUIState state,
WidgetRef ref,
AdvancedLocalizationUIModel model) {
2024-05-03 22:35:31 +08:00
return AlignedGridView.count(
2024-05-05 14:59:07 +08:00
crossAxisCount: 4,
2024-05-03 22:35:31 +08:00
crossAxisSpacing: 12,
mainAxisSpacing: 12,
padding: const EdgeInsets.all(12),
itemBuilder: (BuildContext context, int index) {
final item = state.classMap!.values.elementAt(index);
return Container(
2024-05-05 14:59:07 +08:00
padding: const EdgeInsets.only(top: 6, bottom: 12),
2024-05-03 22:35:31 +08:00
decoration: BoxDecoration(
color: Colors.white.withOpacity(.05),
borderRadius: BorderRadius.circular(4),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
2024-05-05 14:59:07 +08:00
IconButton(
onPressed:
item.isWorking ? null : () => _showContent(context, item),
icon: Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: Row(
children: [
Expanded(
child: Text(
"${item.className}",
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
)),
Text(
"${item.valuesMap.length}",
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(.6),
),
),
const SizedBox(width: 6),
Icon(
FluentIcons.chevron_right,
2024-05-03 22:35:31 +08:00
color: Colors.white.withOpacity(.6),
2024-05-05 14:59:07 +08:00
size: 16,
2024-05-03 22:35:31 +08:00
),
2024-05-05 14:59:07 +08:00
],
),
2024-05-03 22:35:31 +08:00
),
),
Container(
margin: const EdgeInsets.only(top: 6, bottom: 12),
width: MediaQuery.of(context).size.width,
height: 1,
color: Colors.white.withOpacity(.1),
),
2024-05-05 14:59:07 +08:00
if (item.isWorking)
Column(
children: [
makeLoading(context),
const SizedBox(height: 6),
2024-05-05 16:34:38 +08:00
Text(
S.current.home_localization_advanced_action_mod_change),
2024-05-05 14:59:07 +08:00
],
)
else ...[
Padding(
2024-05-03 22:35:31 +08:00
padding: const EdgeInsets.only(left: 12, right: 12),
2024-05-05 14:59:07 +08:00
child: Row(
children: [
2024-05-05 16:34:38 +08:00
Expanded(
child: Text(S
.current.home_localization_advanced_action_mode)),
2024-05-05 14:59:07 +08:00
ComboBox(
value: item.mode,
items: [
for (final type
in AppAdvancedLocalizationClassKeysDataMode
.values)
ComboBoxItem(
value: type,
child: Text(state.typeNames[type] ?? "-"),
),
],
onChanged: item.lockMod
? null
: (v) => model.onChangeMod(item,
v as AppAdvancedLocalizationClassKeysDataMode),
2024-05-03 22:35:31 +08:00
),
2024-05-05 14:59:07 +08:00
],
),
2024-05-03 22:35:31 +08:00
),
2024-05-05 14:59:07 +08:00
const SizedBox(height: 6),
SizedBox(
height: 180,
child: SuperListView.builder(
itemCount: item.valuesMap.length,
padding: const EdgeInsets.only(left: 12, right: 12),
itemBuilder: (BuildContext context, int index) {
final itemKey = item.valuesMap.keys.elementAt(index);
return Text(
"${item.valuesMap[itemKey]}",
maxLines: 1,
style: const TextStyle(
fontSize: 12,
overflow: TextOverflow.ellipsis,
),
);
},
),
),
],
2024-05-03 22:35:31 +08:00
],
),
);
},
itemCount: state.classMap?.length ?? 0,
);
}
2024-05-05 14:59:07 +08:00
_showContent(
BuildContext context, AppAdvancedLocalizationClassKeysData item) {
showDialog(
context: context,
builder: (BuildContext context) {
return HookConsumer(
builder: (BuildContext context, WidgetRef ref, Widget? child) {
final textData = useState("");
loadData() async {
final v = StringBuffer("");
for (var element in item.valuesMap.entries) {
v.write("${element.key}=${element.value}\n");
await Future.delayed(Duration.zero);
}
textData.value = v.toString();
}
useEffect(() {
loadData();
return null;
}, const []);
return ContentDialog(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .8,
),
title: Row(
children: [
IconButton(
icon: const Icon(
FluentIcons.back,
size: 22,
),
onPressed: () => context.pop()),
const SizedBox(
width: 24,
),
2024-05-05 16:34:38 +08:00
Text(S.current.home_localization_advanced_title_preview(
item.className ?? "-")),
2024-05-05 14:59:07 +08:00
],
),
content: textData.value.isEmpty
? makeLoading(context)
: Container(
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(7),
),
child: CodeEditor(
readOnly: true,
controller:
CodeLineEditingController.fromText(textData.value),
style: CodeEditorStyle(
codeTheme: CodeHighlightTheme(
languages: {
'ini': CodeHighlightThemeMode(mode: langIni)
},
theme: vs2015Theme,
),
),
),
),
);
},
);
},
);
}
2024-05-03 22:35:31 +08:00
}
2024-09-04 17:18:13 +08:00
class ErrorMessageWidget extends HookConsumerWidget {
final String errorMessage;
const ErrorMessageWidget({super.key, required this.errorMessage});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.red.withOpacity(.1),
borderRadius: BorderRadius.circular(4),
),
child: Row(
children: [
const Icon(FluentIcons.error),
const SizedBox(width: 12),
Expanded(
child: Text(
errorMessage,
style: TextStyle(color: Colors.red),
),
),
],
),
);
}
}