add android translate

This commit is contained in:
csf 2022-03-23 15:28:21 +08:00
parent 1daaa3a4cd
commit cc75ffbeeb
6 changed files with 82 additions and 82 deletions

View File

@ -9,7 +9,7 @@ import 'package:path/path.dart' as Path;
import 'model.dart'; import 'model.dart';
enum SortBy { name, type, date, size } enum SortBy { Name, Type, Modified, Size }
// enum FileType { // enum FileType {
// Dir = 0, // Dir = 0,
@ -42,7 +42,7 @@ class FileModel extends ChangeNotifier {
JobState get jobState => _jobProgress.state; JobState get jobState => _jobProgress.state;
SortBy _sortStyle = SortBy.name; SortBy _sortStyle = SortBy.Name;
SortBy get sortStyle => _sortStyle; SortBy get sortStyle => _sortStyle;
@ -272,19 +272,19 @@ class FileModel extends ChangeNotifier {
var content = ""; var content = "";
late final List<Entry> entries; late final List<Entry> entries;
if (item.isFile) { if (item.isFile) {
title = "是否永久删除文件"; title = translate("Are you sure you want to delete this file?");
content = "${item.name}"; content = "${item.name}";
entries = [item]; entries = [item];
} else if (item.isDirectory) { } else if (item.isDirectory) {
title = "这不是一个空文件夹"; title = translate("Not a Empty Directory");
showLoading("正在读取..."); showLoading(translate("Waiting"));
final fd = await _fileFetcher.fetchDirectoryRecursive( final fd = await _fileFetcher.fetchDirectoryRecursive(
_jobId, item.path, items.isLocal!, true); _jobId, item.path, items.isLocal!, true);
fd.format(isWindows); fd.format(isWindows);
EasyLoading.dismiss(); EasyLoading.dismiss();
// //
if (fd.entries.isEmpty) { if (fd.entries.isEmpty) {
final confirm = await showRemoveDialog("是否删除空文件夹", item.name, false); final confirm = await showRemoveDialog(translate("Are you sure you want to delete this empty directory?"), item.name, false);
if (confirm == true) { if (confirm == true) {
sendRemoveEmptyDir(item.path, 0, items.isLocal!); sendRemoveEmptyDir(item.path, 0, items.isLocal!);
} }
@ -296,9 +296,9 @@ class FileModel extends ChangeNotifier {
} }
for (var i = 0; i < entries.length; i++) { for (var i = 0; i < entries.length; i++) {
final dirShow = item.isDirectory ? "是否删除文件夹下的文件?\n" : ""; final dirShow = item.isDirectory ? "${translate("Are you sure you want to delete the file of this directory?")}\n" : "";
final count = final count =
entries.length > 1 ? "${i + 1}/${entries.length}" : ""; entries.length > 1 ? "${i + 1}/${entries.length}" : "";
content = dirShow + "$count \n${entries[i].path}"; content = dirShow + "$count \n${entries[i].path}";
final confirm = final confirm =
await showRemoveDialog(title, content, item.isDirectory); await showRemoveDialog(title, content, item.isDirectory);
@ -348,7 +348,7 @@ class FileModel extends ChangeNotifier {
children: [ children: [
Text(content), Text(content),
SizedBox(height: 5), SizedBox(height: 5),
Text("此操作不可逆!", Text(translate("This is irreversible!"),
style: TextStyle(fontWeight: FontWeight.bold)), style: TextStyle(fontWeight: FontWeight.bold)),
showCheckbox showCheckbox
? CheckboxListTile( ? CheckboxListTile(
@ -356,7 +356,7 @@ class FileModel extends ChangeNotifier {
dense: true, dense: true,
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
title: Text( title: Text(
"应用于文件夹下所有文件", translate("Do this for all conflicts"),
), ),
value: removeCheckboxRemember, value: removeCheckboxRemember,
onChanged: (v) { onChanged: (v) {
@ -369,12 +369,12 @@ class FileModel extends ChangeNotifier {
actions: [ actions: [
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () => close(true), onPressed: () => close(false),
child: Text("Yes")), child: Text(translate("Cancel"))),
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () => close(false), onPressed: () => close(true),
child: Text("No")) child: Text(translate("OK"))),
])); ]));
} }
@ -675,7 +675,7 @@ class DirectoryOption {
// code from file_manager pkg after edit // code from file_manager pkg after edit
List<Entry> _sortList(List<Entry> list, SortBy sortType) { List<Entry> _sortList(List<Entry> list, SortBy sortType) {
if (sortType == SortBy.name) { if (sortType == SortBy.Name) {
// making list of only folders. // making list of only folders.
final dirs = list.where((element) => element.isDirectory).toList(); final dirs = list.where((element) => element.isDirectory).toList();
// sorting folder list by name. // sorting folder list by name.
@ -688,7 +688,7 @@ List<Entry> _sortList(List<Entry> list, SortBy sortType) {
// first folders will go to list (if available) then files will go to list. // first folders will go to list (if available) then files will go to list.
return [...dirs, ...files]; return [...dirs, ...files];
} else if (sortType == SortBy.date) { } else if (sortType == SortBy.Modified) {
// making the list of Path & DateTime // making the list of Path & DateTime
List<_PathStat> _pathStat = []; List<_PathStat> _pathStat = [];
for (Entry e in list) { for (Entry e in list) {
@ -703,7 +703,7 @@ List<Entry> _sortList(List<Entry> list, SortBy sortType) {
.indexWhere((element) => element.path == a.name) .indexWhere((element) => element.path == a.name)
.compareTo(_pathStat.indexWhere((element) => element.path == b.name))); .compareTo(_pathStat.indexWhere((element) => element.path == b.name)));
return list; return list;
} else if (sortType == SortBy.type) { } else if (sortType == SortBy.Type) {
// making list of only folders. // making list of only folders.
final dirs = list.where((element) => element.isDirectory).toList(); final dirs = list.where((element) => element.isDirectory).toList();
@ -720,7 +720,7 @@ List<Entry> _sortList(List<Entry> list, SortBy sortType) {
.last .last
.compareTo(b.name.toLowerCase().split('.').last)); .compareTo(b.name.toLowerCase().split('.').last));
return [...dirs, ...files]; return [...dirs, ...files];
} else if (sortType == SortBy.size) { } else if (sortType == SortBy.Size) {
// create list of path and size // create list of path and size
Map<String, int> _sizeMap = {}; Map<String, int> _sizeMap = {};
for (Entry e in list) { for (Entry e in list) {

View File

@ -80,11 +80,11 @@ class ServerModel with ChangeNotifier {
toggleService() async { toggleService() async {
if(_isStart){ if(_isStart){
final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog( final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog(
title: Text("是否关闭"), title: Text(translate("Warning")),
content: Text("关闭录屏服务将自动关闭所有已连接的控制"), content: Text(translate("android_stop_service_tip")),
actions: [ actions: [
TextButton(onPressed: ()=>close(), child: Text("Cancel")), TextButton(onPressed: ()=>close(), child: Text(translate("Cancel"))),
ElevatedButton(onPressed: ()=>close(true), child: Text("Ok")), ElevatedButton(onPressed: ()=>close(true), child: Text(translate("OK"))),
], ],
)); ));
if(res == true){ if(res == true){
@ -92,11 +92,11 @@ class ServerModel with ChangeNotifier {
} }
}else{ }else{
final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog( final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog(
title: Text("是否开启录屏服务"), title: Text(translate("Warning")),
content: Text("将自动开启监听服务"), content: Text(translate("android_service_will_start_tip")),
actions: [ actions: [
TextButton(onPressed: ()=>close(), child: Text("Cancel")), TextButton(onPressed: ()=>close(), child: Text(translate("Cancel"))),
ElevatedButton(onPressed: ()=>close(true), child: Text("Ok")), ElevatedButton(onPressed: ()=>close(true), child: Text(translate("OK"))),
], ],
)); ));
if(res == true){ if(res == true){
@ -169,7 +169,6 @@ class ServerModel with ChangeNotifier {
switch (name) { switch (name) {
case "media": case "media":
_mediaOk = value; _mediaOk = value;
debugPrint("value $value,_isStart:$_isStart");
if(value && !_isStart){ if(value && !_isStart){
startService(); startService();
} }
@ -191,13 +190,11 @@ class ServerModel with ChangeNotifier {
updateClientState() { updateClientState() {
var res = FFI.getByName("clients_state"); var res = FFI.getByName("clients_state");
debugPrint("getByName clients_state string:$res");
try { try {
final List clientsJson = jsonDecode(res); final List clientsJson = jsonDecode(res);
_clients = clientsJson _clients = clientsJson
.map((clientJson) => Client.fromJson(jsonDecode(res))) .map((clientJson) => Client.fromJson(jsonDecode(res)))
.toList(); .toList();
debugPrint("updateClientState:${_clients.toString()}");
notifyListeners(); notifyListeners();
} catch (e) {} } catch (e) {}
} }
@ -217,7 +214,7 @@ class ServerModel with ChangeNotifier {
Text(translate("Do you accept?")), Text(translate("Do you accept?")),
SizedBox(height: 20), SizedBox(height: 20),
clientInfo(client), clientInfo(client),
Text(translate("It will be control your device!")), Text(translate("android_new_connection_tip")),
], ],
), ),
actions: [ actions: [
@ -321,27 +318,36 @@ showInputWarnAlert() async {
await showDialog<bool>( await showDialog<bool>(
context: globalKey.currentContext!, context: globalKey.currentContext!,
builder: (alertContext) { builder: (alertContext) {
// TODO t
DialogManager.register(alertContext); DialogManager.register(alertContext);
return AlertDialog( return AlertDialog(
title: Text("获取输入权限引导"), title: Text("获取输入权限引导"),
content: Text.rich(TextSpan(style: TextStyle(), children: [ // content: Text.rich(TextSpan(style: TextStyle(), children: [
TextSpan(text: "请在接下来的系统设置页\n进入"), // // [] : [Installed Services]
TextSpan(text: " [服务] ", style: TextStyle(color: MyTheme.accent)), // // [Installed Services][RustDesk Input]
TextSpan(text: "配置页面\n"), // TextSpan(text: "请在接下来的系统设置页\n进入"),
TextSpan( // TextSpan(text: " [服务] ", style: TextStyle(color: MyTheme.accent)),
text: " [RustDesk Input] ", // TextSpan(text: "配置页面\n"),
style: TextStyle(color: MyTheme.accent)), // TextSpan(
TextSpan(text: "服务开启") // text: " [RustDesk Input] ",
])), // style: TextStyle(color: MyTheme.accent)),
// TextSpan(text: "服务开启")
// ])),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(translate(translate("android_input_permission_tip1"))),
SizedBox(height: 10),
Text(translate(translate("android_input_permission_tip2"))),
],
),
actions: [ actions: [
TextButton( TextButton(
child: Text(translate("Do nothing")), child: Text(translate("Cancel")),
onPressed: () { onPressed: () {
DialogManager.reset(); DialogManager.reset();
}), }),
ElevatedButton( ElevatedButton(
child: Text(translate("Go System Setting")), child: Text(translate("Open System Setting")),
onPressed: () { onPressed: () {
FFI.serverModel.initInput(); FFI.serverModel.initInput();
DialogManager.reset(); DialogManager.reset();

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/chat_model.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../models/model.dart';
import 'home_page.dart'; import 'home_page.dart';
OverlayEntry? iconOverlayEntry; OverlayEntry? iconOverlayEntry;
@ -13,7 +14,7 @@ ChatPage chatPage = ChatPage();
class ChatPage extends StatelessWidget implements PageShape { class ChatPage extends StatelessWidget implements PageShape {
@override @override
final title = "Chat"; final title = translate("Chat");
@override @override
final icon = Icon(Icons.chat); final icon = Icon(Icons.chat);
@ -209,7 +210,7 @@ class _ChatWindowOverlayState extends State<ChatWindowOverlay> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 15),child: Text( Padding(padding: EdgeInsets.symmetric(horizontal: 15),child: Text(
"Chat", translate("Chat"),
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontFamily: 'WorkSans', fontFamily: 'WorkSans',

View File

@ -139,12 +139,12 @@ class _FileManagerPageState extends State<FileManagerPage> {
itemBuilder: (context) { itemBuilder: (context) {
return [ return [
PopupMenuItem( PopupMenuItem(
child: Text("删除"), child: Text(translate("Delete")),
value: "delete", value: "delete",
), ),
PopupMenuItem( PopupMenuItem(
child: Text("详细信息"), child: Text(translate("Properties")),
value: "delete", value: "properties",
enabled: false, enabled: false,
) )
]; ];
@ -255,14 +255,13 @@ class _FileManagerPageState extends State<FileManagerPage> {
)), )),
Row( Row(
children: [ children: [
// IconButton(onPressed: () {}, icon: Icon(Icons.sort)),
PopupMenuButton<SortBy>( PopupMenuButton<SortBy>(
icon: Icon(Icons.sort), icon: Icon(Icons.sort),
itemBuilder: (context) { itemBuilder: (context) {
return SortBy.values return SortBy.values
.map((e) => PopupMenuItem( .map((e) => PopupMenuItem(
child: Text( child: Text(
e.toString().split(".").last.toUpperCase()), translate(e.toString().split(".").last)),
value: e, value: e,
)) ))
.toList(); .toList();
@ -277,7 +276,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
children: [ children: [
Icon(Icons.refresh), Icon(Icons.refresh),
SizedBox(width: 5), SizedBox(width: 5),
Text("刷新") Text(translate("Refresh File"))
], ],
), ),
value: "refresh", value: "refresh",
@ -287,7 +286,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
children: [ children: [
Icon(Icons.check), Icon(Icons.check),
SizedBox(width: 5), SizedBox(width: 5),
Text("多选") Text(translate("CheckBox"))
], ],
), ),
value: "select", value: "select",
@ -309,7 +308,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
? Icons.check_box_outlined ? Icons.check_box_outlined
: Icons.check_box_outline_blank), : Icons.check_box_outline_blank),
SizedBox(width: 5), SizedBox(width: 5),
Text(translate("Toggle Hidden")) Text(translate("Show Hidden Files"))
], ],
), ),
value: "hidden", value: "hidden",
@ -340,6 +339,10 @@ class _FileManagerPageState extends State<FileManagerPage> {
), ),
actions: [ actions: [
TextButton( TextButton(
style: flatButtonStyle,
onPressed: () => close(false),
child: Text(translate("Cancel"))),
ElevatedButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
if (name.value.text.isNotEmpty) { if (name.value.text.isNotEmpty) {
@ -350,11 +353,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
close(); close();
} }
}, },
child: Text(translate("OK"))), child: Text(translate("OK")))
TextButton(
style: flatButtonStyle,
onPressed: () => close(false),
child: Text(translate("Cancel")))
])); ]));
} else if (v == "hidden") { } else if (v == "hidden") {
model.toggleShowHidden(); model.toggleShowHidden();
@ -381,8 +380,9 @@ class _FileManagerPageState extends State<FileManagerPage> {
children: [ children: [
Padding( Padding(
padding: EdgeInsets.all(2), padding: EdgeInsets.all(2),
// TODO
child: Text( child: Text(
"总计: ${model.currentDir.entries.length}个项目", "${translate("Count")}: ${model.currentDir.entries.length}${translate("items")}",
style: TextStyle(color: MyTheme.darkGray), style: TextStyle(color: MyTheme.darkGray),
), ),
) )
@ -394,17 +394,17 @@ class _FileManagerPageState extends State<FileManagerPage> {
Widget? bottomSheet() { Widget? bottomSheet() {
final state = model.jobState; final state = model.jobState;
final isOtherPage = _selectedItems.isOtherPage(model.isLocal); final isOtherPage = _selectedItems.isOtherPage(model.isLocal);
final selectedItemsLength = "${_selectedItems.length} 个项目"; final selectedItemsLength = "${_selectedItems.length} ${translate("items")}"; // TODO t
final local = _selectedItems.isLocal == null final local = _selectedItems.isLocal == null
? "" ? ""
: " [${_selectedItems.isLocal! ? '本地' : '远程'}]"; : " [${_selectedItems.isLocal! ? translate("Local") : translate("Remote")}]";
if (model.selectMode) { if (model.selectMode) {
if (_selectedItems.length == 0 || !isOtherPage) { if (_selectedItems.length == 0 || !isOtherPage) {
// //
return BottomSheetBody( return BottomSheetBody(
leading: Icon(Icons.check), leading: Icon(Icons.check),
title: "已选择", title: translate("Selected"),
text: selectedItemsLength + local, text: selectedItemsLength + local,
onCanceled: () => model.toggleSelectMode(), onCanceled: () => model.toggleSelectMode(),
actions: [ actions: [
@ -421,7 +421,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
// //
return BottomSheetBody( return BottomSheetBody(
leading: Icon(Icons.input), leading: Icon(Icons.input),
title: "粘贴到这里?", title: translate("Paste here?"),
text: selectedItemsLength + local, text: selectedItemsLength + local,
onCanceled: () => model.toggleSelectMode(), onCanceled: () => model.toggleSelectMode(),
actions: [ actions: [
@ -440,21 +440,21 @@ class _FileManagerPageState extends State<FileManagerPage> {
case JobState.inProgress: case JobState.inProgress:
return BottomSheetBody( return BottomSheetBody(
leading: CircularProgressIndicator(), leading: CircularProgressIndicator(),
title: "正在发送文件...", title: translate("Waiting"),
text: "速度: ${readableFileSize(model.jobProgress.speed)}/s", text: "${translate("Speed")}: ${readableFileSize(model.jobProgress.speed)}/s",
onCanceled: null, onCanceled: null,
); );
case JobState.done: case JobState.done:
return BottomSheetBody( return BottomSheetBody(
leading: Icon(Icons.check), leading: Icon(Icons.check),
title: "操作成功!", title: "${translate("Successful")}!",
text: "", text: "",
onCanceled: () => model.jobReset(), onCanceled: () => model.jobReset(),
); );
case JobState.error: case JobState.error:
return BottomSheetBody( return BottomSheetBody(
leading: Icon(Icons.error), leading: Icon(Icons.error),
title: "错误!", title: "${translate("Error")}!",
text: "", text: "",
onCanceled: () => model.jobReset(), onCanceled: () => model.jobReset(),
); );

View File

@ -1,4 +1,3 @@
import 'package:device_info/device_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/models/model.dart'; import 'package:flutter_hbb/models/model.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -11,7 +10,7 @@ import '../models/model.dart';
class ServerPage extends StatelessWidget implements PageShape { class ServerPage extends StatelessWidget implements PageShape {
@override @override
final title = "Share Screen"; final title = translate("Share Screen");
@override @override
final icon = Icon(Icons.mobile_screen_share); final icon = Icon(Icons.mobile_screen_share);
@ -27,7 +26,7 @@ class ServerPage extends StatelessWidget implements PageShape {
enabled: false, enabled: false,
), ),
PopupMenuItem( PopupMenuItem(
child: Text("Set your own password"), child: Text(translate("Set your own password")),
value: "changePW", value: "changePW",
enabled: false, enabled: false,
) )
@ -127,7 +126,7 @@ class _ServerInfoState extends State<ServerInfo> {
color: Colors.redAccent, size: 24), color: Colors.redAccent, size: 24),
SizedBox(width: 10), SizedBox(width: 10),
Text( Text(
"屏幕共享尚未开启", translate("Service is not running"),
style: TextStyle( style: TextStyle(
fontFamily: 'WorkSans', fontFamily: 'WorkSans',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -140,7 +139,7 @@ class _ServerInfoState extends State<ServerInfo> {
SizedBox(height: 5), SizedBox(height: 5),
Center( Center(
child: Text( child: Text(
"点击[启动服务]或打开Screen Capture 开启共享手机屏幕", translate("android_start_service_tip"),
style: TextStyle(fontSize: 12, color: MyTheme.darkGray), style: TextStyle(fontSize: 12, color: MyTheme.darkGray),
)) ))
], ],
@ -170,19 +169,19 @@ class _PermissionCheckerState extends State<PermissionChecker> {
serverModel.toggleInput), serverModel.toggleInput),
PermissionRow(translate("File Transfer"), serverModel.fileOk, PermissionRow(translate("File Transfer"), serverModel.fileOk,
serverModel.toggleFile), serverModel.toggleFile),
hasAudioPermission?PermissionRow(translate("Audio Capture"), serverModel.inputOk, hasAudioPermission?PermissionRow(translate("Audio Capture"), serverModel.audioOk,
serverModel.toggleAudio):Text("* 当前安卓版本不支持音频捕获",style: TextStyle(color: MyTheme.darkGray),), serverModel.toggleAudio):Text("* ${translate("android_version_audio_tip")}",style: TextStyle(color: MyTheme.darkGray),),
SizedBox(height: 8), SizedBox(height: 8),
serverModel.mediaOk serverModel.mediaOk
? ElevatedButton.icon( ? ElevatedButton.icon(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red)), backgroundColor: MaterialStateProperty.all(Colors.red)),
icon: Icon(Icons.stop), icon: Icon(Icons.stop),
onPressed: serverModel.stopService, onPressed: serverModel.toggleService,
label: Text(translate("Stop service"))) label: Text(translate("Stop service")))
: ElevatedButton.icon( : ElevatedButton.icon(
icon: Icon(Icons.play_arrow), icon: Icon(Icons.play_arrow),
onPressed: serverModel.startService, onPressed: serverModel.toggleService,
label: Text(translate("Start Service"))), label: Text(translate("Start Service"))),
], ],
)); ));
@ -323,12 +322,6 @@ Widget clientInfo(Client client) {
]) ])
], ],
), ),
// !client.isFileTransfer?Row(
// children: [
// client.audio?Icon(Icons.volume_up):SizedBox.shrink(),
// client.keyboard?Icon(Icons.mouse):SizedBox.shrink(),
// ],
// ):SizedBox.shrink()
]); ]);
} }

View File

@ -7,7 +7,7 @@ import 'home_page.dart';
class SettingsPage extends StatelessWidget implements PageShape { class SettingsPage extends StatelessWidget implements PageShape {
@override @override
final title = "Settings"; final title = translate("Settings");
@override @override
final icon = Icon(Icons.settings); final icon = Icon(Icons.settings);