This commit is contained in:
rustdesk
2023-11-06 20:12:01 +08:00
parent 679a026e72
commit d7e8d4d5c3
64 changed files with 1193 additions and 1082 deletions

View File

@@ -972,7 +972,7 @@ void showRestartRemoteDevice(PeerInfo pi, String id, SessionID sessionId,
title: Row(children: [
Icon(Icons.warning_rounded, color: Colors.redAccent, size: 28),
Flexible(
child: Text(translate("Restart Remote Device"))
child: Text(translate("Restart remote device"))
.paddingOnly(left: 10)),
]),
content: Text(

View File

@@ -495,7 +495,7 @@ abstract class BasePeerCard extends StatelessWidget {
return _connectCommonAction(
context,
id,
translate('Transfer File'),
translate('Transfer file'),
isFileTransfer: true,
);
}
@@ -505,7 +505,7 @@ abstract class BasePeerCard extends StatelessWidget {
return _connectCommonAction(
context,
id,
translate('TCP Tunneling'),
translate('TCP tunneling'),
isTcpTunneling: true,
);
}
@@ -568,7 +568,7 @@ abstract class BasePeerCard extends StatelessWidget {
MenuEntryBase<String> _createShortCutAction(String id) {
return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Create Desktop Shortcut'),
translate('Create desktop shortcut'),
style: style,
),
proc: () {
@@ -818,7 +818,7 @@ abstract class BasePeerCard extends StatelessWidget {
MenuEntryBase<String> _addToAb(Peer peer) {
return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Add to Address Book'),
translate('Add to address book'),
style: style,
),
proc: () {

View File

@@ -456,7 +456,7 @@ class _PeerTabPageState extends State<PeerTabPage>
});
},
child: Tooltip(
message: translate('Add to Address Book'),
message: translate('Add to address book'),
child: Icon(model.icons[PeerTabIndex.ab.index])),
).marginOnly(left: isMobile ? 11 : 6),
);

View File

@@ -270,7 +270,7 @@ List<Widget> ServerConfigImportExportWidgets(
return [
Tooltip(
message: translate('Import Server Config'),
message: translate('Import server config'),
child: IconButton(
icon: Icon(Icons.paste, color: Colors.grey), onPressed: import),
),

View File

@@ -133,7 +133,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
if (isDesktop) {
v.add(
TTextMenu(
child: Text(translate('Transfer File')),
child: Text(translate('Transfer file')),
onPressed: () => connect(context, id, isFileTransfer: true)),
);
}
@@ -141,7 +141,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
if (isDesktop) {
v.add(
TTextMenu(
child: Text(translate('TCP Tunneling')),
child: Text(translate('TCP tunneling')),
onPressed: () => connect(context, id, isTcpTunneling: true)),
);
}
@@ -176,7 +176,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
pi.platform == kPeerPlatformMacOS)) {
v.add(
TTextMenu(
child: Text(translate('Restart Remote Device')),
child: Text(translate('Restart remote device')),
onPressed: () =>
showRestartRemoteDevice(pi, id, sessionId, ffi.dialogManager)),
);

View File

@@ -50,6 +50,7 @@ class _ConnectionPageState extends State<ConnectionPage>
return list.sublist(0, n);
}
}
bool isPeersLoading = false;
bool isPeersLoaded = false;
@@ -81,7 +82,7 @@ class _ConnectionPageState extends State<ConnectionPage>
if (Get.isRegistered<IDTextEditingController>()) {
Get.delete<IDTextEditingController>();
}
if (Get.isRegistered<TextEditingController>()){
if (Get.isRegistered<TextEditingController>()) {
Get.delete<TextEditingController>();
}
super.dispose();
@@ -157,9 +158,9 @@ class _ConnectionPageState extends State<ConnectionPage>
await Future.delayed(Duration(milliseconds: 100));
peers = await getAllPeers();
setState(() {
isPeersLoading = false;
isPeersLoaded = true;
});
isPeersLoading = false;
isPeersLoaded = true;
});
}
/// UI for the remote ID TextField.
@@ -177,148 +178,173 @@ class _ConnectionPageState extends State<ConnectionPage>
Row(
children: [
Expanded(
child: AutoSizeText(
translate('Control Remote Desktop'),
maxLines: 1,
style: Theme.of(context)
.textTheme
.titleLarge
?.merge(TextStyle(height: 1)),
),
),
child: Row(
children: [
AutoSizeText(
translate('Control Remote Desktop'),
maxLines: 1,
style: Theme.of(context)
.textTheme
.titleLarge
?.merge(TextStyle(height: 1)),
).marginOnly(right: 4),
Tooltip(
waitDuration: Duration(milliseconds: 0),
message: translate("id_input_tip"),
child: Icon(
Icons.help_outline_outlined,
size: 16,
color: Theme.of(context)
.textTheme
.titleLarge
?.color
?.withOpacity(0.5),
),
),
],
)),
],
).marginOnly(bottom: 15),
Row(
children: [
Expanded(
child:
Autocomplete<Peer>(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<Peer>.empty();
}
else if (peers.isEmpty && !isPeersLoaded) {
Peer emptyPeer = Peer(
id: '',
username: '',
hostname: '',
alias: '',
platform: '',
tags: [],
hash: '',
forceAlwaysRelay: false,
rdpPort: '',
rdpUsername: '',
loginName: '',
child: Autocomplete<Peer>(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<Peer>.empty();
} else if (peers.isEmpty && !isPeersLoaded) {
Peer emptyPeer = Peer(
id: '',
username: '',
hostname: '',
alias: '',
platform: '',
tags: [],
hash: '',
forceAlwaysRelay: false,
rdpPort: '',
rdpUsername: '',
loginName: '',
);
return [emptyPeer];
} else {
String textWithoutSpaces =
textEditingValue.text.replaceAll(" ", "");
if (int.tryParse(textWithoutSpaces) != null) {
textEditingValue = TextEditingValue(
text: textWithoutSpaces,
selection: textEditingValue.selection,
);
return [emptyPeer];
}
else {
String textWithoutSpaces = textEditingValue.text.replaceAll(" ", "");
if (int.tryParse(textWithoutSpaces) != null) {
textEditingValue = TextEditingValue(
text: textWithoutSpaces,
selection: textEditingValue.selection,
);
}
String textToFind = textEditingValue.text.toLowerCase();
String textToFind = textEditingValue.text.toLowerCase();
return peers.where((peer) =>
peer.id.toLowerCase().contains(textToFind) ||
peer.username.toLowerCase().contains(textToFind) ||
peer.hostname.toLowerCase().contains(textToFind) ||
peer.alias.toLowerCase().contains(textToFind))
.toList();
return peers
.where((peer) =>
peer.id.toLowerCase().contains(textToFind) ||
peer.username
.toLowerCase()
.contains(textToFind) ||
peer.hostname
.toLowerCase()
.contains(textToFind) ||
peer.alias.toLowerCase().contains(textToFind))
.toList();
}
},
fieldViewBuilder: (
BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted,
) {
fieldTextEditingController.text = _idController.text;
Get.put<TextEditingController>(fieldTextEditingController);
fieldFocusNode.addListener(() async {
_idInputFocused.value = fieldFocusNode.hasFocus;
if (fieldFocusNode.hasFocus && !isPeersLoading) {
_fetchPeers();
}
},
});
final textLength =
fieldTextEditingController.value.text.length;
// select all to facilitate removing text, just following the behavior of address input of chrome
fieldTextEditingController.selection =
TextSelection(baseOffset: 0, extentOffset: textLength);
return Obx(() => TextField(
autocorrect: false,
enableSuggestions: false,
keyboardType: TextInputType.visiblePassword,
focusNode: fieldFocusNode,
style: const TextStyle(
fontFamily: 'WorkSans',
fontSize: 22,
height: 1.4,
),
maxLines: 1,
cursorColor:
Theme.of(context).textTheme.titleLarge?.color,
decoration: InputDecoration(
filled: false,
counterText: '',
hintText: _idInputFocused.value
? null
: translate('Enter Remote ID'),
contentPadding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 13)),
controller: fieldTextEditingController,
inputFormatters: [IDTextInputFormatter()],
onChanged: (v) {
_idController.id = v;
},
));
},
onSelected: (option) {
setState(() {
_idController.id = option.id;
FocusScope.of(context).unfocus();
});
},
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<Peer> onSelected,
Iterable<Peer> options) {
double maxHeight = options.length * 50;
maxHeight = maxHeight > 200 ? 200 : maxHeight;
fieldViewBuilder: (BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode ,
VoidCallback onFieldSubmitted,
) {
fieldTextEditingController.text = _idController.text;
Get.put<TextEditingController>(fieldTextEditingController);
fieldFocusNode.addListener(() async {
_idInputFocused.value = fieldFocusNode.hasFocus;
if (fieldFocusNode.hasFocus && !isPeersLoading){
_fetchPeers();
}
});
final textLength = fieldTextEditingController.value.text.length;
// select all to facilitate removing text, just following the behavior of address input of chrome
fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength);
return Obx(() =>
TextField(
maxLength: 90,
autocorrect: false,
enableSuggestions: false,
keyboardType: TextInputType.visiblePassword,
focusNode: fieldFocusNode,
style: const TextStyle(
fontFamily: 'WorkSans',
fontSize: 22,
height: 1.4,
),
maxLines: 1,
cursorColor: Theme.of(context).textTheme.titleLarge?.color,
decoration: InputDecoration(
filled: false,
counterText: '',
hintText: _idInputFocused.value
? null
: translate('Enter Remote ID'),
contentPadding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 13)),
controller: fieldTextEditingController,
inputFormatters: [IDTextInputFormatter()],
onChanged: (v) {
_idController.id = v;
},
));
},
onSelected: (option) {
setState(() {
_idController.id = option.id;
FocusScope.of(context).unfocus();
});
},
optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<Peer> onSelected, Iterable<Peer> options) {
double maxHeight = options.length * 50;
maxHeight = maxHeight > 200 ? 200 : maxHeight;
return Align(
alignment: Alignment.topLeft,
child: ClipRRect(
return Align(
alignment: Alignment.topLeft,
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Material(
elevation: 4,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: maxHeight,
maxWidth: 319,
),
child: peers.isEmpty && isPeersLoading
? Container(
height: 80,
child: Center(
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
)
: Padding(
padding: const EdgeInsets.only(top: 5),
child: ListView(
children: options.map((peer) => AutocompletePeerTile(onSelect: () => onSelected(peer), peer: peer)).toList(),
elevation: 4,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: maxHeight,
maxWidth: 319,
),
child: peers.isEmpty && isPeersLoading
? Container(
height: 80,
child: Center(
child: CircularProgressIndicator(
strokeWidth: 2,
),
))
: Padding(
padding: const EdgeInsets.only(top: 5),
child: ListView(
children: options
.map((peer) => AutocompletePeerTile(
onSelect: () =>
onSelected(peer),
peer: peer))
.toList(),
),
),
),
),
)),
);
},
)
),
)),
);
},
)),
],
),
Padding(
@@ -329,7 +355,7 @@ class _ConnectionPageState extends State<ConnectionPage>
Button(
isOutline: true,
onTap: () => onConnect(isFileTransfer: true),
text: "Transfer File",
text: "Transfer file",
),
const SizedBox(
width: 17,
@@ -382,7 +408,7 @@ class _ConnectionPageState extends State<ConnectionPage>
onTap: () async {
await start_service(true);
},
child: Text(translate("Start Service"),
child: Text(translate("Start service"),
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: em)))

View File

@@ -632,22 +632,22 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
}).marginOnly(left: _kContentHMargin),
Column(
children: [
_OptionCheckBox(context, 'Enable Keyboard/Mouse', 'enable-keyboard',
_OptionCheckBox(context, 'Enable keyboard/mouse', 'enable-keyboard',
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable Clipboard', 'enable-clipboard',
_OptionCheckBox(context, 'Enable clipboard', 'enable-clipboard',
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(
context, 'Enable File Transfer', 'enable-file-transfer',
context, 'Enable file transfer', 'enable-file-transfer',
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable Audio', 'enable-audio',
_OptionCheckBox(context, 'Enable audio', 'enable-audio',
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable TCP Tunneling', 'enable-tunnel',
_OptionCheckBox(context, 'Enable TCP tunneling', 'enable-tunnel',
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(
context, 'Enable Remote Restart', 'enable-remote-restart',
context, 'Enable remote restart', 'enable-remote-restart',
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(
context, 'Enable Recording Session', 'enable-record-session',
context, 'Enable recording session', 'enable-record-session',
enabled: enabled, fakeValue: fakeValue),
if (Platform.isWindows)
_OptionCheckBox(
@@ -773,7 +773,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
bool enabled = !locked;
return _Card(title: 'Security', children: [
shareRdp(context, enabled),
_OptionCheckBox(context, 'Deny LAN Discovery', 'enable-lan-discovery',
_OptionCheckBox(context, 'Deny LAN discovery', 'enable-lan-discovery',
reverse: true, enabled: enabled),
...directIp(context),
whitelist(),
@@ -813,7 +813,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
update() => setState(() {});
RxBool applyEnabled = false.obs;
return [
_OptionCheckBox(context, 'Enable Direct IP Access', 'direct-server',
_OptionCheckBox(context, 'Enable direct IP access', 'direct-server',
update: update, enabled: !locked),
() {
// Simple temp wrapper for PR check

View File

@@ -386,7 +386,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
pi.platform == kPeerPlatformMacOS)) {
menu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Restart Remote Device'),
translate('Restart remote device'),
style: style,
),
proc: () => showRestartRemoteDevice(

View File

@@ -592,7 +592,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
client.keyboard = enabled;
});
},
translate('Enable Keyboard/Mouse'),
translate('Enable keyboard/mouse'),
),
buildPermissionIcon(
client.clipboard,
@@ -604,7 +604,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
client.clipboard = enabled;
});
},
translate('Enable Clipboard'),
translate('Enable clipboard'),
),
buildPermissionIcon(
client.audio,
@@ -616,7 +616,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
client.audio = enabled;
});
},
translate('Enable Audio'),
translate('Enable audio'),
),
buildPermissionIcon(
client.file,
@@ -640,7 +640,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
client.restart = enabled;
});
},
translate('Enable Remote Restart'),
translate('Enable remote restart'),
),
buildPermissionIcon(
client.recording,
@@ -652,7 +652,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
client.recording = enabled;
});
},
translate('Enable Recording Session'),
translate('Enable recording session'),
),
// only windows support block input
if (Platform.isWindows)

