feat: CommunityInputMethod Install

This commit is contained in:
xkeyC 2024-11-05 20:42:02 +08:00
parent 8d07af2253
commit 281f6ee995
7 changed files with 281 additions and 20 deletions

View File

@ -7,6 +7,7 @@ import 'package:starcitizen_doctor/data/app_placard_data.dart';
import 'package:starcitizen_doctor/data/app_torrent_data.dart';
import 'package:starcitizen_doctor/data/app_version_data.dart';
import 'package:starcitizen_doctor/data/countdown_festival_item_data.dart';
import 'package:starcitizen_doctor/data/input_method_api_data.dart';
import 'package:starcitizen_doctor/data/sc_localization_data.dart';
class Api {
@ -52,6 +53,15 @@ class Api {
return l;
}
static Future<InputMethodApiData> getCommunityInputMethodIndexData() async {
final data = await getCommunityInputMethodData("index.json");
return InputMethodApiData.fromJson(json.decode(data));
}
static Future<String> getCommunityInputMethodData(String file) async {
return getRepoData("input_method", file);
}
static Future<List<AppTorrentData>> getAppTorrentDataList() async {
final data = await getRepoData("sc_doctor", "torrent.json");
final dataJson = json.decode(data);
@ -83,13 +93,15 @@ class Api {
}
static Future<String> getRepoData(String dir, String name) async {
final r = await RSHttp.getText("${URLConf.apiRepoPath}/$dir/$name",withCustomDns: await isUseInternalDNS());
final r = await RSHttp.getText("${URLConf.apiRepoPath}/$dir/$name",
withCustomDns: await isUseInternalDNS());
return r;
}
static Future<bool> isUseInternalDNS() async {
final userBox = await Hive.openBox("app_conf");
final isUseInternalDNS = userBox.get("isUseInternalDNS", defaultValue: false);
final isUseInternalDNS =
userBox.get("isUseInternalDNS", defaultValue: false);
return isUseInternalDNS;
}
}

View File

@ -0,0 +1,52 @@
class InputMethodApiData {
InputMethodApiData({
this.enable,
this.languages,
});
InputMethodApiData.fromJson(dynamic json) {
enable = json['enable'];
if (json['languages'] != null) {
languages = <String, InputMethodApiLanguageData>{};
json['languages'].forEach((String key, dynamic v) {
languages![key] = InputMethodApiLanguageData.fromJson(v);
});
}
}
bool? enable;
Map<String, InputMethodApiLanguageData>? languages;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['enable'] = enable;
if (languages != null) {
map['languages'] = languages!.map<String, dynamic>((key, value) {
return MapEntry(key, value.toJson());
});
}
return map;
}
}
class InputMethodApiLanguageData {
InputMethodApiLanguageData({
this.file,
this.version,
});
InputMethodApiLanguageData.fromJson(dynamic json) {
file = json['file'];
version = json['version'];
}
String? file;
String? version;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['file'] = file;
map['version'] = version;
return map;
}
}

View File

@ -4,6 +4,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/data/sc_localization_data.dart';
import 'package:starcitizen_doctor/ui/tools/tools_ui_model.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
@ -102,10 +103,22 @@ class LocalizationDialogUI extends HookConsumerWidget {
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: Row(
children: [
Text(S.current.localization_info_installed_version(
"${state.patchStatus?.value ?? ""} ${(state.isInstalledAdvanced ?? false) ? S.current.home_localization_msg_version_advanced : ""}")),
const Spacer(),
SizedBox(width: 24),
if (state
.installedCommunityInputMethodSupportVersion !=
null)
Text(
"社区输入法支持:${state.installedCommunityInputMethodSupportVersion}",
)
],
),
),
if (state.patchStatus?.value !=
S.current.home_action_info_game_built_in)
Row(
@ -415,6 +428,8 @@ class LocalizationDialogUI extends HookConsumerWidget {
LocalizationUIModel model,
MapEntry<String, ScLocalizationData> item,
LocalizationUIState state) async {
bool enableCommunityInputMethod =
state.communityInputMethodLanguageData != null;
final userOK = await showConfirmDialogs(
context,
"${item.value.info}",
@ -443,6 +458,7 @@ class LocalizationDialogUI extends HookConsumerWidget {
.localization_info_update_time(item.value.updateAt ?? ""),
style: TextStyle(color: Colors.white.withOpacity(.6)),
),
const SizedBox(height: 12),
],
),
const SizedBox(height: 12),
@ -462,6 +478,29 @@ class LocalizationDialogUI extends HookConsumerWidget {
],
),
),
SizedBox(height: 12),
Row(
children: [
Text(
"安装社区输入法支持",
),
Spacer(),
StatefulBuilder(
builder: (BuildContext context,
void Function(void Function()) setState) {
return ToggleSwitch(
checked: enableCommunityInputMethod,
onChanged: state.communityInputMethodLanguageData == null
? null
: (v) {
enableCommunityInputMethod = v;
setState(() {});
},
);
},
)
],
)
],
),
confirm: S.current.localization_action_install,
@ -471,7 +510,11 @@ class LocalizationDialogUI extends HookConsumerWidget {
);
if (userOK) {
if (!context.mounted) return;
model.doRemoteInstall(context, item.value)?.call();
dPrint("doRemoteInstall ${item.value} $enableCommunityInputMethod");
model
.doRemoteInstall(context, item.value,
isEnableCommunityInputMethod: enableCommunityInputMethod)
?.call();
}
}

