FSX-Translate/lib/pages/home/home_controller.dart
2024-08-19 15:11:49 +08:00

366 lines
12 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_text_detect_area/flutter_text_detect_area.dart';
import 'package:flutter_translate/ads/interstitial_ad_manage.dart';
import 'package:flutter_translate/common/components/speak_alert.dart';
import 'package:flutter_translate/common/hive/history_data.dart';
import 'package:flutter_translate/common/utils/bot_toast.dart';
import 'package:flutter_translate/common/utils/log_utils.dart';
import 'package:flutter_translate/common/utils/number_utils.dart';
import 'package:flutter_translate/common/utils/object_utils.dart';
import 'package:flutter_translate/common/utils/permission_utils.dart';
import 'package:flutter_translate/common/utils/shared_util.dart';
import 'package:flutter_translate/generated/assets.dart';
import 'package:flutter_translate/global/app_lifecycle_reactor.dart';
import 'package:flutter_translate/global/app_tracking_transparency_manager.dart';
import 'package:flutter_translate/manager/speech_convert.dart';
import 'package:flutter_translate/manager/translate.dart';
import 'package:flutter_translate/manager/tts.dart';
import 'package:flutter_translate/model/history_model.dart';
import 'package:flutter_translate/model/language_model.dart';
import 'package:flutter_translate/model/scene_model.dart';
import 'package:flutter_translate/pages/home/components/photo_picker.dart';
import 'package:flutter_translate/router/get_gages.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
class HomeController extends GetxController {
static HomeController get to => Get.find<HomeController>();
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
var versionName = ''.obs;
var options = ['Privacy Policy', 'User Agreement', 'Color Setting'];
var lastWords = '';
var fromLanguage = Rx<LanguageModel>(
LanguageModel(code: 'en', name: 'English'),
);
var toLanguage = Rx<LanguageModel>(
LanguageModel(code: 'zh-cn', name: 'Chinese (Simplified)'),
);
var fromScene = Rx<String>("loading");
var toScene = Rx<String>("loading");
RxBool isPlayingFrom = false.obs;
RxBool isPlayingTo = false.obs;
RxInt appColor = 0xff529F2D.obs;
final languageModels = <LanguageModel>[
LanguageModel(code: 'zh-cn', name: 'Chinese (Simplified)'),
LanguageModel(code: 'ar', name: 'Arabic'),
LanguageModel(code: 'bn', name: 'Bengali'),
LanguageModel(code: 'en', name: 'English'),
LanguageModel(code: 'fr', name: 'French'),
LanguageModel(code: 'de', name: 'German'),
LanguageModel(code: 'hi', name: 'Hindi'),
LanguageModel(code: 'ja', name: 'Japanese'),
LanguageModel(code: 'jv', name: 'Javanese'),
LanguageModel(code: 'ko', name: 'Korean'),
LanguageModel(code: 'pt', name: 'Portuguese'),
LanguageModel(code: 'pa', name: 'Punjabi'),
LanguageModel(code: 'ru', name: 'Russian'),
LanguageModel(code: 'es', name: 'Spanish'),
];
var historyList = <HistoryModel>[].obs;
@override
void onInit() {
super.onInit();
AppTrackingTransparencyManager().requestATT();
AppLifecycleReactor().listenToAppStateChanges();
appColor.value = SharedUtil.getInstance().get<int>("appColor") ?? 0xff554281;
_getAppVersion();
}
@override
void onReady() {
super.onReady();
initData();
initHistoryList();
}
@override
void onClose() {
AppLifecycleReactor().appLifecycleListener?.dispose();
super.onClose();
}
void initHistoryList() {
historyList.value = HistoryData().findAll().reversed.toList();
}
Future<void> initData() async {
LanguageModel fromModel = Translate().fromLanguageEntity.value;
LanguageModel toModel = Translate().toLanguageEntity.value;
LanguageModel? f =
languageModels.firstWhereOrNull((e) => e.code == fromModel.code);
if (f != null) fromLanguage.value = f;
LanguageModel? t = languageModels.firstWhereOrNull((e) => e.code == toModel.code);
if (t != null) toLanguage.value = t;
var data = jsonDecode(await rootBundle.loadString(Assets.jsonScene));
if (data != null && data is List) {
var sceneTypeList = data.map((e) => SceneModel.fromMap(e)).toList();
if (sceneTypeList.isNotEmpty) {
var x = NumberUtils.getRandomNumber(0, sceneTypeList.length);
SceneModel entity = sceneTypeList[x];
if (entity.sceneList != null && entity.sceneList!.isNotEmpty) {
var y = NumberUtils.getRandomNumber(0, entity.sceneList!.length);
fromScene.value = _getSentence(true, entity.sceneList![y]);
toScene.value = _getSentence(false, entity.sceneList![y]);
}
}
}
}
/// 获取版本号
void _getAppVersion() async {
final packageInfo = await PackageInfo.fromPlatform();
versionName.value = 'version number ${packageInfo.version}';
}
void openHomeDrawer() {
scaffoldKey.currentState?.openDrawer();
}
void clickItem(int index) {
Log.d(index);
if (index == 2) {
Get.toNamed(GetPages.colorSetting);
} else {
Get.toNamed(GetPages.webView, arguments: {
'title': options[index],
'url': index == 0
? 'https://trans-globe.mystrikingly.com/privacy'
: 'https://trans-globe.mystrikingly.com/terms',
});
}
scaffoldKey.currentState?.closeDrawer();
}
String _getSentence(bool isFrom, SceneList sceneList) {
List keys = sceneList.toMap().keys.toList();
List values = sceneList.toMap().values.toList();
int index = keys.indexWhere(
(e) => e == (isFrom ? fromLanguage.value.name : toLanguage.value.name));
if (index != -1) {
return values[index];
}
return 'loading';
}
void textConvertVoice(bool isFrom) async {
isPlayingTo.value = false;
isPlayingFrom.value = false;
if (isFrom) {
isPlayingFrom.value = true;
await Tts().voiceTranslator(fromScene.value, fromLanguage.value.code);
isPlayingFrom.value = false;
} else {
isPlayingTo.value = true;
await Tts().voiceTranslator(toScene.value, toLanguage.value.code);
isPlayingTo.value = false;
}
}
void sceneCategory() {
Get.toNamed(GetPages.sceneCategory);
}
Future photos() async {
Get.bottomSheet(
isScrollControlled: true,
PhotoPicker(
funCamera: () async {
await PermissionUtils.checkPermission(
[Permission.camera],
).then((res) {
if (!res) return;
_openCameraGallery(ImageSource.camera);
});
},
funGallery: () async {
Permission permission = Permission.photos;
await PermissionUtils.checkPermission(
[permission],
).then((res) {
if (!res) return;
_openCameraGallery(ImageSource.gallery);
});
},
),
);
}
void face2face() {
InterstitialAdManager().showAdIfReady(
InterstitialAdManager().adIds[2],
onTap: () async {
bool micResult = await PermissionUtils.checkPermission(
[Permission.microphone],
);
if (!micResult) return;
if (Platform.isIOS) {
bool speechResult = await PermissionUtils.checkPermission(
[Permission.speech],
);
if (!speechResult) return;
}
Get.toNamed(GetPages.faceToFace);
},
);
}
void history() {
Get.toNamed(GetPages.history);
}
void translator() {
Get.toNamed(GetPages.translator);
}
Future speak() async {
bool micResult =
await PermissionUtils.checkPermission([Permission.microphone]);
if (!micResult) return;
if (Platform.isIOS) {
bool speechResult =
await PermissionUtils.checkPermission([Permission.speech]);
if (!speechResult) return;
}
await Get.dialog(
barrierDismissible: true,
useSafeArea: false,
SpeakAlert(
isListening: SpeechConvert().isListening,
onTap: () async {
if (!SpeechConvert().hasSpeech) {
await SpeechConvert().init();
}
if (SpeechConvert().hasSpeech) {
if (SpeechConvert().isListening.value) {
_translatedText();
} else {
SpeechConvert().start(
Translate().fromLanguageEntity.value.code,
(SpeechRecognitionResult result) {
Log.d('识别结果:${result.recognizedWords}');
lastWords = result.recognizedWords;
},
);
}
} else {
Get.back();
toast('Speech not available');
}
},
),
);
if (Get.isDialogOpen != null && !Get.isDialogOpen!) {
SpeechConvert().stop(showLoading: false);
}
}
void _translatedText() {
if (ObjectUtils.isEmpty(lastWords)) {
toast('No text recognized');
return;
}
Get.back();
Get.toNamed(
GetPages.translateText,
arguments: {"sourceText": lastWords},
);
}
Future<void> _openCameraGallery(ImageSource source) async {
String detectedValue = "";
final ImagePicker picker = ImagePicker();
final XFile? photo = await picker.pickImage(source: source);
if (photo != null) {
Get.to(() => SelectImageAreaTextDetect(
detectOnce: true,
enableImageInteractions: true,
imagePath: photo.path,
onDetectText: (v) {
if (v is String) {
detectedValue = v;
}
if (v is List) {
int counter = 0;
for (var element in v) {
detectedValue += "$counter. \t\t $element \n\n";
counter++;
}
}
},
onDetectError: (error) {
///This error will occurred in Android only while user will try to crop image at max zoom level then ml kit will throw max 32 height/width exception
if (error is PlatformException &&
(error.message?.contains(
"InputImage width and height should be at least 32!",
) ??
false)) {
toast(
'Selected area should be able to crop image with at least 32 width and height.',
);
}
},
))?.then(
(onValue) {
InterstitialAdManager().showAdIfReady(
InterstitialAdManager().adIds[3],
onTap: () {
if (ObjectUtils.isEmpty(detectedValue)) {
toast('No text recognized');
return;
}
Get.toNamed(
GetPages.translateText,
arguments: {"sourceText": detectedValue},
);
},
);
},
);
}
}
void removeHistoryByIndex(int index) {
// 计算原始列表中的对应索引
int indexToRemoveFromDb = HistoryData().findAll().length - 1 - index;
historyList.removeAt(indexToRemoveFromDb);
HistoryData().remove(indexToRemoveFromDb);
}
void historyTranslate(HistoryModel historyModel) {
Get.toNamed(
GetPages.translateText,
arguments: {
'isHistory': true,
'sourceText': historyModel.sourceText,
'targetText': historyModel.targetText,
'fromLanguageName': historyModel.sourceLanguageName,
'toLanguageName': historyModel.targetLanguageName,
'fromLanguageCode': historyModel.sourceLanguageCode,
'toLanguageCode': historyModel.targetLanguageCode,
},
);
}
}