View File

@@ -217,7 +217,7 @@ class ServiceNotRunningNotification extends StatelessWidget {
serverModel.toggleService();
}
},
label: Text(translate("Start Service")))
label: Text(translate("Start service")))
],
));
}
@@ -561,7 +561,7 @@ class _PermissionCheckerState extends State<PermissionChecker> {
serverModel.toggleService),
PermissionRow(translate("Input Control"), serverModel.inputOk,
serverModel.toggleInput),
PermissionRow(translate("Transfer File"), serverModel.fileOk,
PermissionRow(translate("Transfer file"), serverModel.fileOk,
serverModel.toggleFile),
hasAudioPermission
? PermissionRow(translate("Audio Capture"), serverModel.audioOk,

View File

@@ -221,7 +221,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
final List<AbstractSettingsTile> enhancementsTiles = [];
final List<AbstractSettingsTile> shareScreenTiles = [
SettingsTile.switchTile(
title: Text(translate('Deny LAN Discovery')),
title: Text(translate('Deny LAN discovery')),
initialValue: _denyLANDiscovery,
onToggle: (v) async {
await bind.mainSetOption(
@@ -270,7 +270,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
},
),
SettingsTile.switchTile(
title: Text(translate('Enable Recording Session')),
title: Text(translate('Enable recording session')),
initialValue: _enableRecordSession,
onToggle: (v) async {
await bind.mainSetOption(
@@ -407,7 +407,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
enhancementsTiles.add(SettingsTile.switchTile(
initialValue: _enableStartOnBoot,
title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text("${translate('Start on Boot')} (beta)"),
Text("${translate('Start on boot')} (beta)"),
Text(
'* ${translate('Start the screen sharing service on boot, requires special permissions')}',
style: Theme.of(context).textTheme.bodySmall),

View File

@@ -1006,7 +1006,7 @@ extension JobStateDisplay on JobState {
case JobState.none:
return translate("Waiting");
case JobState.inProgress:
return translate("Transfer File");
return translate("Transfer file");
case JobState.done:
return translate("Finished");
case JobState.error:

View File

@@ -22,10 +22,10 @@ class PeerTabModel with ChangeNotifier {
int get currentTab => _currentTab;
int _currentTab = 0; // index in tabNames
List<String> tabNames = [
'Recent Sessions',
'Recent sessions',
'Favorites',
'Discovered',
'Address Book',
'Address book',
'Group',
];
final List<IconData> icons = [