View File

@ -15,6 +15,7 @@ import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/data/input_method_api_data.dart';
import 'package:starcitizen_doctor/data/sc_localization_data.dart';
import 'package:starcitizen_doctor/generated/no_l10n_strings.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
@ -29,6 +30,8 @@ part 'localization_ui_model.freezed.dart';
class LocalizationUIState with _$LocalizationUIState {
factory LocalizationUIState({
String? selectedLanguage,
String? installedCommunityInputMethodSupportVersion,
InputMethodApiLanguageData? communityInputMethodLanguageData,
Map<String, ScLocalizationData>? apiLocalizationData,
@Default("") String workingVersion,
MapEntry<bool, String>? patchStatus,
@ -83,9 +86,28 @@ class LocalizationUIModel extends _$LocalizationUIModel {
final Map<String, Map<String, ScLocalizationData>>
_allVersionLocalizationData = {};
Future<void> _loadCommunityInputMethodData() async {
try {
final data = await Api.getCommunityInputMethodIndexData();
if (data.enable ?? false) {
final lang = state.selectedLanguage;
if (lang != null) {
final l = data.languages?[lang];
if (l != null) {
state = state.copyWith(communityInputMethodLanguageData: l);
dPrint("loadCommunityInputMethodData: ${l.toJson()}");
}
}
}
} catch (e) {
dPrint("loadCommunityInputMethodData error: $e");
}
}
Future<void> _loadData() async {
_allVersionLocalizationData.clear();
await _updateStatus();
await _loadCommunityInputMethodData();
for (var lang in languageSupport.keys) {
final l = await Api.getScLocalizationData(lang).unwrap();
if (l != null) {
@ -211,8 +233,13 @@ class LocalizationUIModel extends _$LocalizationUIModel {
return path.split("\\").last;
}
installFormString(StringBuffer globalIni, String versionName,
{bool? advanced}) async {
installFormString(
StringBuffer globalIni,
String versionName, {
bool? advanced,
String? communityInputMethodVersion,
String? communityInputMethodSupportData,
}) async {
dPrint("LocalizationUIModel -> installFormString $versionName");
final iniFile = File(
"${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini");
@ -223,6 +250,15 @@ class LocalizationUIModel extends _$LocalizationUIModel {
if (advanced ?? false) {
globalIni.write("_starcitizen_doctor_localization_advanced=true\n");
}
if (communityInputMethodVersion != null) {
globalIni.write(
"_starcitizen_doctor_localization_community_input_method_version=$communityInputMethodVersion\n");
}
if (communityInputMethodSupportData != null) {
for (var line in communityInputMethodSupportData.split("\n")) {
globalIni.write("$line\n");
}
}
globalIni
.write("_starcitizen_doctor_localization_version=$versionName\n");
}
@ -241,8 +277,8 @@ class LocalizationUIModel extends _$LocalizationUIModel {
await _updateStatus();
}
VoidCallback? doRemoteInstall(
BuildContext context, ScLocalizationData value) {
VoidCallback? doRemoteInstall(BuildContext context, ScLocalizationData value,
{bool isEnableCommunityInputMethod = false}) {
return () async {
AnalyticsApi.touch("install_localization");
@ -256,13 +292,33 @@ class LocalizationUIModel extends _$LocalizationUIModel {
} else {
dPrint("use cache $savePath");
}
final communityInputMethodData = state.communityInputMethodLanguageData;
String? communityInputMethodSupportData;
if (isEnableCommunityInputMethod && communityInputMethodData != null) {
final str = await downloadOrGetCachedCommunityInputMethodSupportFile(
communityInputMethodData);
if (str.trim().isNotEmpty) {
communityInputMethodSupportData = str;
}
}
await Future.delayed(const Duration(milliseconds: 300));
// check file
final globalIni = await compute(readArchive, savePath.absolute.path);
if (globalIni.isEmpty) {
throw S.current.localization_info_corrupted_file;
}
await installFormString(globalIni, value.versionName ?? "");
await installFormString(
globalIni,
value.versionName ?? "",
communityInputMethodSupportData: communityInputMethodSupportData,
communityInputMethodVersion: isEnableCommunityInputMethod
? communityInputMethodData?.version
: null,
);
} catch (e) {
if (!context.mounted) return;
await showToast(
@ -273,6 +329,21 @@ class LocalizationUIModel extends _$LocalizationUIModel {
};
}
Future<String> downloadOrGetCachedCommunityInputMethodSupportFile(
InputMethodApiLanguageData communityInputMethodData) async {
final lang = state.selectedLanguage ?? "_";
final box = await Hive.openBox("community_input_method_data");
final cachedVersion = box.get("${lang}_version");
if (cachedVersion != communityInputMethodData.version) {
final data = await Api.getCommunityInputMethodData(
communityInputMethodData.file ?? "");
await box.put("${lang}_data", data);
return data;
}
return box.get("${lang}_data").toString();
}
Future<void> downloadLocalizationFile(
File savePath, ScLocalizationData value) async {
dPrint("downloading file to $savePath");
@ -310,7 +381,8 @@ class LocalizationUIModel extends _$LocalizationUIModel {
}
void selectLang(String v) async {
state = state.copyWith(selectedLanguage: v);
state = state.copyWith(
selectedLanguage: v, communityInputMethodLanguageData: null);
_loadData();
final appConfBox = await Hive.openBox("app_conf");
await appConfBox.put("localization_selectedLanguage", v);
@ -332,14 +404,42 @@ class LocalizationUIModel extends _$LocalizationUIModel {
}
_updateStatus() async {
final iniPath =
"${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini";
final patchStatus = MapEntry(
await _getLangCfgEnableLang(lang: state.selectedLanguage!),
await _getInstalledIniVersion(
"${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini"));
final isInstalledAdvanced = await _checkAdvancedStatus(
"${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini");
await _getInstalledIniVersion(iniPath));
final isInstalledAdvanced = await _checkAdvancedStatus(iniPath);
final installedCommunityInputMethodSupportVersion =
await getInstalledCommunityInputMethodSupportVersion(iniPath);
dPrint(
"_updateStatus updateStatus: $patchStatus , isInstalledAdvanced: $isInstalledAdvanced ,installedCommunityInputMethodSupportVersion: $installedCommunityInputMethodSupportVersion");
state = state.copyWith(
patchStatus: patchStatus, isInstalledAdvanced: isInstalledAdvanced);
patchStatus: patchStatus,
isInstalledAdvanced: isInstalledAdvanced,
installedCommunityInputMethodSupportVersion:
installedCommunityInputMethodSupportVersion,
);
}
Future<String?> getInstalledCommunityInputMethodSupportVersion(
String path) async {
final iniFile = File(path);
if (!await iniFile.exists()) {
return null;
}
final iniStringSplit = (await iniFile.readAsString()).split("\n");
for (var i = iniStringSplit.length - 1; i > 0; i--) {
if (iniStringSplit[i].contains(
"_starcitizen_doctor_localization_community_input_method_version=")) {
final v = iniStringSplit[i].trim().split(
"_starcitizen_doctor_localization_community_input_method_version=")[1];
return v;
}
}
return null;
}
Future<bool> _checkAdvancedStatus(String path) async {

View File

@ -17,6 +17,10 @@ final _privateConstructorUsedError = UnsupportedError(
/// @nodoc
mixin _$LocalizationUIState {
String? get selectedLanguage => throw _privateConstructorUsedError;
String? get installedCommunityInputMethodSupportVersion =>
throw _privateConstructorUsedError;
InputMethodApiLanguageData? get communityInputMethodLanguageData =>
throw _privateConstructorUsedError;
Map<String, ScLocalizationData>? get apiLocalizationData =>
throw _privateConstructorUsedError;
String get workingVersion => throw _privateConstructorUsedError;
@ -39,6 +43,8 @@ abstract class $LocalizationUIStateCopyWith<$Res> {
@useResult
$Res call(
{String? selectedLanguage,
String? installedCommunityInputMethodSupportVersion,
InputMethodApiLanguageData? communityInputMethodLanguageData,
Map<String, ScLocalizationData>? apiLocalizationData,
String workingVersion,
MapEntry<bool, String>? patchStatus,
@ -62,6 +68,8 @@ class _$LocalizationUIStateCopyWithImpl<$Res, $Val extends LocalizationUIState>
@override
$Res call({
Object? selectedLanguage = freezed,
Object? installedCommunityInputMethodSupportVersion = freezed,
Object? communityInputMethodLanguageData = freezed,
Object? apiLocalizationData = freezed,
Object? workingVersion = null,
Object? patchStatus = freezed,
@ -73,6 +81,16 @@ class _$LocalizationUIStateCopyWithImpl<$Res, $Val extends LocalizationUIState>
? _value.selectedLanguage
: selectedLanguage // ignore: cast_nullable_to_non_nullable
as String?,
installedCommunityInputMethodSupportVersion: freezed ==
installedCommunityInputMethodSupportVersion
? _value.installedCommunityInputMethodSupportVersion
: installedCommunityInputMethodSupportVersion // ignore: cast_nullable_to_non_nullable
as String?,
communityInputMethodLanguageData: freezed ==
communityInputMethodLanguageData
? _value.communityInputMethodLanguageData
: communityInputMethodLanguageData // ignore: cast_nullable_to_non_nullable
as InputMethodApiLanguageData?,
apiLocalizationData: freezed == apiLocalizationData
? _value.apiLocalizationData
: apiLocalizationData // ignore: cast_nullable_to_non_nullable
@ -107,6 +125,8 @@ abstract class _$$LocalizationUIStateImplCopyWith<$Res>
@useResult
$Res call(
{String? selectedLanguage,
String? installedCommunityInputMethodSupportVersion,
InputMethodApiLanguageData? communityInputMethodLanguageData,
Map<String, ScLocalizationData>? apiLocalizationData,
String workingVersion,
MapEntry<bool, String>? patchStatus,
@ -128,6 +148,8 @@ class __$$LocalizationUIStateImplCopyWithImpl<$Res>
@override
$Res call({
Object? selectedLanguage = freezed,
Object? installedCommunityInputMethodSupportVersion = freezed,
Object? communityInputMethodLanguageData = freezed,
Object? apiLocalizationData = freezed,
Object? workingVersion = null,
Object? patchStatus = freezed,
@ -139,6 +161,16 @@ class __$$LocalizationUIStateImplCopyWithImpl<$Res>
? _value.selectedLanguage
: selectedLanguage // ignore: cast_nullable_to_non_nullable
as String?,
installedCommunityInputMethodSupportVersion: freezed ==
installedCommunityInputMethodSupportVersion
? _value.installedCommunityInputMethodSupportVersion
: installedCommunityInputMethodSupportVersion // ignore: cast_nullable_to_non_nullable
as String?,
communityInputMethodLanguageData: freezed ==
communityInputMethodLanguageData
? _value.communityInputMethodLanguageData
: communityInputMethodLanguageData // ignore: cast_nullable_to_non_nullable
as InputMethodApiLanguageData?,
apiLocalizationData: freezed == apiLocalizationData
? _value._apiLocalizationData
: apiLocalizationData // ignore: cast_nullable_to_non_nullable
@ -168,6 +200,8 @@ class __$$LocalizationUIStateImplCopyWithImpl<$Res>
class _$LocalizationUIStateImpl implements _LocalizationUIState {
_$LocalizationUIStateImpl(
{this.selectedLanguage,
this.installedCommunityInputMethodSupportVersion,
this.communityInputMethodLanguageData,
final Map<String, ScLocalizationData>? apiLocalizationData,
this.workingVersion = "",
this.patchStatus,
@ -178,6 +212,10 @@ class _$LocalizationUIStateImpl implements _LocalizationUIState {
@override
final String? selectedLanguage;
@override
final String? installedCommunityInputMethodSupportVersion;
@override
final InputMethodApiLanguageData? communityInputMethodLanguageData;
final Map<String, ScLocalizationData>? _apiLocalizationData;
@override
Map<String, ScLocalizationData>? get apiLocalizationData {
@ -208,7 +246,7 @@ class _$LocalizationUIStateImpl implements _LocalizationUIState {
@override
String toString() {
return 'LocalizationUIState(selectedLanguage: $selectedLanguage, apiLocalizationData: $apiLocalizationData, workingVersion: $workingVersion, patchStatus: $patchStatus, isInstalledAdvanced: $isInstalledAdvanced, customizeList: $customizeList)';
return 'LocalizationUIState(selectedLanguage: $selectedLanguage, installedCommunityInputMethodSupportVersion: $installedCommunityInputMethodSupportVersion, communityInputMethodLanguageData: $communityInputMethodLanguageData, apiLocalizationData: $apiLocalizationData, workingVersion: $workingVersion, patchStatus: $patchStatus, isInstalledAdvanced: $isInstalledAdvanced, customizeList: $customizeList)';
}
@override
@ -218,6 +256,14 @@ class _$LocalizationUIStateImpl implements _LocalizationUIState {
other is _$LocalizationUIStateImpl &&
(identical(other.selectedLanguage, selectedLanguage) ||
other.selectedLanguage == selectedLanguage) &&
(identical(other.installedCommunityInputMethodSupportVersion,
installedCommunityInputMethodSupportVersion) ||
other.installedCommunityInputMethodSupportVersion ==
installedCommunityInputMethodSupportVersion) &&
(identical(other.communityInputMethodLanguageData,
communityInputMethodLanguageData) ||
other.communityInputMethodLanguageData ==
communityInputMethodLanguageData) &&
const DeepCollectionEquality()
.equals(other._apiLocalizationData, _apiLocalizationData) &&
(identical(other.workingVersion, workingVersion) ||
@ -234,6 +280,8 @@ class _$LocalizationUIStateImpl implements _LocalizationUIState {
int get hashCode => Object.hash(
runtimeType,
selectedLanguage,
installedCommunityInputMethodSupportVersion,
communityInputMethodLanguageData,
const DeepCollectionEquality().hash(_apiLocalizationData),
workingVersion,
patchStatus,
@ -253,6 +301,8 @@ class _$LocalizationUIStateImpl implements _LocalizationUIState {
abstract class _LocalizationUIState implements LocalizationUIState {
factory _LocalizationUIState(
{final String? selectedLanguage,
final String? installedCommunityInputMethodSupportVersion,
final InputMethodApiLanguageData? communityInputMethodLanguageData,
final Map<String, ScLocalizationData>? apiLocalizationData,
final String workingVersion,
final MapEntry<bool, String>? patchStatus,
@ -262,6 +312,10 @@ abstract class _LocalizationUIState implements LocalizationUIState {
@override
String? get selectedLanguage;
@override
String? get installedCommunityInputMethodSupportVersion;
@override
InputMethodApiLanguageData? get communityInputMethodLanguageData;
@override
Map<String, ScLocalizationData>? get apiLocalizationData;
@override
String get workingVersion;

View File

@ -7,7 +7,7 @@ part of 'localization_ui_model.dart';
// **************************************************************************
String _$localizationUIModelHash() =>
r'3441a52a0047dcb685c6fdcb25044dae8688210b';
r'86e433e1901683ad05b81e34d3b37b9b72c4c786';
/// See also [LocalizationUIModel].
@ProviderFor(LocalizationUIModel)

View File

@ -6,7 +6,7 @@ part of 'settings_ui_model.dart';
// RiverpodGenerator
// **************************************************************************
String _$settingsUIModelHash() => r'27193efaa8964e8a097daf8dbabf93bb1fdcab3c';
String _$settingsUIModelHash() => r'00662390cfeab943929fe4820665de211f9ec8ef';
/// See also [SettingsUIModel].
@ProviderFor(SettingsUIModel)