1
This commit is contained in:
parent
db01a24756
commit
1eb6ed4546
@ -2,8 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
|
||||
class AppTrackingAuthorizationManager {
|
||||
AppTrackingAuthorizationManager._();
|
||||
@ -23,7 +22,7 @@ class AppTrackingAuthorizationManager {
|
||||
if (status == TrackingStatus.notDetermined) {
|
||||
if (_timer != null && _timer!.isActive) {
|
||||
final TrackingStatus status = await AppTrackingTransparency.requestTrackingAuthorization();
|
||||
LogPrint.d('跟踪授权状态: $status');
|
||||
TPrint.d('跟踪授权状态: $status');
|
||||
} else {
|
||||
_startTimer();
|
||||
}
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import 'package:flutter_tts/flutter_tts.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
|
||||
class FlutterTtsManager {
|
||||
FlutterTtsManager._();
|
||||
|
||||
static final FlutterTtsManager _instance = FlutterTtsManager._();
|
||||
|
||||
factory FlutterTtsManager() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static final FlutterTtsManager _instance = FlutterTtsManager._();
|
||||
|
||||
late FlutterTts ttsController;
|
||||
|
||||
Future<void> init() async {
|
||||
LogPrint.d("TTS Service init start");
|
||||
TPrint.d("TTS Service init start");
|
||||
ttsController = FlutterTts();
|
||||
await ttsController.setSharedInstance(true);
|
||||
await ttsController.setIosAudioCategory(
|
||||
@ -27,7 +27,7 @@ class FlutterTtsManager {
|
||||
IosTextToSpeechAudioMode.voicePrompt);
|
||||
await ttsController.awaitSpeakCompletion(true);
|
||||
await ttsController.awaitSynthCompletion(true);
|
||||
LogPrint.d("TTS Service init success");
|
||||
TPrint.d("TTS Service init success");
|
||||
}
|
||||
|
||||
Future<void> translatorTtsPlay(String text, String language) async {
|
||||
@ -36,7 +36,7 @@ class FlutterTtsManager {
|
||||
await ttsController.setLanguage(language);
|
||||
await ttsController.speak(text);
|
||||
} catch (e) {
|
||||
BaseEasyLoading.toast('This language cannot be played');
|
||||
TBaseEasyLoading.toast('This language cannot be played');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,53 +1,41 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:speech_to_text/speech_recognition_error.dart';
|
||||
import 'package:speech_to_text/speech_to_text.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
|
||||
class SpeechToTextManager {
|
||||
static final SpeechToTextManager _instance = SpeechToTextManager._();
|
||||
|
||||
SpeechToTextManager._();
|
||||
|
||||
factory SpeechToTextManager() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
SpeechToTextManager._();
|
||||
|
||||
final _speechToText = SpeechToText();
|
||||
var hasSpeech = false;
|
||||
var isListening = false.obs;
|
||||
|
||||
Future<void> initSpeech() async {
|
||||
var isListening = false.obs;
|
||||
var hasSpeech = false;
|
||||
|
||||
Future<void> init() async {
|
||||
try {
|
||||
BaseEasyLoading.loading();
|
||||
TBaseEasyLoading.loading();
|
||||
hasSpeech = await _speechToText.initialize(
|
||||
onStatus: _statusListener,
|
||||
onError: _errorListener,
|
||||
);
|
||||
BaseEasyLoading.dismiss();
|
||||
TBaseEasyLoading.dismiss();
|
||||
_speechToText.statusListener ??= _statusListener;
|
||||
_speechToText.errorListener ??= _errorListener;
|
||||
} catch (e) {
|
||||
LogPrint.d('Speech recognition failed: ${e.toString()}');
|
||||
TPrint.d('Speech recognition failed: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
void _statusListener(String status) {
|
||||
LogPrint.d('状态:$status');
|
||||
if (status == 'listening') {
|
||||
isListening.value = true;
|
||||
} else {
|
||||
isListening.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void _errorListener(SpeechRecognitionError error) {
|
||||
LogPrint.d('Received error status: $error, listening: ${_speechToText.isListening}');
|
||||
BaseEasyLoading.toast('Speech recognition failed: ${error.errorMsg}');
|
||||
}
|
||||
|
||||
Future<void> startListening(String localeId, SpeechResultListener onResult) async {
|
||||
BaseEasyLoading.loading();
|
||||
Future<void> startListening(
|
||||
String localeId, SpeechResultListener onResult) async {
|
||||
TBaseEasyLoading.loading();
|
||||
try {
|
||||
await _speechToText.listen(
|
||||
onResult: onResult,
|
||||
@ -60,22 +48,39 @@ class SpeechToTextManager {
|
||||
listenMode: ListenMode.dictation,
|
||||
),
|
||||
);
|
||||
BaseEasyLoading.dismiss();
|
||||
TBaseEasyLoading.dismiss();
|
||||
} catch (e) {
|
||||
if (e.runtimeType == ListenFailedException) {
|
||||
LogPrint.d('speechToText.listen:${(e as ListenFailedException).message}');
|
||||
TPrint.d(
|
||||
'speechToText.listen:${(e as ListenFailedException).message}');
|
||||
} else {
|
||||
LogPrint.d('speechToText.listen:${e.toString()}');
|
||||
TPrint.d('speechToText.listen:${e.toString()}');
|
||||
}
|
||||
BaseEasyLoading.toast('The current language does not support speech recognition');
|
||||
TBaseEasyLoading.toast(
|
||||
'The current language does not support speech recognition');
|
||||
}
|
||||
}
|
||||
|
||||
void _statusListener(String status) {
|
||||
TPrint.d('状态:$status');
|
||||
if (status == 'listening') {
|
||||
isListening.value = true;
|
||||
} else {
|
||||
isListening.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void _errorListener(SpeechRecognitionError error) {
|
||||
TPrint.d(
|
||||
'Received error status: $error, listening: ${_speechToText.isListening}');
|
||||
TBaseEasyLoading.toast('Speech recognition failed: ${error.errorMsg}');
|
||||
}
|
||||
|
||||
Future<void> stopListening() async {
|
||||
if (isListening.value) {
|
||||
BaseEasyLoading.loading();
|
||||
TBaseEasyLoading.loading();
|
||||
await _speechToText.stop();
|
||||
BaseEasyLoading.dismiss();
|
||||
TBaseEasyLoading.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,20 +6,23 @@ import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/language_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/util/num_util.dart';
|
||||
import 'package:trans_lark/util/t_number_utils.dart';
|
||||
|
||||
class TranslateManager {
|
||||
TranslateManager._();
|
||||
|
||||
static final TranslateManager _instance = TranslateManager._();
|
||||
|
||||
factory TranslateManager() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static final TranslateManager _instance = TranslateManager._();
|
||||
|
||||
/// 支持翻译的所有语言
|
||||
var languageList = <LanguageEntity>[].obs;
|
||||
|
||||
/// 是否选择的源语言
|
||||
var isSelectFromLanguage = true.obs;
|
||||
|
||||
/// 源语言
|
||||
var fromLanguageEntity = LanguageEntity(
|
||||
languageCode: 'en',
|
||||
@ -32,9 +35,6 @@ class TranslateManager {
|
||||
languageName: 'Chinese (Simplified)',
|
||||
).obs;
|
||||
|
||||
/// 是否选择的源语言
|
||||
var isSelectFromLanguage = true.obs;
|
||||
|
||||
Future<void> init() async {
|
||||
var data = jsonDecode(await rootBundle.loadString(Assets.jsonLanguage));
|
||||
if (data != null && data is List) {
|
||||
@ -56,7 +56,7 @@ class TranslateManager {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var num = NumUtil.getRandomNumberExcludingCurrent(0, languageList.length, index);
|
||||
var num = TNumberUtils.getRandomNumberExcludingCurrent(0, languageList.length, index);
|
||||
fromLanguageEntity.value = languageList[num].copyWith();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
import 'package:trans_lark/storage/hive_storage.dart';
|
||||
import 'package:trans_lark/util/date_util.dart';
|
||||
import 'package:trans_lark/hive/hive_storage.dart';
|
||||
import 'package:trans_lark/util/t_date_utils.dart';
|
||||
|
||||
class HistoryData {
|
||||
/// 私有构造函数
|
||||
@ -20,35 +20,35 @@ class HistoryData {
|
||||
final _box = getHistoryBox();
|
||||
|
||||
/// 返回所有数据
|
||||
List<HistoryEntity> getList() {
|
||||
List<HistoryEntity> getAllHistory() {
|
||||
return _box.values.toList();
|
||||
}
|
||||
|
||||
/// 返回分组后的所有数据
|
||||
Map<String, List<HistoryEntity>> getGroupByList() {
|
||||
Map<String, List<HistoryEntity>> getMapList() {
|
||||
// 使用 groupBy 函数进行分组
|
||||
var groupedEvents = groupBy(
|
||||
getList().reversed.toList(),
|
||||
(HistoryEntity event) => DateUtil.formatDateMs(
|
||||
event.translationTime ?? DateUtil.getNowTimestamp(),
|
||||
getAllHistory().reversed.toList(),
|
||||
(HistoryEntity event) => TDateUtils.formatDateMs(
|
||||
event.translationTime ?? TDateUtils.getNowTimestamp(),
|
||||
format: DateFormats.yMoD));
|
||||
return groupedEvents;
|
||||
}
|
||||
|
||||
/// 添加数据
|
||||
Future<int> addData(HistoryEntity entity) async {
|
||||
entity.translationTime = DateUtil.getNowTimestamp();
|
||||
Future<int> addHistory(HistoryEntity entity, {int? index}) async {
|
||||
entity.translationTime = TDateUtils.getNowTimestamp();
|
||||
return await _box.add(entity);
|
||||
}
|
||||
|
||||
/// 删除
|
||||
Future<void> delete(int index) async {
|
||||
Future<void> deleteHistory(int index, {HistoryEntity? entity}) async {
|
||||
await _box.deleteAt(index);
|
||||
await _box.flush();
|
||||
}
|
||||
|
||||
/// 清空所有数据
|
||||
Future<void> clear() async {
|
||||
Future<void> clearHistory() async {
|
||||
await _box.clear();
|
||||
await _box.flush();
|
||||
}
|
||||
@ -8,9 +8,10 @@ import 'package:get/get.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/global/global_config.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
import 'package:trans_lark/storage/hive_storage.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
import 'package:trans_lark/hive/hive_storage.dart';
|
||||
import 'package:trans_lark/router/get_router.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@ -53,16 +54,18 @@ class MyApp extends StatelessWidget {
|
||||
),
|
||||
useMaterial3: true,
|
||||
),
|
||||
initialRoute: GetRouter.home,
|
||||
initialRoute: GetRouter.index,
|
||||
getPages: GetRouter.routers,
|
||||
defaultTransition: Transition.rightToLeft,
|
||||
builder: (context, widget) {
|
||||
BaseEasyLoading.configLoading();
|
||||
TBaseEasyLoading.configLoading();
|
||||
widget = easyLoading(context, widget);
|
||||
// 设置文字大小不随系统设置改变
|
||||
return MediaQuery.withNoTextScaling(child: widget);
|
||||
},
|
||||
),
|
||||
routingCallback: (routing) {
|
||||
TPrint.d("路由变化 ${routing?.current}");
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/face_to_face/face_to_face_controller.dart';
|
||||
|
||||
class FaceToFaceBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => FaceToFaceController());
|
||||
}
|
||||
}
|
||||
116
lib/page/home/home_logic.dart → lib/page/index/index_controller.dart
Executable file → Normal file
116
lib/page/home/home_logic.dart → lib/page/index/index_controller.dart
Executable file → Normal file
@ -14,42 +14,25 @@ import 'package:trans_lark/global/app_tracking_authorization_manager.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/global/speech_to_text_manager.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/page/settings/settings_view.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
import 'package:trans_lark/util/device_info_util.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:trans_lark/util/num_util.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/util/permission_util.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
import 'package:trans_lark/widget/photo_picker_bottom_sheet.dart';
|
||||
import 'package:trans_lark/widget/speak_dialog.dart';
|
||||
import 'package:trans_lark/page/settings/settings_widget.dart';
|
||||
import 'package:trans_lark/router/get_router.dart';
|
||||
import 'package:trans_lark/util/t_device_utils.dart';
|
||||
import 'package:trans_lark/util/t_number_utils.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/util/t_permission_utils.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
import 'package:trans_lark/widget/t_photo_picker_bottom_sheet.dart';
|
||||
import 'package:trans_lark/widget/t_speak_dialog.dart';
|
||||
|
||||
class HomeLogic extends GetxController {
|
||||
static HomeLogic get to => Get.find<HomeLogic>();
|
||||
class IndexController extends GetxController {
|
||||
static IndexController get to => Get.find<IndexController>();
|
||||
var lastWords = '';
|
||||
|
||||
var fromLanguage = Rx<LanguageEntity?>(null);
|
||||
var toLanguage = Rx<LanguageEntity?>(null);
|
||||
var fromStr = Rx<String?>(null);
|
||||
var toStr = Rx<String?>(null);
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
AppTrackingAuthorizationManager().requestTrackingAuthorization();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
getDailyQuote();
|
||||
}
|
||||
|
||||
Future<void> getDailyQuote() async {
|
||||
LanguageEntity fromLanguageEntity =
|
||||
TranslateManager().fromLanguageEntity.value;
|
||||
LanguageEntity toLanguageEntity = TranslateManager().toLanguageEntity.value;
|
||||
var languageScene = <LanguageEntity>[
|
||||
LanguageEntity(languageCode: 'ar', languageName: 'Arabic'),
|
||||
LanguageEntity(languageCode: 'bn', languageName: 'Bengali'),
|
||||
@ -67,6 +50,23 @@ class HomeLogic extends GetxController {
|
||||
LanguageEntity(languageCode: 'ru', languageName: 'Russian'),
|
||||
LanguageEntity(languageCode: 'es', languageName: 'Spanish'),
|
||||
];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
AppTrackingAuthorizationManager().requestTrackingAuthorization();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
getDailyQuoteData();
|
||||
}
|
||||
|
||||
Future<void> getDailyQuoteData({int? dataType}) async {
|
||||
LanguageEntity fromLanguageEntity =
|
||||
TranslateManager().fromLanguageEntity.value;
|
||||
LanguageEntity toLanguageEntity = TranslateManager().toLanguageEntity.value;
|
||||
fromLanguage.value = languageScene.firstWhereOrNull(
|
||||
(e) => e.languageCode == fromLanguageEntity.languageCode,
|
||||
) ??
|
||||
@ -91,10 +91,10 @@ class HomeLogic extends GetxController {
|
||||
if (data != null && data is List) {
|
||||
var sceneTypeList = data.map((e) => SceneEntity.fromMap(e)).toList();
|
||||
if (sceneTypeList.isNotEmpty) {
|
||||
var x = NumUtil.getRandomNumber(0, sceneTypeList.length);
|
||||
var x = TNumberUtils.getRandomNumber(0, sceneTypeList.length);
|
||||
SceneEntity entity = sceneTypeList[x];
|
||||
if (entity.sceneList != null && entity.sceneList!.isNotEmpty) {
|
||||
var y = NumUtil.getRandomNumber(0, entity.sceneList!.length);
|
||||
var y = TNumberUtils.getRandomNumber(0, entity.sceneList!.length);
|
||||
fromStr.value = _getSentence(true, entity.sceneList![y]);
|
||||
toStr.value = _getSentence(false, entity.sceneList![y]);
|
||||
}
|
||||
@ -132,38 +132,38 @@ class HomeLogic extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
void openSettings() {
|
||||
void openSettingsBottomSheet() {
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
SettingsView(),
|
||||
SettingsWidget(),
|
||||
);
|
||||
}
|
||||
|
||||
void openSceneType() {
|
||||
Get.toNamed(GetRouter.sceneType);
|
||||
void toSceneCategory() {
|
||||
Get.toNamed(GetRouter.sceneCategory);
|
||||
}
|
||||
|
||||
Future<void> onTapPhotos() async {
|
||||
Future<void> toPhotos() async {
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
PhotoPickerBottomSheet(
|
||||
TPhotoPickerBottomSheet(
|
||||
funCamera: () async {
|
||||
bool result =
|
||||
await PermissionUtil.checkPermission([Permission.camera]);
|
||||
await TPermissionUtils.checkPermission([Permission.camera]);
|
||||
if (!result) return;
|
||||
_openCameraGallery(ImageSource.camera);
|
||||
},
|
||||
funGallery: () async {
|
||||
Permission permission = Permission.photos;
|
||||
if (Platform.isAndroid) {
|
||||
int sdkInt = await DeviceInfoUtil.getAndroidSDKInt();
|
||||
int sdkInt = await TDeviceUtils.getAndroidSDKInt();
|
||||
if (sdkInt <= 32) {
|
||||
permission = Permission.storage;
|
||||
} else {
|
||||
permission = Permission.photos;
|
||||
}
|
||||
}
|
||||
bool result = await PermissionUtil.checkPermission([permission]);
|
||||
bool result = await TPermissionUtils.checkPermission([permission]);
|
||||
if (!result) return;
|
||||
_openCameraGallery(ImageSource.gallery);
|
||||
},
|
||||
@ -198,14 +198,14 @@ class HomeLogic extends GetxController {
|
||||
(error.message?.contains(
|
||||
"InputImage width and height should be at least 32!") ??
|
||||
false)) {
|
||||
BaseEasyLoading.toast(
|
||||
TBaseEasyLoading.toast(
|
||||
'Selected area should be able to crop image with at least 32 width and height.');
|
||||
}
|
||||
},
|
||||
))?.then(
|
||||
(onValue) {
|
||||
if (ObjUtil.isEmpty(detectedValue)) {
|
||||
BaseEasyLoading.toast('No text recognized');
|
||||
if (TObjectUtils.isEmpty(detectedValue)) {
|
||||
TBaseEasyLoading.toast('No text recognized');
|
||||
return;
|
||||
}
|
||||
Get.toNamed(
|
||||
@ -219,21 +219,21 @@ class HomeLogic extends GetxController {
|
||||
|
||||
Future<void> onTapSpeak() async {
|
||||
bool micResult =
|
||||
await PermissionUtil.checkPermission([Permission.microphone]);
|
||||
await TPermissionUtils.checkPermission([Permission.microphone]);
|
||||
if (!micResult) return;
|
||||
if (Platform.isIOS) {
|
||||
bool speechResult =
|
||||
await PermissionUtil.checkPermission([Permission.speech]);
|
||||
await TPermissionUtils.checkPermission([Permission.speech]);
|
||||
if (!speechResult) return;
|
||||
}
|
||||
await Get.dialog(
|
||||
barrierDismissible: true,
|
||||
useSafeArea: false,
|
||||
SpeakDialog(
|
||||
TSpeakDialog(
|
||||
isListening: SpeechToTextManager().isListening,
|
||||
onTap: () async {
|
||||
if (!SpeechToTextManager().hasSpeech) {
|
||||
await SpeechToTextManager().initSpeech();
|
||||
await SpeechToTextManager().init();
|
||||
}
|
||||
if (SpeechToTextManager().hasSpeech) {
|
||||
if (SpeechToTextManager().isListening.value) {
|
||||
@ -245,7 +245,7 @@ class HomeLogic extends GetxController {
|
||||
}
|
||||
} else {
|
||||
Get.back();
|
||||
BaseEasyLoading.toast('Speech not available');
|
||||
TBaseEasyLoading.toast('Speech not available');
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -256,13 +256,13 @@ class HomeLogic extends GetxController {
|
||||
}
|
||||
|
||||
void _onSpeechResult(SpeechRecognitionResult result) {
|
||||
LogPrint.d('识别结果:${result.recognizedWords}');
|
||||
TPrint.d('识别结果:${result.recognizedWords}');
|
||||
lastWords = result.recognizedWords;
|
||||
}
|
||||
|
||||
void _openTranslatorResultPage() {
|
||||
if (ObjUtil.isEmpty(lastWords)) {
|
||||
BaseEasyLoading.toast('No text recognized');
|
||||
if (TObjectUtils.isEmpty(lastWords)) {
|
||||
TBaseEasyLoading.toast('No text recognized');
|
||||
return;
|
||||
}
|
||||
Get.back();
|
||||
@ -272,23 +272,23 @@ class HomeLogic extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
void openTranslate() {
|
||||
void toTranslate() {
|
||||
Get.toNamed(GetRouter.translate);
|
||||
}
|
||||
|
||||
Future<void> openFaceToFace() async {
|
||||
Future<void> toP2P() async {
|
||||
bool micResult =
|
||||
await PermissionUtil.checkPermission([Permission.microphone]);
|
||||
await TPermissionUtils.checkPermission([Permission.microphone]);
|
||||
if (!micResult) return;
|
||||
if (Platform.isIOS) {
|
||||
bool speechResult =
|
||||
await PermissionUtil.checkPermission([Permission.speech]);
|
||||
await TPermissionUtils.checkPermission([Permission.speech]);
|
||||
if (!speechResult) return;
|
||||
}
|
||||
Get.toNamed(GetRouter.faceToFace);
|
||||
Get.toNamed(GetRouter.p2p);
|
||||
}
|
||||
|
||||
void openTranslateHistory() {
|
||||
Get.toNamed(GetRouter.translateHistory);
|
||||
void toTranslateHistory() {
|
||||
Get.toNamed(GetRouter.translateRecord);
|
||||
}
|
||||
}
|
||||
32
lib/page/home/home_view.dart → lib/page/index/index_view.dart
Executable file → Normal file
32
lib/page/home/home_view.dart → lib/page/index/index_view.dart
Executable file → Normal file
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/home/home_logic.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/language_bar.dart';
|
||||
import 'package:trans_lark/page/index/index_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/widget/t_language_bar_widget.dart';
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
final HomeLogic logic = Get.put(HomeLogic());
|
||||
class IndexView extends StatelessWidget {
|
||||
final IndexController logic = Get.put(IndexController());
|
||||
|
||||
HomePage({super.key});
|
||||
IndexView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -59,7 +59,7 @@ class HomePage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: logic.openSettings,
|
||||
onTap: logic.openSettingsBottomSheet,
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
@ -85,7 +85,7 @@ class HomePage extends StatelessWidget {
|
||||
return Stack(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: logic.openSceneType,
|
||||
onTap: logic.toSceneCategory,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 30),
|
||||
@ -104,7 +104,7 @@ class HomePage extends StatelessWidget {
|
||||
top: 46,
|
||||
left: 20,
|
||||
child: GestureDetector(
|
||||
onTap: logic.openSceneType,
|
||||
onTap: logic.toSceneCategory,
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
@ -173,7 +173,7 @@ class HomePage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
return Text(
|
||||
ObjUtil.getStr(logic.fromStr.value),
|
||||
TObjectUtils.getStr(logic.fromStr.value),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
@ -235,7 +235,7 @@ class HomePage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
return Text(
|
||||
ObjUtil.getStr(logic.toStr.value),
|
||||
TObjectUtils.getStr(logic.toStr.value),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
@ -286,7 +286,7 @@ class HomePage extends StatelessWidget {
|
||||
Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: logic.onTapPhotos,
|
||||
onTap: logic.toPhotos,
|
||||
child: Container(
|
||||
width: 72,
|
||||
height: 72,
|
||||
@ -316,7 +316,7 @@ class HomePage extends StatelessWidget {
|
||||
Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: logic.openFaceToFace,
|
||||
onTap: logic.toP2P,
|
||||
child: Container(
|
||||
width: 72,
|
||||
height: 72,
|
||||
@ -346,7 +346,7 @@ class HomePage extends StatelessWidget {
|
||||
Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: logic.openTranslateHistory,
|
||||
onTap: logic.toTranslateHistory,
|
||||
child: Container(
|
||||
width: 72,
|
||||
height: 72,
|
||||
@ -381,7 +381,7 @@ class HomePage extends StatelessWidget {
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: logic.openTranslate,
|
||||
onTap: logic.toTranslate,
|
||||
child: Container(
|
||||
height: 76,
|
||||
alignment: Alignment.center,
|
||||
@ -438,7 +438,7 @@ class HomePage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const LanguageBar(),
|
||||
const TLanguageBarWidget(),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
9
lib/page/p2p/p2p_binding.dart
Normal file
9
lib/page/p2p/p2p_binding.dart
Normal file
@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/p2p/p2p_controller.dart';
|
||||
|
||||
class P2PBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => P2PController());
|
||||
}
|
||||
}
|
||||
@ -2,32 +2,33 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:speech_to_text/speech_recognition_result.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
import 'package:translator/translator.dart';
|
||||
import 'package:trans_lark/global/speech_to_text_manager.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
|
||||
class FaceToFaceController extends GetxController with GetSingleTickerProviderStateMixin{
|
||||
class P2PController extends GetxController
|
||||
with GetSingleTickerProviderStateMixin {
|
||||
final aboveScrollController = ScrollController();
|
||||
final underScrollController = ScrollController();
|
||||
|
||||
var angle = 0.0.obs;
|
||||
|
||||
/// 翻译
|
||||
final _translator = GoogleTranslator();
|
||||
|
||||
/// 显示的文本
|
||||
var aboveText = ''.obs;
|
||||
var underText = ''.obs;
|
||||
|
||||
/// 翻译
|
||||
final _translator = GoogleTranslator();
|
||||
|
||||
/// 是否选择的下方
|
||||
var selectedUnder = true.obs;
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
super.onReady();
|
||||
onTapSpeak(true);
|
||||
onSpeak(true);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -38,19 +39,19 @@ class FaceToFaceController extends GetxController with GetSingleTickerProviderSt
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<void> onBackTap() async {
|
||||
Future<void> onBack() async {
|
||||
await SpeechToTextManager().stopListening();
|
||||
Get.back();
|
||||
}
|
||||
|
||||
/// 旋转 180 度
|
||||
void onTapRotate() {
|
||||
void onRotate() {
|
||||
angle.value -= 0.5;
|
||||
}
|
||||
|
||||
Future<void> onTapSpeak(bool isUnder) async {
|
||||
Future<void> onSpeak(bool isUnder, {int? speakType}) async {
|
||||
if (!SpeechToTextManager().hasSpeech) {
|
||||
await SpeechToTextManager().initSpeech();
|
||||
await SpeechToTextManager().init();
|
||||
}
|
||||
if (SpeechToTextManager().hasSpeech) {
|
||||
if (isUnder) {
|
||||
@ -59,35 +60,38 @@ class FaceToFaceController extends GetxController with GetSingleTickerProviderSt
|
||||
}
|
||||
selectedUnder.value = true;
|
||||
_scrollToBottom();
|
||||
SpeechToTextManager().startListening(TranslateManager().fromLanguageEntity.value.languageCode, _onSpeechResult);
|
||||
SpeechToTextManager().startListening(
|
||||
TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
_speechRes);
|
||||
} else {
|
||||
if (selectedUnder.value) {
|
||||
await SpeechToTextManager().stopListening();
|
||||
}
|
||||
selectedUnder.value = false;
|
||||
_scrollToBottom();
|
||||
SpeechToTextManager().startListening(TranslateManager().toLanguageEntity.value.languageCode, _onSpeechResult);
|
||||
SpeechToTextManager().startListening(
|
||||
TranslateManager().toLanguageEntity.value.languageCode, _speechRes);
|
||||
}
|
||||
} else {
|
||||
BaseEasyLoading.toast('Speech not available');
|
||||
TBaseEasyLoading.toast('Speech not available');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSpeechResult(SpeechRecognitionResult result) async {
|
||||
LogPrint.d('识别结果:${result.recognizedWords}');
|
||||
if (ObjUtil.isNotEmptyStr(result.recognizedWords)) {
|
||||
Future<void> _speechRes(SpeechRecognitionResult result) async {
|
||||
TPrint.d('识别结果:${result.recognizedWords}');
|
||||
if (TObjectUtils.isNotEmptyStr(result.recognizedWords)) {
|
||||
if (selectedUnder.value) {
|
||||
underText.value += '${result.recognizedWords}\n';
|
||||
var translateText = await _translation(result.recognizedWords);
|
||||
LogPrint.d('翻译结果:${result.recognizedWords}');
|
||||
if (ObjUtil.isNotEmptyStr(translateText)) {
|
||||
TPrint.d('翻译结果:${result.recognizedWords}');
|
||||
if (TObjectUtils.isNotEmptyStr(translateText)) {
|
||||
aboveText.value += '$translateText\n';
|
||||
}
|
||||
} else {
|
||||
aboveText.value += '${result.recognizedWords}\n';
|
||||
var translateText = await _translation(result.recognizedWords);
|
||||
LogPrint.d('翻译结果:${result.recognizedWords}');
|
||||
if (ObjUtil.isNotEmptyStr(translateText)) {
|
||||
TPrint.d('翻译结果:${result.recognizedWords}');
|
||||
if (TObjectUtils.isNotEmptyStr(translateText)) {
|
||||
underText.value += '$translateText\n';
|
||||
}
|
||||
}
|
||||
@ -95,10 +99,14 @@ class FaceToFaceController extends GetxController with GetSingleTickerProviderSt
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _translation(String sourceText) async {
|
||||
Future<String> _translation(String sourceText, {int? translationType}) async {
|
||||
try {
|
||||
String from = selectedUnder.value ? TranslateManager().fromLanguageEntity.value.languageCode : TranslateManager().toLanguageEntity.value.languageCode;
|
||||
String to = selectedUnder.value ? TranslateManager().toLanguageEntity.value.languageCode : TranslateManager().fromLanguageEntity.value.languageCode;
|
||||
String from = selectedUnder.value
|
||||
? TranslateManager().fromLanguageEntity.value.languageCode
|
||||
: TranslateManager().toLanguageEntity.value.languageCode;
|
||||
String to = selectedUnder.value
|
||||
? TranslateManager().toLanguageEntity.value.languageCode
|
||||
: TranslateManager().fromLanguageEntity.value.languageCode;
|
||||
Translation translate = await _translator.translate(
|
||||
sourceText,
|
||||
from: from,
|
||||
@ -106,7 +114,7 @@ class FaceToFaceController extends GetxController with GetSingleTickerProviderSt
|
||||
);
|
||||
return translate.text;
|
||||
} catch (e) {
|
||||
LogPrint.d('Translation failed,${e.toString()}');
|
||||
TPrint.d('Translation failed,${e.toString()}');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -1,34 +1,46 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/speech_to_text_manager.dart';
|
||||
import 'package:trans_lark/page/face_to_face/face_to_face_controller.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/page/p2p/p2p_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:wave/config.dart';
|
||||
import 'package:wave/wave.dart';
|
||||
|
||||
class FaceToFaceView extends GetView<FaceToFaceController> {
|
||||
const FaceToFaceView({super.key});
|
||||
class P2PView extends GetView<P2PController> {
|
||||
const P2PView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
extendBody: true,
|
||||
extendBodyBehindAppBar: true,
|
||||
backgroundColor: Colors.black,
|
||||
appBar: BaseAppBar(
|
||||
appBar: _buildAppBar(),
|
||||
body: Column(
|
||||
children: [
|
||||
_buildAbove(context),
|
||||
_buildUnder(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TBaseAppbarWidget _buildAppBar() {
|
||||
return TBaseAppbarWidget(
|
||||
backgroundColor: Colors.transparent,
|
||||
backColor: Colors.white,
|
||||
onBackTap: controller.onBackTap,
|
||||
onBackTap: controller.onBack,
|
||||
actionWidget: Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: ClipOval(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: controller.onTapRotate,
|
||||
onTap: controller.onRotate,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: SvgPicture.asset(
|
||||
@ -41,13 +53,6 @@ class FaceToFaceView extends GetView<FaceToFaceController> {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
_buildAbove(context),
|
||||
_buildUnder(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -55,7 +60,7 @@ class FaceToFaceView extends GetView<FaceToFaceController> {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => controller.onTapSpeak(false),
|
||||
onTap: () => controller.onSpeak(false),
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: double.infinity,
|
||||
@ -124,7 +129,7 @@ class FaceToFaceView extends GetView<FaceToFaceController> {
|
||||
Flexible(
|
||||
child: Visibility(
|
||||
visible: SpeechToTextManager().isListening.value &&
|
||||
ObjUtil.isNotEmptyStr(
|
||||
TObjectUtils.isNotEmptyStr(
|
||||
controller.aboveText.value),
|
||||
replacement: const Text(
|
||||
'Please start talking',
|
||||
@ -163,7 +168,7 @@ class FaceToFaceView extends GetView<FaceToFaceController> {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => controller.onTapSpeak(true),
|
||||
onTap: () => controller.onSpeak(true),
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: double.infinity,
|
||||
@ -223,7 +228,8 @@ class FaceToFaceView extends GetView<FaceToFaceController> {
|
||||
Flexible(
|
||||
child: Visibility(
|
||||
visible: SpeechToTextManager().isListening.value &&
|
||||
ObjUtil.isNotEmptyStr(controller.underText.value),
|
||||
TObjectUtils.isNotEmptyStr(
|
||||
controller.underText.value),
|
||||
replacement: const Text(
|
||||
'Please start talking',
|
||||
style: TextStyle(
|
||||
9
lib/page/scene_category/scene_category_binding.dart
Normal file
9
lib/page/scene_category/scene_category_binding.dart
Normal file
@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/scene_category/scene_category_controller.dart';
|
||||
|
||||
class SceneCategoryBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SceneCategoryController());
|
||||
}
|
||||
}
|
||||
@ -4,17 +4,16 @@ import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/scene_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
import 'package:trans_lark/widget/view_state_widget.dart';
|
||||
import 'package:trans_lark/router/get_router.dart';
|
||||
import 'package:trans_lark/widget/t_view_state_widget.dart';
|
||||
|
||||
class SceneTypeController extends GetxController {
|
||||
class SceneCategoryController extends GetxController {
|
||||
var sceneTypeList = <SceneEntity>[].obs;
|
||||
var viewState = ViewState.loading.obs;
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
super.onReady();
|
||||
|
||||
var data = jsonDecode(await rootBundle.loadString(Assets.jsonTranslationScene));
|
||||
if (data != null && data is List) {
|
||||
sceneTypeList.value = data.map((e) => SceneEntity.fromMap(e)).toList();
|
||||
@ -22,7 +21,7 @@ class SceneTypeController extends GetxController {
|
||||
viewState.value = sceneTypeList.isNotEmpty ? ViewState.normal : ViewState.empty;
|
||||
}
|
||||
|
||||
void onTapItem(SceneEntity item) {
|
||||
void toSceneItem(SceneEntity item) {
|
||||
Get.toNamed(GetRouter.sceneList, arguments: item.sceneList);
|
||||
}
|
||||
}
|
||||
@ -3,30 +3,30 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/scene_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/scene_type/scene_type_controller.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/widget/base_scrollbar.dart';
|
||||
import 'package:trans_lark/widget/view_state_widget.dart';
|
||||
import 'package:trans_lark/page/scene_category/scene_category_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_base_scrollbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_view_state_widget.dart';
|
||||
|
||||
class SceneTypeView extends StatelessWidget {
|
||||
SceneTypeView({super.key});
|
||||
class SceneCategoryView extends StatelessWidget {
|
||||
SceneCategoryView({super.key});
|
||||
|
||||
final controller = Get.find<SceneTypeController>();
|
||||
final controller = Get.find<SceneCategoryController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const BaseAppBar(
|
||||
appBar: const TBaseAppbarWidget(
|
||||
title: 'Selected oral expressions',
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: Obx(() {
|
||||
return ViewStateWidget(
|
||||
return TViewStateWidget(
|
||||
viewState: controller.viewState.value,
|
||||
child: BaseScrollbar(
|
||||
child: TBaseScrollbarWidget(
|
||||
child: ListView.builder(
|
||||
itemCount: controller.sceneTypeList.length,
|
||||
itemBuilder: (context, index) {
|
||||
@ -76,7 +76,7 @@ class SceneTypeView extends StatelessWidget {
|
||||
bgColor = const Color(0xffFD9D65);
|
||||
}
|
||||
return InkWell(
|
||||
onTap: () => controller.onTapItem(item),
|
||||
onTap: () => controller.toSceneItem(item),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
|
||||
child: Row(
|
||||
@ -108,7 +108,7 @@ class SceneTypeView extends StatelessWidget {
|
||||
left: 7,
|
||||
right: 7,
|
||||
child: Text(
|
||||
ObjUtil.getStr(item.sceneType).toUpperCase(),
|
||||
TObjectUtils.getStr(item.sceneType).toUpperCase(),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
@ -127,7 +127,7 @@ class SceneTypeView extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
ObjUtil.getStr(item.sceneType),
|
||||
TObjectUtils.getStr(item.sceneType),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/scene_category_item/scene_category_item_controller.dart';
|
||||
|
||||
class SceneCategoryItemBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SceneCategoryItemController());
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,9 @@ import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/language_entity.dart';
|
||||
import 'package:trans_lark/entity/scene_entity.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/widget/language_scene_bottom_sheet.dart';
|
||||
import 'package:trans_lark/widget/t_language_scene_bottom_sheet.dart';
|
||||
|
||||
class SceneListController extends GetxController {
|
||||
class SceneCategoryItemController extends GetxController {
|
||||
var languageScene = <LanguageEntity>[
|
||||
LanguageEntity(languageCode: 'ar', languageName: 'Arabic'),
|
||||
LanguageEntity(languageCode: 'bn', languageName: 'Bengali'),
|
||||
@ -34,25 +34,32 @@ class SceneListController extends GetxController {
|
||||
toLanguage = languageScene[2].copyWith().obs;
|
||||
}
|
||||
|
||||
void onTapFrom() {
|
||||
void onChangeFromLanguage({String? languageCode, String? languageName}) {
|
||||
Get.bottomSheet(
|
||||
LanguageSceneBottomSheet(
|
||||
TLanguageSceneBottomSheet(
|
||||
languageScene: languageScene,
|
||||
selectedLanguage: fromLanguage,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void onTapTo() {
|
||||
void onChangeToLanguage({String? languageCode, String? languageName}) {
|
||||
Get.bottomSheet(
|
||||
LanguageSceneBottomSheet(
|
||||
TLanguageSceneBottomSheet(
|
||||
languageScene: languageScene,
|
||||
selectedLanguage: toLanguage,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String getSentence(bool isFrom, SceneList item) {
|
||||
void translatorTtsPlay(bool isFrom, SceneList item, {String? language}) {
|
||||
FlutterTtsManager().translatorTtsPlay(
|
||||
getSentence(isFrom, item),
|
||||
isFrom ? fromLanguage.value.languageCode : toLanguage.value.languageCode,
|
||||
);
|
||||
}
|
||||
|
||||
String getSentence(bool isFrom, SceneList item, {String? language}) {
|
||||
List keys = item.toMap().keys.toList();
|
||||
int index = 0;
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
@ -70,11 +77,4 @@ class SceneListController extends GetxController {
|
||||
}
|
||||
return 'loading';
|
||||
}
|
||||
|
||||
void translatorTtsPlay(bool isFrom, SceneList item) {
|
||||
FlutterTtsManager().translatorTtsPlay(
|
||||
getSentence(isFrom, item),
|
||||
isFrom ? fromLanguage.value.languageCode : toLanguage.value.languageCode,
|
||||
);
|
||||
}
|
||||
}
|
||||
131
lib/page/scene_category_item/scene_category_item_view.dart
Normal file
131
lib/page/scene_category_item/scene_category_item_view.dart
Normal file
@ -0,0 +1,131 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/scene_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/scene_category_item/scene_category_item_controller.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_base_scrollbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_language_scene_bar_widget.dart';
|
||||
|
||||
class SceneCategoryItemView extends GetView<SceneCategoryItemController> {
|
||||
const SceneCategoryItemView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xffF5F6F8),
|
||||
appBar: TBaseAppbarWidget(
|
||||
titleWidget: TLanguageSceneBarWidget(
|
||||
fromLanguage: controller.fromLanguage,
|
||||
toLanguage: controller.toLanguage,
|
||||
onTapFrom: controller.onChangeFromLanguage,
|
||||
onTapTo: controller.onChangeToLanguage,
|
||||
),
|
||||
),
|
||||
body: _buildList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildList() {
|
||||
return Expanded(
|
||||
child: TBaseScrollbarWidget(
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
itemCount: controller.sceneList.length,
|
||||
itemBuilder: (context, index) {
|
||||
var item = controller.sceneList[index];
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Obx(
|
||||
() => Column(
|
||||
children: [
|
||||
_buildScene(
|
||||
item,
|
||||
isFrom: true,
|
||||
languageName: controller.fromLanguage.value.languageName,
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 1,
|
||||
color: const Color(0xffF4F4F4),
|
||||
margin: const EdgeInsets.symmetric(vertical: 20),
|
||||
),
|
||||
_buildScene(
|
||||
item,
|
||||
isFrom: false,
|
||||
languageName: controller.toLanguage.value.languageName,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return const SizedBox(height: 12);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildScene(
|
||||
SceneList item, {
|
||||
required bool isFrom,
|
||||
required String languageName,
|
||||
}) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
languageName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xffC2C3C5),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
return Text(
|
||||
controller.getSentence(isFrom, item),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff152A3D),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => controller.translatorTtsPlay(isFrom, item),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: const Color(0xff4ECA8C).withOpacity(0.2),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.none,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svgSpeaker,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/scene_list/scene_list_controller.dart';
|
||||
|
||||
class SceneListBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SceneListController());
|
||||
}
|
||||
}
|
||||
@ -1,174 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/scene_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/scene_list/scene_list_controller.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/widget/base_scrollbar.dart';
|
||||
import 'package:trans_lark/widget/language_scene_bar.dart';
|
||||
|
||||
class SceneListView extends GetView<SceneListController> {
|
||||
const SceneListView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xffF5F6F8),
|
||||
appBar: BaseAppBar(
|
||||
titleWidget: LanguageSceneBar(
|
||||
fromLanguage: controller.fromLanguage,
|
||||
toLanguage: controller.toLanguage,
|
||||
onTapFrom: controller.onTapFrom,
|
||||
onTapTo: controller.onTapTo,
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BaseScrollbar(
|
||||
child: ListView.separated(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
itemCount: controller.sceneList.length,
|
||||
itemBuilder: (context, index) {
|
||||
var item = controller.sceneList[index];
|
||||
return _buildItem(item);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return const SizedBox(height: 12);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItem(SceneList item) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Obx(() {
|
||||
return Text(
|
||||
controller.fromLanguage.value.languageName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xffC2C3C5),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
return Text(
|
||||
controller.getSentence(true, item),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff152A3D),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => controller.translatorTtsPlay(true, item),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: const Color(0xff4ECA8C).withOpacity(0.2),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.none,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svgSpeaker,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 1,
|
||||
color: const Color(0xffF4F4F4),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
Obx(() {
|
||||
return Text(
|
||||
controller.toLanguage.value.languageName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xffC2C3C5),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
return Text(
|
||||
controller.getSentence(false, item),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff152A3D),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => controller.translatorTtsPlay(false, item),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: const Color(0xff4ECA8C).withOpacity(0.2),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.none,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svgSpeaker,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/scene_type/scene_type_controller.dart';
|
||||
|
||||
class SceneTypeBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SceneTypeController());
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
import 'package:trans_lark/router/get_router.dart';
|
||||
|
||||
class SettingsController extends GetxController {
|
||||
var versionName = ''.obs;
|
||||
// var options = ['Feedback', 'Privacy Policy', 'User Agreement'];
|
||||
|
||||
var options = ['Privacy Policy', 'User Agreement'];
|
||||
|
||||
@override
|
||||
@ -19,7 +19,7 @@ class SettingsController extends GetxController {
|
||||
versionName.value = 'version number ${packageInfo.version}';
|
||||
}
|
||||
|
||||
void itemOnTap(int index) {
|
||||
void clickItem(int index, {String? title}) {
|
||||
if (index == 0) {
|
||||
Get.toNamed(GetRouter.privacy, arguments: {
|
||||
'title': options[index],
|
||||
|
||||
@ -1,147 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/global_config.dart';
|
||||
import 'package:trans_lark/widget/divider_widget.dart';
|
||||
|
||||
import 'settings_controller.dart';
|
||||
|
||||
class SettingsView extends StatelessWidget {
|
||||
SettingsView({super.key});
|
||||
|
||||
final controller = Get.put(SettingsController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height * 0.77,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(26), topRight: Radius.circular(26),
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Image.asset(
|
||||
Assets.imagesHomeBackground,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 384,
|
||||
fit: BoxFit.fitWidth,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 46),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 34),
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: Image.asset(
|
||||
Assets.launcherIconLauncherIcon,
|
||||
width: 48,
|
||||
height: 48,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
GlobalConfig.appName,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w500,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Obx(() {
|
||||
return Text(
|
||||
controller.versionName.value,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff979797),
|
||||
fontSize: 12,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
// _buildItem('Give a good review', -1),
|
||||
// const SizedBox(height: 15),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 34),
|
||||
child: DividerWidget(),
|
||||
),
|
||||
_buildListView(),
|
||||
Image.asset(
|
||||
Assets.imagesRabbitSayGood,
|
||||
width: 90,
|
||||
height: 90,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
const SizedBox(height: 58),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListView() {
|
||||
return Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: controller.options.length,
|
||||
itemBuilder: (context, index) {
|
||||
var item = controller.options[index];
|
||||
return _buildItem(item, index);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItem(String item, int index) {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => controller.itemOnTap(index),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 30),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
item,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff222F38),
|
||||
fontSize: 16,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Icon(
|
||||
Icons.keyboard_arrow_right_rounded,
|
||||
color: Color(0xffBCC0CE),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
149
lib/page/settings/settings_widget.dart
Normal file
149
lib/page/settings/settings_widget.dart
Normal file
@ -0,0 +1,149 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/global_config.dart';
|
||||
import 'package:trans_lark/widget/t_divider_widget.dart';
|
||||
|
||||
import 'settings_controller.dart';
|
||||
|
||||
class SettingsWidget extends StatelessWidget {
|
||||
SettingsWidget({super.key});
|
||||
|
||||
final controller = Get.put(SettingsController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height * 0.77,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(26),
|
||||
topRight: Radius.circular(26),
|
||||
),
|
||||
),
|
||||
child: _buildSettingBody(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSettingBody(context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Image.asset(
|
||||
Assets.imagesHomeBackground,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 384,
|
||||
fit: BoxFit.fitWidth,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 46),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 34),
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: Image.asset(
|
||||
Assets.launcherIconLauncherIcon,
|
||||
width: 48,
|
||||
height: 48,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
GlobalConfig.appName,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w500,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Obx(() {
|
||||
return Text(
|
||||
controller.versionName.value,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff979797),
|
||||
fontSize: 12,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
// _buildItem('Give a good review', -1),
|
||||
// const SizedBox(height: 15),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 34),
|
||||
child: TDividerWidget(),
|
||||
),
|
||||
_buildSettingItems(),
|
||||
Image.asset(
|
||||
Assets.imagesRabbitSayGood,
|
||||
width: 90,
|
||||
height: 90,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
const SizedBox(height: 58),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSettingItems() {
|
||||
return Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: controller.options.length,
|
||||
itemBuilder: (context, index) {
|
||||
var item = controller.options[index];
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => controller.clickItem(index),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 15, horizontal: 30),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
item,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff222F38),
|
||||
fontSize: 16,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Icon(
|
||||
Icons.keyboard_arrow_right_rounded,
|
||||
color: Color(0xffBCC0CE),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/splash/splash_controller.dart';
|
||||
|
||||
class SplashBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SplashController());
|
||||
}
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
|
||||
class SplashController extends GetxController with GetTickerProviderStateMixin {
|
||||
var processValue = 0.0.obs;
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 10),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
// 创建 Tween 并绑定到 AnimationController
|
||||
_animation = Tween<double>(begin: 0, end: 1).animate(_controller)
|
||||
..addListener(() {
|
||||
processValue.value = _animation.value;
|
||||
if (processValue.value >= 1) {
|
||||
_openInitial();
|
||||
}
|
||||
});
|
||||
|
||||
// 启动动画
|
||||
_controller.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_controller.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
/// 打开首个页面
|
||||
void _openInitial() {
|
||||
Get.offNamed(GetRouter.home);
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/splash/splash_controller.dart';
|
||||
|
||||
class SplashView extends GetView<SplashController> {
|
||||
const SplashView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
// _buildImageBg(),
|
||||
_buildProgress(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Widget _buildImageBg() {
|
||||
// return Image.asset(
|
||||
// Assets.sideALaunchImage,
|
||||
// width: ,
|
||||
// height: ,
|
||||
// fit: BoxFit.cover,
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget _buildProgress() {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.only(bottom: 60),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 0.5,
|
||||
child: Obx(() {
|
||||
return LinearProgressIndicator(
|
||||
value: controller.processValue.value,
|
||||
backgroundColor: Colors.white,
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(Color.fromARGB(255, 185, 239, 200)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
);
|
||||
}),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
const Text(
|
||||
'Resource Loading...',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
9
lib/page/translator/translator_binding.dart
Normal file
9
lib/page/translator/translator_binding.dart
Normal file
@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/translator/translator_controller.dart';
|
||||
|
||||
class TranslatorBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => TranslatorController());
|
||||
}
|
||||
}
|
||||
146
lib/page/translator/translator_controller.dart
Normal file
146
lib/page/translator/translator_controller.dart
Normal file
@ -0,0 +1,146 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:speech_to_text/speech_recognition_result.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
import 'package:trans_lark/global/speech_to_text_manager.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/hive/history_data.dart';
|
||||
import 'package:trans_lark/router/get_router.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/util/t_permission_utils.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
import 'package:trans_lark/widget/t_speak_dialog.dart';
|
||||
|
||||
class TranslatorController extends GetxController {
|
||||
var textController = TextEditingController();
|
||||
var isValue = false.obs;
|
||||
var historyList = <HistoryEntity>[].obs;
|
||||
var lastWords = '';
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_getAllHistory();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
textController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
_getAllHistory() async {
|
||||
historyList.value = HistoryData().getAllHistory().reversed.toList();
|
||||
}
|
||||
|
||||
void onSpeakTranslation() {
|
||||
if (isValue.value) {
|
||||
textController.text = "";
|
||||
isValue.value = false;
|
||||
} else {
|
||||
_onSpeak();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSpeak({String? translation}) async {
|
||||
bool micResult = await TPermissionUtils.checkPermission(
|
||||
[Permission.microphone],
|
||||
);
|
||||
if (!micResult) return;
|
||||
if (Platform.isIOS) {
|
||||
bool speechResult = await TPermissionUtils.checkPermission(
|
||||
[Permission.speech],
|
||||
);
|
||||
if (!speechResult) return;
|
||||
}
|
||||
await Get.dialog(
|
||||
barrierDismissible: true,
|
||||
useSafeArea: false,
|
||||
TSpeakDialog(
|
||||
isListening: SpeechToTextManager().isListening,
|
||||
onTap: () async {
|
||||
if (!SpeechToTextManager().hasSpeech) {
|
||||
await SpeechToTextManager().init();
|
||||
}
|
||||
if (SpeechToTextManager().hasSpeech) {
|
||||
if (SpeechToTextManager().isListening.value) {
|
||||
_toTranslatorRes();
|
||||
} else {
|
||||
SpeechToTextManager().startListening(
|
||||
TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
_speechRes,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Get.back();
|
||||
TBaseEasyLoading.toast('Speech not available');
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
if (Get.isDialogOpen != null && !Get.isDialogOpen!) {
|
||||
SpeechToTextManager().stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
void _speechRes(SpeechRecognitionResult result) {
|
||||
TPrint.d('识别结果:${result.recognizedWords}');
|
||||
lastWords = result.recognizedWords;
|
||||
}
|
||||
|
||||
void _toTranslatorRes() {
|
||||
if (TObjectUtils.isEmpty(lastWords)) {
|
||||
TBaseEasyLoading.toast('No text recognized');
|
||||
return;
|
||||
}
|
||||
Get.back();
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {"sourceText": lastWords},
|
||||
);
|
||||
}
|
||||
|
||||
void toHistoryItem(HistoryEntity entity, {int? index}) {
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {
|
||||
'sourceText': entity.sourceText,
|
||||
'targetText': entity.targetText,
|
||||
'isHistory': true,
|
||||
'fromLanguage': entity.sourceLanguageName,
|
||||
'toLanguage': entity.targetLanguageName,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void deleteHistoryByIndex(int index, {HistoryEntity? entity}) {
|
||||
// 计算原始列表中的对应索引
|
||||
int indexToRemoveFromDb = HistoryData().getAllHistory().length - 1 - index;
|
||||
historyList.removeAt(indexToRemoveFromDb);
|
||||
HistoryData().deleteHistory(indexToRemoveFromDb);
|
||||
}
|
||||
|
||||
void onTextChanged(String value) {
|
||||
isValue.value = value.trim().isNotEmpty;
|
||||
}
|
||||
|
||||
void onTextSubmit(String value) {
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {"sourceText": value},
|
||||
);
|
||||
}
|
||||
|
||||
void insertHistory(HistoryEntity entity, {int? index}) {
|
||||
historyList.insert(0, entity);
|
||||
}
|
||||
|
||||
void dropHistory() {
|
||||
historyList.clear();
|
||||
HistoryData().clearHistory();
|
||||
}
|
||||
}
|
||||
@ -1,144 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:speech_to_text/speech_recognition_result.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
import 'package:trans_lark/global/speech_to_text_manager.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
import 'package:trans_lark/storage/history_data.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/util/permission_util.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
import 'package:trans_lark/widget/speak_dialog.dart';
|
||||
|
||||
import 'translator_state.dart';
|
||||
|
||||
/// @description:
|
||||
/// @author
|
||||
/// @date: 2024-06-27 13:55:27
|
||||
class TranslatorLogic extends GetxController {
|
||||
final state = TranslatorState();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
initData();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
state.textController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
initData() async {
|
||||
state.historyList.value = HistoryData().getList().reversed.toList();
|
||||
}
|
||||
|
||||
void onTapSuffix() {
|
||||
if (state.isValue.value) {
|
||||
state.textController.text = "";
|
||||
state.isValue.value = false;
|
||||
} else {
|
||||
_onTapSpeak();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onTapSpeak() async {
|
||||
bool micResult =
|
||||
await PermissionUtil.checkPermission([Permission.microphone]);
|
||||
if (!micResult) return;
|
||||
if (Platform.isIOS) {
|
||||
bool speechResult =
|
||||
await PermissionUtil.checkPermission([Permission.speech]);
|
||||
if (!speechResult) return;
|
||||
}
|
||||
await Get.dialog(
|
||||
barrierDismissible: true,
|
||||
useSafeArea: false,
|
||||
SpeakDialog(
|
||||
isListening: SpeechToTextManager().isListening,
|
||||
onTap: () async {
|
||||
if (!SpeechToTextManager().hasSpeech) {
|
||||
await SpeechToTextManager().initSpeech();
|
||||
}
|
||||
if (SpeechToTextManager().hasSpeech) {
|
||||
if (SpeechToTextManager().isListening.value) {
|
||||
_openTranslatorResultPage();
|
||||
} else {
|
||||
SpeechToTextManager().startListening(
|
||||
TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
_onSpeechResult);
|
||||
}
|
||||
} else {
|
||||
Get.back();
|
||||
BaseEasyLoading.toast('Speech not available');
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
if (Get.isDialogOpen != null && !Get.isDialogOpen!) {
|
||||
SpeechToTextManager().stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
void _onSpeechResult(SpeechRecognitionResult result) {
|
||||
LogPrint.d('识别结果:${result.recognizedWords}');
|
||||
state.lastWords = result.recognizedWords;
|
||||
}
|
||||
|
||||
void _openTranslatorResultPage() {
|
||||
if (ObjUtil.isEmpty(state.lastWords)) {
|
||||
BaseEasyLoading.toast('No text recognized');
|
||||
return;
|
||||
}
|
||||
Get.back();
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {"sourceText": state.lastWords},
|
||||
);
|
||||
}
|
||||
|
||||
void onTapHistoryItem(HistoryEntity entity) {
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {
|
||||
'sourceText': entity.sourceText,
|
||||
'targetText': entity.targetText,
|
||||
'isHistory': true,
|
||||
'fromLanguage': entity.sourceLanguageName,
|
||||
'toLanguage': entity.targetLanguageName,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void deleteItem(int index) {
|
||||
// 计算原始列表中的对应索引
|
||||
int indexToRemoveFromDb = HistoryData().getList().length - 1 - index;
|
||||
state.historyList.removeAt(indexToRemoveFromDb);
|
||||
HistoryData().delete(indexToRemoveFromDb);
|
||||
}
|
||||
|
||||
void onChanged(String value) {
|
||||
state.isValue.value = value.trim().isNotEmpty;
|
||||
}
|
||||
|
||||
void onSubmitted(String value) {
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {"sourceText": value},
|
||||
);
|
||||
}
|
||||
|
||||
void insertHistory(HistoryEntity entity) {
|
||||
state.historyList.insert(0, entity);
|
||||
}
|
||||
|
||||
void cleanAllHistory() {
|
||||
state.historyList.clear();
|
||||
HistoryData().clear();
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
import 'package:trans_lark/entity/translator_history_entity.dart';
|
||||
|
||||
/// @description:
|
||||
/// @author
|
||||
/// @date: 2024-06-27 13:55:27
|
||||
class TranslatorState {
|
||||
var textController = TextEditingController();
|
||||
var isValue = false.obs;
|
||||
var historyList = <HistoryEntity>[].obs;
|
||||
var lastWords = '';
|
||||
}
|
||||
@ -3,35 +3,20 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/translator/translator_logic.dart';
|
||||
import 'package:trans_lark/page/translator/translator_state.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/widget/language_bar.dart';
|
||||
import 'package:trans_lark/page/translator/translator_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_language_bar_widget.dart';
|
||||
|
||||
class TranslatorPage extends StatefulWidget {
|
||||
const TranslatorPage({super.key});
|
||||
|
||||
@override
|
||||
State<TranslatorPage> createState() => _TranslatorPageState();
|
||||
}
|
||||
|
||||
class _TranslatorPageState extends State<TranslatorPage> {
|
||||
final TranslatorLogic logic = Get.put(TranslatorLogic());
|
||||
|
||||
final TranslatorState state = Get.find<TranslatorLogic>().state;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
class TranslatorView extends GetView<TranslatorController> {
|
||||
const TranslatorView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const BaseAppBar(
|
||||
titleWidget: LanguageBar(),
|
||||
appBar: const TBaseAppbarWidget(
|
||||
titleWidget: TLanguageBarWidget(),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
@ -53,7 +38,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
textInputAction: TextInputAction.done,
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
textAlign: TextAlign.left,
|
||||
controller: state.textController,
|
||||
controller: controller.textController,
|
||||
maxLines: null,
|
||||
minLines: 1,
|
||||
autofocus: true,
|
||||
@ -74,19 +59,19 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
onChanged: (value) => logic.onChanged(value),
|
||||
onSubmitted: (value) => logic.onSubmitted(value),
|
||||
onChanged: (value) => controller.onTextChanged(value),
|
||||
onSubmitted: (value) => controller.onTextSubmit(value),
|
||||
),
|
||||
),
|
||||
Obx(() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: state.isValue.value ? 26 : 20, right: 20),
|
||||
top: controller.isValue.value ? 26 : 20, right: 20),
|
||||
child: GestureDetector(
|
||||
onTap: logic.onTapSuffix,
|
||||
onTap: controller.onSpeakTranslation,
|
||||
child: ClipOval(
|
||||
child: Visibility(
|
||||
visible: state.isValue.value,
|
||||
visible: controller.isValue.value,
|
||||
replacement: Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
@ -111,7 +96,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => state.historyList.isNotEmpty
|
||||
() => controller.historyList.isNotEmpty
|
||||
? Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
@ -128,7 +113,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: logic.cleanAllHistory,
|
||||
onPressed: controller.dropHistory,
|
||||
icon: Image.asset(
|
||||
Assets.imagesDeleteIcon,
|
||||
width: 24,
|
||||
@ -139,9 +124,9 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.historyList.length,
|
||||
itemCount: controller.historyList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final historyEntity = state.historyList[index];
|
||||
final historyEntity = controller.historyList[index];
|
||||
return CustomPopupMenu(
|
||||
arrowColor: Colors.black,
|
||||
barrierColor: Colors.transparent,
|
||||
@ -150,7 +135,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
pressType: PressType.longPress,
|
||||
menuBuilder: () {
|
||||
return GestureDetector(
|
||||
onTap: () => logic.deleteItem(index),
|
||||
onTap: () => controller.deleteHistoryByIndex(index),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
@ -168,7 +153,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () =>
|
||||
logic.onTapHistoryItem(historyEntity),
|
||||
controller.toHistoryItem(historyEntity),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
@ -182,7 +167,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: ObjUtil.getStr(
|
||||
text: TObjectUtils.getStr(
|
||||
historyEntity.sourceText),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -196,7 +181,7 @@ class _TranslatorPageState extends State<TranslatorPage> {
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ObjUtil.getStr(
|
||||
text: TObjectUtils.getStr(
|
||||
historyEntity.targetText),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff979797),
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_rx/get_rx.dart';
|
||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
|
||||
class TranslatorHistoryState {
|
||||
RxMap<String, List<HistoryEntity>> historyList = <String, List<HistoryEntity>>{}.obs;
|
||||
}
|
||||
@ -1,203 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/translator_history/translator_history_logic.dart';
|
||||
import 'package:trans_lark/page/translator_history/translator_history_state.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/widget/base_scrollbar.dart';
|
||||
|
||||
class TranslatorHistoryPage extends StatefulWidget {
|
||||
static String routName = "/translateHistory";
|
||||
|
||||
const TranslatorHistoryPage({super.key});
|
||||
|
||||
@override
|
||||
State<TranslatorHistoryPage> createState() => _TranslatorHistoryPageState();
|
||||
}
|
||||
|
||||
class _TranslatorHistoryPageState extends State<TranslatorHistoryPage> {
|
||||
final TranslatorHistoryLogic logic = Get.put(TranslatorHistoryLogic());
|
||||
|
||||
final TranslatorHistoryState state = Get.find<TranslatorHistoryLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const BaseAppBar(
|
||||
title: 'History',
|
||||
backColor: Colors.black,
|
||||
),
|
||||
body: Obx(() {
|
||||
return state.historyList.isNotEmpty ? BaseScrollbar(
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
itemCount: state.historyList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final map = state.historyList.entries.elementAt(index);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text(
|
||||
map.key,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff949494),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: map.value.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = map.value[index];
|
||||
return InkWell(
|
||||
onTap: () => logic.onTapItem(item),
|
||||
child: Dismissible(
|
||||
key: Key(item.translationTime.toString()),
|
||||
dismissThresholds: const {
|
||||
DismissDirection.startToEnd: 0.5,
|
||||
DismissDirection.endToStart: 0.5,
|
||||
},
|
||||
onDismissed: (_) => logic.deleteItem(map.key, item, index),
|
||||
background: Container(
|
||||
color: const Color(0xffFF98BC),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
left: 16,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Image.asset(
|
||||
Assets.imagesDeleteIcon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
secondaryBackground: Container(
|
||||
color: const Color(0xffFF98BC),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
right: 16,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Image.asset(
|
||||
Assets.imagesDeleteIcon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => logic.translatorTtsPlay(item),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
color: const Color(0xff4ECA8C),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.none,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svgSpeakerWhite,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
ObjUtil.getStr(item.sourceText),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff212121),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
ObjUtil.getStr(item.targetText),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff979797),
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return Container(
|
||||
height: 0.5,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 20),
|
||||
color: const Color(0xffEDEDED),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
) : Center(
|
||||
child: Image.asset(
|
||||
Assets.imagesRabbitSayGood,
|
||||
width: 90,
|
||||
height: 90,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
Obx(() {
|
||||
return Visibility(
|
||||
visible: state.historyList.isNotEmpty,
|
||||
child: Positioned(
|
||||
top: 59,
|
||||
right: 23,
|
||||
child: Image.asset(
|
||||
Assets.imagesRabbitSayGood,
|
||||
width: 90,
|
||||
height: 90,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/translator_record/translator_record_controller.dart';
|
||||
|
||||
class TranslatorRecordBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => TranslatorRecordController());
|
||||
}
|
||||
}
|
||||
31
lib/page/translator_history/translator_history_logic.dart → lib/page/translator_record/translator_record_controller.dart
Executable file → Normal file
31
lib/page/translator_history/translator_history_logic.dart → lib/page/translator_record/translator_record_controller.dart
Executable file → Normal file
@ -1,21 +1,20 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/page/translator_history/translator_history_state.dart';
|
||||
import 'package:trans_lark/router/router.dart';
|
||||
import 'package:trans_lark/storage/history_data.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/hive/history_data.dart';
|
||||
import 'package:trans_lark/router/get_router.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
|
||||
class TranslatorHistoryLogic extends GetxController {
|
||||
final state = TranslatorHistoryState();
|
||||
class TranslatorRecordController extends GetxController {
|
||||
RxMap<String, List<HistoryEntity>> historyList = <String, List<HistoryEntity>>{}.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
state.historyList.value = HistoryData().getGroupByList();
|
||||
historyList.value = HistoryData().getMapList();
|
||||
}
|
||||
|
||||
void onTapItem(HistoryEntity entity) {
|
||||
void toHistoryItem(HistoryEntity entity, {int? index}) {
|
||||
Get.toNamed(
|
||||
GetRouter.translateResult,
|
||||
arguments: {
|
||||
@ -28,8 +27,8 @@ class TranslatorHistoryLogic extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
void translatorTtsPlay(HistoryEntity entity) {
|
||||
if (ObjUtil.isNotEmpty(entity.targetText)) {
|
||||
void onTextToSpeech(HistoryEntity entity, {String? text}) {
|
||||
if (TObjectUtils.isNotEmpty(entity.targetText)) {
|
||||
FlutterTtsManager().translatorTtsPlay(
|
||||
entity.targetText!,
|
||||
entity.targetLanguageCode!,
|
||||
@ -37,18 +36,18 @@ class TranslatorHistoryLogic extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
void deleteItem(String key, HistoryEntity entity, int index) {
|
||||
final list = HistoryData().getList();
|
||||
state.historyList.forEach((key, value) {
|
||||
void deleteHistoryItem(String key, HistoryEntity entity, int index) {
|
||||
final list = HistoryData().getAllHistory();
|
||||
historyList.forEach((key, value) {
|
||||
value.removeWhere((e) => e.translationTime == entity.translationTime);
|
||||
});
|
||||
if (state.historyList[key] != null && state.historyList[key]!.isEmpty) {
|
||||
state.historyList.remove(key);
|
||||
if (historyList[key] != null && historyList[key]!.isEmpty) {
|
||||
historyList.remove(key);
|
||||
}
|
||||
final deleteEntity = list.firstWhereOrNull(
|
||||
(item) => item.translationTime == entity.translationTime);
|
||||
if (deleteEntity != null) {
|
||||
HistoryData().delete(list.indexOf(deleteEntity));
|
||||
HistoryData().deleteHistory(list.indexOf(deleteEntity));
|
||||
}
|
||||
}
|
||||
}
|
||||
198
lib/page/translator_record/translator_record_view.dart
Normal file
198
lib/page/translator_record/translator_record_view.dart
Normal file
@ -0,0 +1,198 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/page/translator_record/translator_record_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_base_scrollbar_widget.dart';
|
||||
|
||||
class TranslatorRecordView extends GetView<TranslatorRecordController> {
|
||||
const TranslatorRecordView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const TBaseAppbarWidget(
|
||||
title: 'History',
|
||||
backColor: Colors.black,
|
||||
),
|
||||
body: Obx(() {
|
||||
if (controller.historyList.isNotEmpty) return _buildHistoryList();
|
||||
return Center(
|
||||
child: Image.asset(
|
||||
Assets.imagesRabbitSayGood,
|
||||
width: 90,
|
||||
height: 90,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
Obx(() {
|
||||
return Visibility(
|
||||
visible: controller.historyList.isNotEmpty,
|
||||
child: Positioned(
|
||||
top: 59,
|
||||
right: 23,
|
||||
child: Image.asset(
|
||||
Assets.imagesRabbitSayGood,
|
||||
width: 90,
|
||||
height: 90,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHistoryList() {
|
||||
return TBaseScrollbarWidget(
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
itemCount: controller.historyList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final map = controller.historyList.entries.elementAt(index);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text(
|
||||
map.key,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff949494),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: map.value.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = map.value[index];
|
||||
return InkWell(
|
||||
onTap: () => controller.toHistoryItem(item),
|
||||
child: Dismissible(
|
||||
key: Key(item.translationTime.toString()),
|
||||
dismissThresholds: const {
|
||||
DismissDirection.startToEnd: 0.5,
|
||||
DismissDirection.endToStart: 0.5,
|
||||
},
|
||||
onDismissed: (_) =>
|
||||
controller.deleteHistoryItem(map.key, item, index),
|
||||
background: Container(
|
||||
color: const Color(0xffFF98BC),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
left: 16,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Image.asset(
|
||||
Assets.imagesDeleteIcon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
secondaryBackground: Container(
|
||||
color: const Color(0xffFF98BC),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
right: 16,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Image.asset(
|
||||
Assets.imagesDeleteIcon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 20),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => controller.onTextToSpeech(item),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
color: const Color(0xff4ECA8C),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.none,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svgSpeakerWhite,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
TObjectUtils.getStr(item.sourceText),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff212121),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
TObjectUtils.getStr(item.targetText),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff979797),
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return Container(
|
||||
height: 0.5,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 20),
|
||||
color: const Color(0xffEDEDED),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_controller.dart';
|
||||
|
||||
class TranslatorResultBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => TranslatorResultController());
|
||||
}
|
||||
}
|
||||
112
lib/page/translator_result/translator_result_controller.dart
Normal file
112
lib/page/translator_result/translator_result_controller.dart
Normal file
@ -0,0 +1,112 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/hive/history_data.dart';
|
||||
import 'package:trans_lark/page/translator/translator_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/util/t_print.dart';
|
||||
import 'package:trans_lark/widget/t_base_easy_loading.dart';
|
||||
import 'package:trans_lark/widget/t_translate_text_full_screen_page.dart';
|
||||
import 'package:translator/translator.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
|
||||
class TranslatorResultController extends GetxController {
|
||||
var translator = GoogleTranslator();
|
||||
RxString sourceText = "".obs;
|
||||
RxString targetText = "".obs;
|
||||
var isTranslationCompleted = false.obs;
|
||||
bool isHistory = false;
|
||||
String? fromLanguage;
|
||||
String? toLanguage;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
sourceText.value = Get.arguments['sourceText'] ?? '';
|
||||
targetText.value = Get.arguments['targetText'] ?? '';
|
||||
isHistory = Get.arguments['isHistory'] ?? false;
|
||||
fromLanguage = Get.arguments['fromLanguage'];
|
||||
toLanguage = Get.arguments['toLanguage'];
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
if (isHistory) {
|
||||
isTranslationCompleted.value = true;
|
||||
} else {
|
||||
translation();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> translation({String? text, String? language}) async {
|
||||
if (TObjectUtils.isNotEmpty(sourceText.value)) {
|
||||
try {
|
||||
Translation translate = await translator.translate(
|
||||
sourceText.value,
|
||||
from: TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
to: TranslateManager().toLanguageEntity.value.languageCode,
|
||||
);
|
||||
targetText.value = translate.text;
|
||||
addHistory();
|
||||
} catch (e) {
|
||||
TBaseEasyLoading.toast('Translation failed');
|
||||
TPrint.d('Translation failed,${e.toString()}');
|
||||
}
|
||||
isTranslationCompleted.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
void addHistory({HistoryEntity? entity, int? index}) {
|
||||
final entity = HistoryEntity(
|
||||
sourceText: sourceText.value,
|
||||
targetText: targetText.value,
|
||||
sourceLanguageName:
|
||||
TranslateManager().fromLanguageEntity.value.languageName,
|
||||
sourceLanguageCode:
|
||||
TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
targetLanguageName:
|
||||
TranslateManager().toLanguageEntity.value.languageName,
|
||||
targetLanguageCode:
|
||||
TranslateManager().toLanguageEntity.value.languageCode,
|
||||
);
|
||||
HistoryData().addHistory(entity);
|
||||
if (Get.isRegistered<TranslatorController>()) {
|
||||
final controller = Get.find<TranslatorController>();
|
||||
controller.insertHistory(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void onTextToSpeech(String text, String type, {String? language}) {
|
||||
if (TObjectUtils.isNotEmpty(text)) {
|
||||
String language =
|
||||
TranslateManager().fromLanguageEntity.value.languageCode;
|
||||
switch (type) {
|
||||
case "from":
|
||||
language = fromLanguage ??
|
||||
TranslateManager().fromLanguageEntity.value.languageCode;
|
||||
break;
|
||||
case "to":
|
||||
language = toLanguage ??
|
||||
TranslateManager().toLanguageEntity.value.languageCode;
|
||||
break;
|
||||
}
|
||||
FlutterTtsManager().translatorTtsPlay(text, language);
|
||||
}
|
||||
}
|
||||
|
||||
void copyText({String? copyText}) {
|
||||
if (TObjectUtils.isNotEmpty(targetText.value)) {
|
||||
Clipboard.setData(ClipboardData(text: targetText.value));
|
||||
TBaseEasyLoading.toast('Copied to clipboard');
|
||||
}
|
||||
}
|
||||
|
||||
void toFullScreen({String? title}) {
|
||||
if (TObjectUtils.isNotEmpty(targetText.value)) {
|
||||
Get.to(() => const TTranslateTextFullScreenPage(),
|
||||
arguments: {"data": targetText.value});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,107 +0,0 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_state.dart';
|
||||
import 'package:trans_lark/util/log_print.dart';
|
||||
import 'package:translator/translator.dart';
|
||||
import 'package:trans_lark/entity/history_model.dart';
|
||||
import 'package:trans_lark/page/translator/translator_logic.dart';
|
||||
import 'package:trans_lark/storage/history_data.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_easyloading.dart';
|
||||
import 'package:trans_lark/widget/translate_text_full_screen_page.dart';
|
||||
|
||||
class TranslatorResultPageLogic extends GetxController {
|
||||
final state = TranslatorResultPageState();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
state.sourceText.value = Get.arguments['sourceText'] ?? '';
|
||||
state.targetText.value = Get.arguments['targetText'] ?? '';
|
||||
state.isHistory = Get.arguments['isHistory'] ?? false;
|
||||
state.fromLanguage = Get.arguments['fromLanguage'];
|
||||
state.toLanguage = Get.arguments['toLanguage'];
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
if (state.isHistory) {
|
||||
state.isTranslationCompleted.value = true;
|
||||
} else {
|
||||
translation();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> translation() async {
|
||||
if (ObjUtil.isNotEmpty(state.sourceText.value)) {
|
||||
try {
|
||||
Translation translate = await state.translator.translate(
|
||||
state.sourceText.value,
|
||||
from: TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
to: TranslateManager().toLanguageEntity.value.languageCode,
|
||||
);
|
||||
state.targetText.value = translate.text;
|
||||
addHistory();
|
||||
} catch (e) {
|
||||
BaseEasyLoading.toast('Translation failed');
|
||||
LogPrint.d('Translation failed,${e.toString()}');
|
||||
}
|
||||
state.isTranslationCompleted.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
void addHistory() {
|
||||
final entity = HistoryEntity(
|
||||
sourceText: state.sourceText.value,
|
||||
targetText: state.targetText.value,
|
||||
sourceLanguageName:
|
||||
TranslateManager().fromLanguageEntity.value.languageName,
|
||||
sourceLanguageCode:
|
||||
TranslateManager().fromLanguageEntity.value.languageCode,
|
||||
targetLanguageName:
|
||||
TranslateManager().toLanguageEntity.value.languageName,
|
||||
targetLanguageCode:
|
||||
TranslateManager().toLanguageEntity.value.languageCode,
|
||||
);
|
||||
HistoryData().addData(entity);
|
||||
if (Get.isRegistered<TranslatorLogic>()) {
|
||||
final logic = Get.find<TranslatorLogic>();
|
||||
logic.insertHistory(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void translatorTtsPlay(String text, type) {
|
||||
if (ObjUtil.isNotEmpty(text)) {
|
||||
String language =
|
||||
TranslateManager().fromLanguageEntity.value.languageCode;
|
||||
switch (type) {
|
||||
case "from":
|
||||
language = state.fromLanguage ??
|
||||
TranslateManager().fromLanguageEntity.value.languageCode;
|
||||
break;
|
||||
case "to":
|
||||
language = state.toLanguage ??
|
||||
TranslateManager().toLanguageEntity.value.languageCode;
|
||||
break;
|
||||
}
|
||||
FlutterTtsManager().translatorTtsPlay(text, language);
|
||||
}
|
||||
}
|
||||
|
||||
void copy() {
|
||||
if (ObjUtil.isNotEmpty(state.targetText.value)) {
|
||||
Clipboard.setData(ClipboardData(text: state.targetText.value));
|
||||
BaseEasyLoading.toast('Copied to clipboard');
|
||||
}
|
||||
}
|
||||
|
||||
void openFullScreenPage() {
|
||||
if (ObjUtil.isNotEmpty(state.targetText.value)) {
|
||||
Get.to(() => const TranslateTextFullScreenPage(),
|
||||
arguments: {"data": state.targetText.value});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||
import 'package:translator/translator.dart';
|
||||
|
||||
class TranslatorResultPageState {
|
||||
var translator = GoogleTranslator();
|
||||
RxString sourceText = "".obs;
|
||||
RxString targetText = "".obs;
|
||||
var isTranslationCompleted = false.obs;
|
||||
bool isHistory = false;
|
||||
String? fromLanguage;
|
||||
String? toLanguage;
|
||||
}
|
||||
@ -3,56 +3,57 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_logic.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_state.dart';
|
||||
import 'package:trans_lark/util/obj_util.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/widget/language_result_bar.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_controller.dart';
|
||||
import 'package:trans_lark/util/t_object_utils.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_language_result_bar_widget.dart';
|
||||
|
||||
class TranslatorResultPage extends StatefulWidget {
|
||||
const TranslatorResultPage({super.key});
|
||||
|
||||
@override
|
||||
State<TranslatorResultPage> createState() => _TranslatorResultPageState();
|
||||
}
|
||||
|
||||
class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
final TranslatorResultPageLogic logic = Get.put(TranslatorResultPageLogic());
|
||||
|
||||
final TranslatorResultPageState state =
|
||||
Get.find<TranslatorResultPageLogic>().state;
|
||||
class TranslatorResultView extends GetView<TranslatorResultController> {
|
||||
const TranslatorResultView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
height: double.infinity,
|
||||
width: double.infinity,
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(Assets.imagesTranslatorResultBackground),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
BaseAppBar(
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
titleWidget: LanguageResultBar(
|
||||
fromLanguage: state.isHistory
|
||||
? (state.fromLanguage != null ? state.fromLanguage! : '')
|
||||
appBar: _buildAppbar(),
|
||||
body: _buildBody(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TBaseAppbarWidget _buildAppbar() {
|
||||
return TBaseAppbarWidget(
|
||||
backgroundColor: Colors.transparent,
|
||||
titleWidget: TLanguageResultBarWidget(
|
||||
fromLanguage: controller.isHistory
|
||||
? (controller.fromLanguage != null ? controller.fromLanguage! : '')
|
||||
: TranslateManager().fromLanguageEntity.value.languageName,
|
||||
toLanguage: state.isHistory
|
||||
? (state.toLanguage != null ? state.toLanguage! : '')
|
||||
toLanguage: controller.isHistory
|
||||
? (controller.toLanguage != null ? controller.toLanguage! : '')
|
||||
: TranslateManager().toLanguageEntity.value.languageName,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return ListView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
children: [
|
||||
Obx(
|
||||
() => Padding(
|
||||
_buildFromWidget(),
|
||||
_buildToWidget(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFromWidget() {
|
||||
return Obx(() => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -62,7 +63,7 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
state.sourceText.value,
|
||||
controller.sourceText.value,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -90,8 +91,10 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
height: 30,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => logic.translatorTtsPlay(
|
||||
state.sourceText.value, "from"),
|
||||
onTap: () => controller.onTextToSpeech(
|
||||
controller.sourceText.value,
|
||||
"from",
|
||||
),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
@ -116,9 +119,11 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildToWidget() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -130,10 +135,7 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
TranslateManager()
|
||||
.toLanguageEntity
|
||||
.value
|
||||
.languageName,
|
||||
TranslateManager().toLanguageEntity.value.languageName,
|
||||
style: const TextStyle(
|
||||
color: Color(0xff949494),
|
||||
fontSize: 16,
|
||||
@ -143,7 +145,7 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Visibility(
|
||||
visible: !state.isTranslationCompleted.value,
|
||||
visible: !controller.isTranslationCompleted.value,
|
||||
child: const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
@ -159,7 +161,7 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
),
|
||||
Obx(
|
||||
() => Text(
|
||||
state.targetText.value,
|
||||
controller.targetText.value,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -172,13 +174,14 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
),
|
||||
Obx(() {
|
||||
return Visibility(
|
||||
visible:
|
||||
ObjUtil.isNotEmptyStr(state.targetText.value),
|
||||
visible: TObjectUtils.isNotEmptyStr(controller.targetText.value),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => logic.translatorTtsPlay(
|
||||
state.targetText.value, "to"),
|
||||
onTap: () => controller.onTextToSpeech(
|
||||
controller.targetText.value,
|
||||
"to",
|
||||
),
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
@ -197,7 +200,7 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
GestureDetector(
|
||||
onTap: logic.copy,
|
||||
onTap: controller.copyText,
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
@ -216,7 +219,7 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
GestureDetector(
|
||||
onTap: logic.openFullScreenPage,
|
||||
onTap: controller.toFullScreen,
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
width: 32,
|
||||
@ -239,12 +242,6 @@ class _TranslatorResultPageState extends State<TranslatorResultPage> {
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/widget/view_state_widget.dart';
|
||||
import 'package:trans_lark/widget/t_view_state_widget.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class WebPageController extends GetxController {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/web_page/web_page_controller.dart';
|
||||
import 'package:trans_lark/widget/base_appbar.dart';
|
||||
import 'package:trans_lark/widget/view_state_widget.dart';
|
||||
import 'package:trans_lark/widget/t_base_appbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_view_state_widget.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class WebPageView extends GetView<WebPageController> {
|
||||
@ -12,11 +12,11 @@ class WebPageView extends GetView<WebPageController> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: BaseAppBar(
|
||||
appBar: TBaseAppbarWidget(
|
||||
title: controller.title,
|
||||
),
|
||||
body: Obx(() {
|
||||
return ViewStateWidget(
|
||||
return TViewStateWidget(
|
||||
viewState: controller.viewState.value,
|
||||
child: WebViewWidget(controller: controller.webViewController),
|
||||
);
|
||||
|
||||
88
lib/router/get_router.dart
Normal file
88
lib/router/get_router.dart
Normal file
@ -0,0 +1,88 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/index/index_view.dart';
|
||||
import 'package:trans_lark/page/p2p/p2p_binding.dart';
|
||||
import 'package:trans_lark/page/p2p/p2p_view.dart';
|
||||
import 'package:trans_lark/page/scene_category/scene_category_binding.dart';
|
||||
import 'package:trans_lark/page/scene_category/scene_category_view.dart';
|
||||
import 'package:trans_lark/page/scene_category_item/scene_category_item_binding.dart';
|
||||
import 'package:trans_lark/page/scene_category_item/scene_category_item_view.dart';
|
||||
import 'package:trans_lark/page/translator/translator_binding.dart';
|
||||
import 'package:trans_lark/page/translator/translator_view.dart';
|
||||
import 'package:trans_lark/page/translator_record/translator_record_binding.dart';
|
||||
import 'package:trans_lark/page/translator_record/translator_record_view.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_binding.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_view.dart';
|
||||
import 'package:trans_lark/page/web_page/web_page_binding.dart';
|
||||
import 'package:trans_lark/page/web_page/web_page_view.dart';
|
||||
|
||||
class GetRouter {
|
||||
static const splash = '/';
|
||||
static const index = '/index';
|
||||
static const sceneCategory = '/scene_category';
|
||||
static const sceneList = '/scene_list';
|
||||
static const translate = '/translate';
|
||||
static const p2p = '/p2p';
|
||||
static const translateResult = '/translate_result';
|
||||
static const translateRecord = '/translate_record';
|
||||
static const terms = '/terms';
|
||||
static const privacy = '/privacy';
|
||||
|
||||
static List<GetPage> routers = [
|
||||
// GetPage(
|
||||
// name: splash,
|
||||
// page: () => SplashView(),
|
||||
// binding: SplashBinding(),
|
||||
// ),
|
||||
//首页
|
||||
GetPage(
|
||||
name: index,
|
||||
page: () => IndexView(),
|
||||
),
|
||||
GetPage(
|
||||
name: sceneCategory,
|
||||
page: () => SceneCategoryView(),
|
||||
binding: SceneCategoryBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: sceneList,
|
||||
page: () => const SceneCategoryItemView(),
|
||||
binding: SceneCategoryItemBinding(),
|
||||
),
|
||||
//翻译输入页面
|
||||
GetPage(
|
||||
name: translate,
|
||||
page: () => const TranslatorView(),
|
||||
binding: TranslatorBinding(),
|
||||
),
|
||||
//翻译结果页
|
||||
GetPage(
|
||||
name: translateResult,
|
||||
page: () => const TranslatorResultView(),
|
||||
binding: TranslatorResultBinding(),
|
||||
),
|
||||
//翻译历史页面
|
||||
GetPage(
|
||||
name: translateRecord,
|
||||
page: () => const TranslatorRecordView(),
|
||||
binding: TranslatorRecordBinding(),
|
||||
),
|
||||
// 面对面翻译
|
||||
GetPage(
|
||||
name: p2p,
|
||||
page: () => const P2PView(),
|
||||
binding: P2PBinding(),
|
||||
),
|
||||
// 隐私政策
|
||||
GetPage(
|
||||
name: privacy,
|
||||
page: () => const WebPageView(),
|
||||
binding: WebPageBinding(),
|
||||
),
|
||||
// 用户协议
|
||||
GetPage(
|
||||
name: terms,
|
||||
page: () => const WebPageView(),
|
||||
binding: WebPageBinding(),
|
||||
),
|
||||
];
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/page/face_to_face/face_to_face_binding.dart';
|
||||
import 'package:trans_lark/page/face_to_face/face_to_face_view.dart';
|
||||
import 'package:trans_lark/page/home/home_view.dart';
|
||||
import 'package:trans_lark/page/scene_list/scene_list_binding.dart';
|
||||
import 'package:trans_lark/page/scene_list/scene_list_view.dart';
|
||||
import 'package:trans_lark/page/scene_type/scene_type_binding.dart';
|
||||
import 'package:trans_lark/page/scene_type/scene_type_view.dart';
|
||||
import 'package:trans_lark/page/translator/translator_view.dart';
|
||||
import 'package:trans_lark/page/translator_history/translator_history_view.dart';
|
||||
import 'package:trans_lark/page/translator_result/translator_result_view.dart';
|
||||
import 'package:trans_lark/page/web_page/web_page_binding.dart';
|
||||
import 'package:trans_lark/page/web_page/web_page_view.dart';
|
||||
|
||||
class GetRouter {
|
||||
static const splash = '/';
|
||||
static const home = '/home';
|
||||
static const sceneType = '/scene_type';
|
||||
static const sceneList = '/scene_list';
|
||||
static const translate = '/translate';
|
||||
static const faceToFace = '/face_to_face';
|
||||
static const translateResult = '/translate_result';
|
||||
static const translateHistory = '/translate_history';
|
||||
static const terms = '/terms';
|
||||
static const privacy = '/privacy';
|
||||
|
||||
static List<GetPage> routers = [
|
||||
// GetPage(
|
||||
// name: splash,
|
||||
// page: () => SplashView(),
|
||||
// binding: SplashBinding(),
|
||||
// ),
|
||||
//首页
|
||||
GetPage(
|
||||
name: home,
|
||||
page: () => HomePage(),
|
||||
),
|
||||
GetPage(
|
||||
name: sceneType,
|
||||
page: () => SceneTypeView(),
|
||||
binding: SceneTypeBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: sceneList,
|
||||
page: () => SceneListView(),
|
||||
binding: SceneListBinding(),
|
||||
),
|
||||
//翻译输入页面
|
||||
GetPage(
|
||||
name: translate,
|
||||
page: () => const TranslatorPage(),
|
||||
),
|
||||
//翻译结果页
|
||||
GetPage(
|
||||
name: translateResult,
|
||||
page: () => const TranslatorResultPage(),
|
||||
),
|
||||
//翻译历史页面
|
||||
GetPage(
|
||||
name: translateHistory,
|
||||
page: () => const TranslatorHistoryPage(),
|
||||
),
|
||||
// 面对面翻译
|
||||
GetPage(
|
||||
name: faceToFace,
|
||||
page: () => FaceToFaceView(),
|
||||
binding: FaceToFaceBinding(),
|
||||
),
|
||||
// 隐私政策
|
||||
GetPage(
|
||||
name: privacy,
|
||||
page: () => WebPageView(),
|
||||
binding: WebPageBinding(),
|
||||
),
|
||||
// 用户协议
|
||||
GetPage(
|
||||
name: terms,
|
||||
page: () => WebPageView(),
|
||||
binding: WebPageBinding(),
|
||||
),
|
||||
];
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DateConverter {
|
||||
static stringToYyMmDd(String date) {
|
||||
DateTime sourceDate = DateTime.parse(date);
|
||||
String formatDate = DateFormat("yyyy-MM-dd").format(sourceDate);
|
||||
return formatDate;
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DateFormats {
|
||||
static String full = 'yyyy-MM-dd HH:mm:ss';
|
||||
static String yMoDHM = 'yyyy-MM-dd HH:mm';
|
||||
@ -18,7 +20,7 @@ class DateFormats {
|
||||
static String zhHM = 'HH时mm分';
|
||||
}
|
||||
|
||||
class DateUtil {
|
||||
class TDateUtils {
|
||||
/// 月->天数.
|
||||
static Map<int, int> monthDay = {
|
||||
1: 31,
|
||||
@ -188,7 +190,7 @@ class DateUtil {
|
||||
DateTime.fromMillisecondsSinceEpoch(milliseconds, isUtc: isUtc);
|
||||
DateTime now;
|
||||
if (locMs != null) {
|
||||
now = DateUtil.getDateTimeByMs(locMs);
|
||||
now = TDateUtils.getDateTimeByMs(locMs);
|
||||
} else {
|
||||
now = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal();
|
||||
}
|
||||
@ -223,7 +225,7 @@ class DateUtil {
|
||||
DateTime oldT = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc);
|
||||
DateTime nowT;
|
||||
if (locMs != null) {
|
||||
nowT = DateUtil.getDateTimeByMs(locMs, isUtc: isUtc);
|
||||
nowT = TDateUtils.getDateTimeByMs(locMs, isUtc: isUtc);
|
||||
} else {
|
||||
nowT = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal();
|
||||
}
|
||||
@ -285,4 +287,10 @@ class DateUtil {
|
||||
}
|
||||
return dateTime.month + 1;
|
||||
}
|
||||
|
||||
static stringToYyMmDd(String date) {
|
||||
DateTime sourceDate = DateTime.parse(date);
|
||||
String formatDate = DateFormat("yyyy-MM-dd").format(sourceDate);
|
||||
return formatDate;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
|
||||
class DeviceInfoUtil {
|
||||
class TDeviceUtils {
|
||||
/// 获取当前Android设备的系统版本
|
||||
static Future<int> getAndroidSDKInt() async {
|
||||
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
|
||||
@ -1,6 +1,6 @@
|
||||
import 'dart:math';
|
||||
|
||||
class NumUtil {
|
||||
class TNumberUtils {
|
||||
/// 获取一个随机随
|
||||
static int getRandomNumber(int min, int max) {
|
||||
Random random = Random();
|
||||
@ -1,4 +1,4 @@
|
||||
class ObjUtil {
|
||||
class TObjectUtils {
|
||||
static bool isNotEmptyStr(String? str) {
|
||||
return str != null && str.trim().isNotEmpty;
|
||||
}
|
||||
@ -2,9 +2,9 @@ import 'dart:io';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:trans_lark/widget/remind_dialog.dart';
|
||||
import 'package:trans_lark/widget/t_remind_dialog.dart';
|
||||
|
||||
class PermissionUtil {
|
||||
class TPermissionUtils {
|
||||
/// 检测是否有权限
|
||||
/// [permissionList] 权限申请列表
|
||||
static Future<bool> checkPermission(List<Permission> permissionList,
|
||||
@ -107,7 +107,7 @@ class PermissionUtil {
|
||||
{bool isPermanentlyDenied = false}) async {
|
||||
Get.dialog(
|
||||
barrierDismissible: false,
|
||||
RemindDialog(
|
||||
TRemindDialog(
|
||||
content: await _getDescription(permissionList),
|
||||
confirmText: isPermanentlyDenied ? 'Go open' : 'Confirm',
|
||||
confirmOnTap: () {
|
||||
@ -17,30 +17,30 @@ final _logger = Logger(
|
||||
),
|
||||
);
|
||||
|
||||
class LogPrint {
|
||||
class TPrint {
|
||||
static const String _tag = 'LogPrint';
|
||||
|
||||
LogPrint.t(dynamic msg, {String tag = _tag}) {
|
||||
TPrint.t(dynamic msg, {String tag = _tag}) {
|
||||
_logger.t('[$tag]: $msg');
|
||||
}
|
||||
|
||||
LogPrint.d(dynamic msg, {String tag = _tag}) {
|
||||
TPrint.d(dynamic msg, {String tag = _tag}) {
|
||||
_logger.d('[$tag]: $msg');
|
||||
}
|
||||
|
||||
LogPrint.i(dynamic msg, {String tag = _tag}) {
|
||||
TPrint.i(dynamic msg, {String tag = _tag}) {
|
||||
_logger.i('[$tag]: $msg');
|
||||
}
|
||||
|
||||
LogPrint.w(dynamic msg, {String tag = _tag}) {
|
||||
TPrint.w(dynamic msg, {String tag = _tag}) {
|
||||
_logger.w('[$tag]: $msg');
|
||||
}
|
||||
|
||||
LogPrint.e(dynamic msg, {String tag = _tag}) {
|
||||
TPrint.e(dynamic msg, {String tag = _tag}) {
|
||||
_logger.e('[$tag]: $msg');
|
||||
}
|
||||
|
||||
LogPrint.f(dynamic msg, {String tag = _tag}) {
|
||||
TPrint.f(dynamic msg, {String tag = _tag}) {
|
||||
_logger.f('[$tag]: $msg');
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
|
||||
class BaseAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
const BaseAppBar({
|
||||
class TBaseAppbarWidget extends StatelessWidget implements PreferredSizeWidget {
|
||||
const TBaseAppbarWidget({
|
||||
super.key,
|
||||
this.backgroundColor,
|
||||
this.backColor,
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
|
||||
class BaseEasyLoading {
|
||||
class TBaseEasyLoading {
|
||||
static void configLoading() {
|
||||
EasyLoading.instance
|
||||
// 当loading展示的时候,是否允许用户操作.
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BaseScrollbar extends StatelessWidget {
|
||||
const BaseScrollbar({super.key, required this.child, this.thumbColor});
|
||||
class TBaseScrollbarWidget extends StatelessWidget {
|
||||
const TBaseScrollbarWidget({super.key, required this.child, this.thumbColor});
|
||||
|
||||
final Widget child;
|
||||
final Color? thumbColor;
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DividerWidget extends StatelessWidget {
|
||||
const DividerWidget({super.key, this.height, this.color});
|
||||
class TDividerWidget extends StatelessWidget {
|
||||
const TDividerWidget({super.key, this.height, this.color});
|
||||
|
||||
final double? height;
|
||||
final Color? color;
|
||||
10
lib/widget/language_bar.dart → lib/widget/t_language_bar_widget.dart
Executable file → Normal file
10
lib/widget/language_bar.dart → lib/widget/t_language_bar_widget.dart
Executable file → Normal file
@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/widget/language_bottom_sheet.dart';
|
||||
import 'package:trans_lark/widget/t_language_bottom_sheet.dart';
|
||||
|
||||
class LanguageBar extends StatelessWidget {
|
||||
const LanguageBar({
|
||||
class TLanguageBarWidget extends StatelessWidget {
|
||||
const TLanguageBarWidget({
|
||||
super.key,
|
||||
this.isSelect = false,
|
||||
this.onTapFrom,
|
||||
@ -155,7 +155,7 @@ class LanguageBar extends StatelessWidget {
|
||||
TranslateManager().isSelectFromLanguage.value = true;
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
const LanguageBottomSheet(),
|
||||
const TLanguageBottomSheet(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ class LanguageBar extends StatelessWidget {
|
||||
TranslateManager().isSelectFromLanguage.value = false;
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
const LanguageBottomSheet(),
|
||||
const TLanguageBottomSheet(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,12 @@ import 'package:get/get_state_manager/get_state_manager.dart';
|
||||
import 'package:trans_lark/entity/language_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
import 'package:trans_lark/page/home/home_logic.dart';
|
||||
import 'package:trans_lark/widget/base_scrollbar.dart';
|
||||
import 'package:trans_lark/widget/language_bar.dart';
|
||||
import 'package:trans_lark/page/index/index_controller.dart';
|
||||
import 'package:trans_lark/widget/t_base_scrollbar_widget.dart';
|
||||
import 'package:trans_lark/widget/t_language_bar_widget.dart';
|
||||
|
||||
class LanguageBottomSheet extends StatelessWidget {
|
||||
const LanguageBottomSheet({super.key});
|
||||
class TLanguageBottomSheet extends StatelessWidget {
|
||||
const TLanguageBottomSheet({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -35,7 +35,7 @@ class LanguageBottomSheet extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
LanguageBar(
|
||||
TLanguageBarWidget(
|
||||
isSelect: true,
|
||||
onTapFrom: _onTapFrom,
|
||||
onTapTo: _onTapTo,
|
||||
@ -49,7 +49,7 @@ class LanguageBottomSheet extends StatelessWidget {
|
||||
|
||||
Widget _buildListView() {
|
||||
return Expanded(
|
||||
child: BaseScrollbar(
|
||||
child: TBaseScrollbarWidget(
|
||||
child: ListView.builder(
|
||||
itemCount: TranslateManager().languageList.length,
|
||||
itemBuilder: (context, index) {
|
||||
@ -136,8 +136,8 @@ class LanguageBottomSheet extends StatelessWidget {
|
||||
fn?.languageName = item.languageName;
|
||||
});
|
||||
}
|
||||
if (Get.isRegistered<HomeLogic>()) {
|
||||
HomeLogic.to.getDailyQuote();
|
||||
if (Get.isRegistered<IndexController>()) {
|
||||
IndexController.to.getDailyQuoteData();
|
||||
}
|
||||
}
|
||||
|
||||
4
lib/widget/language_result_bar.dart → lib/widget/t_language_result_bar_widget.dart
Executable file → Normal file
4
lib/widget/language_result_bar.dart → lib/widget/t_language_result_bar_widget.dart
Executable file → Normal file
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
|
||||
class LanguageResultBar extends StatelessWidget {
|
||||
const LanguageResultBar({
|
||||
class TLanguageResultBarWidget extends StatelessWidget {
|
||||
const TLanguageResultBarWidget({
|
||||
super.key,
|
||||
required this.fromLanguage,
|
||||
required this.toLanguage,
|
||||
4
lib/widget/language_scene_bar.dart → lib/widget/t_language_scene_bar_widget.dart
Executable file → Normal file
4
lib/widget/language_scene_bar.dart → lib/widget/t_language_scene_bar_widget.dart
Executable file → Normal file
@ -3,8 +3,8 @@ import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/language_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
|
||||
class LanguageSceneBar extends StatelessWidget {
|
||||
const LanguageSceneBar({
|
||||
class TLanguageSceneBarWidget extends StatelessWidget {
|
||||
const TLanguageSceneBarWidget({
|
||||
super.key,
|
||||
required this.fromLanguage,
|
||||
required this.toLanguage,
|
||||
@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/entity/language_entity.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/widget/base_scrollbar.dart';
|
||||
import 'package:trans_lark/widget/t_base_scrollbar_widget.dart';
|
||||
|
||||
class LanguageSceneBottomSheet extends StatelessWidget {
|
||||
const LanguageSceneBottomSheet({super.key, required this.languageScene, required this.selectedLanguage});
|
||||
class TLanguageSceneBottomSheet extends StatelessWidget {
|
||||
const TLanguageSceneBottomSheet({super.key, required this.languageScene, required this.selectedLanguage});
|
||||
|
||||
final List<LanguageEntity> languageScene;
|
||||
final Rx<LanguageEntity> selectedLanguage;
|
||||
@ -41,7 +41,7 @@ class LanguageSceneBottomSheet extends StatelessWidget {
|
||||
|
||||
Widget _buildListView() {
|
||||
return Expanded(
|
||||
child: BaseScrollbar(
|
||||
child: TBaseScrollbarWidget(
|
||||
child: ListView.builder(
|
||||
itemCount: languageScene.length,
|
||||
itemBuilder: (context, index) {
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trans_lark/widget/divider_widget.dart';
|
||||
import 'package:trans_lark/widget/t_divider_widget.dart';
|
||||
|
||||
class PhotoPickerBottomSheet extends StatelessWidget {
|
||||
const PhotoPickerBottomSheet({super.key, required this.funCamera, required this.funGallery});
|
||||
class TPhotoPickerBottomSheet extends StatelessWidget {
|
||||
const TPhotoPickerBottomSheet({super.key, required this.funCamera, required this.funGallery});
|
||||
|
||||
final Function() funCamera;
|
||||
final Function() funGallery;
|
||||
@ -24,7 +24,7 @@ class PhotoPickerBottomSheet extends StatelessWidget {
|
||||
Expanded(
|
||||
child: _buildItem('Open camera', funCamera),
|
||||
),
|
||||
const DividerWidget(),
|
||||
const TDividerWidget(),
|
||||
Expanded(
|
||||
child: _buildItem('Open gallery', funGallery),
|
||||
),
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class RemindDialog extends StatelessWidget {
|
||||
const RemindDialog({
|
||||
class TRemindDialog extends StatelessWidget {
|
||||
const TRemindDialog({
|
||||
super.key,
|
||||
this.title,
|
||||
this.content,
|
||||
@ -4,8 +4,8 @@ import 'package:get/get.dart';
|
||||
import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
|
||||
class SpeakDialog extends StatelessWidget {
|
||||
const SpeakDialog({
|
||||
class TSpeakDialog extends StatelessWidget {
|
||||
const TSpeakDialog({
|
||||
super.key,
|
||||
required this.isListening,
|
||||
required this.onTap,
|
||||
8
lib/widget/translate_text_full_screen_page.dart → lib/widget/t_translate_text_full_screen_page.dart
Executable file → Normal file
8
lib/widget/translate_text_full_screen_page.dart → lib/widget/t_translate_text_full_screen_page.dart
Executable file → Normal file
@ -6,16 +6,16 @@ import 'package:trans_lark/generated/assets.dart';
|
||||
import 'package:trans_lark/global/flutter_tts_manager.dart';
|
||||
import 'package:trans_lark/global/translate_manager.dart';
|
||||
|
||||
class TranslateTextFullScreenPage extends StatefulWidget {
|
||||
const TranslateTextFullScreenPage({super.key});
|
||||
class TTranslateTextFullScreenPage extends StatefulWidget {
|
||||
const TTranslateTextFullScreenPage({super.key});
|
||||
|
||||
@override
|
||||
State<TranslateTextFullScreenPage> createState() =>
|
||||
State<TTranslateTextFullScreenPage> createState() =>
|
||||
_TranslateTextFullScreenPageState();
|
||||
}
|
||||
|
||||
class _TranslateTextFullScreenPageState
|
||||
extends State<TranslateTextFullScreenPage> {
|
||||
extends State<TTranslateTextFullScreenPage> {
|
||||
String showData = "";
|
||||
|
||||
@override
|
||||
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
||||
/// 四种视图状态
|
||||
enum ViewState { normal, error, loading, empty }
|
||||
|
||||
class ViewStateWidget extends StatelessWidget {
|
||||
const ViewStateWidget({
|
||||
class TViewStateWidget extends StatelessWidget {
|
||||
const TViewStateWidget({
|
||||
super.key,
|
||||
required this.viewState,
|
||||
required this.child,
|
||||
Loading…
Reference in New Issue
Block a user