commit
4f6c6ab483
@ -17,6 +17,8 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import 'common/widgets/overlay.dart';
|
import 'common/widgets/overlay.dart';
|
||||||
|
import 'mobile/pages/file_manager_page.dart';
|
||||||
|
import 'mobile/pages/remote_page.dart';
|
||||||
import 'models/model.dart';
|
import 'models/model.dart';
|
||||||
import 'models/platform_model.dart';
|
import 'models/platform_model.dart';
|
||||||
|
|
||||||
@ -1071,7 +1073,7 @@ void connect(BuildContext context, String id,
|
|||||||
assert(!(isFileTransfer && isTcpTunneling && isRDP),
|
assert(!(isFileTransfer && isTcpTunneling && isRDP),
|
||||||
"more than one connect type");
|
"more than one connect type");
|
||||||
|
|
||||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
if (isDesktop) {
|
||||||
if (isFileTransfer) {
|
if (isFileTransfer) {
|
||||||
await rustDeskWinManager.newFileTransfer(id);
|
await rustDeskWinManager.newFileTransfer(id);
|
||||||
} else if (isTcpTunneling || isRDP) {
|
} else if (isTcpTunneling || isRDP) {
|
||||||
@ -1079,6 +1081,30 @@ void connect(BuildContext context, String id,
|
|||||||
} else {
|
} else {
|
||||||
await rustDeskWinManager.newRemoteDesktop(id);
|
await rustDeskWinManager.newRemoteDesktop(id);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (isFileTransfer) {
|
||||||
|
if (!await PermissionManager.check("file")) {
|
||||||
|
if (!await PermissionManager.request("file")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (BuildContext context) => FileManagerPage(id: id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (BuildContext context) => RemotePage(id: id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
if (!currentFocus.hasPrimaryFocus) {
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
currentFocus.unfocus();
|
currentFocus.unfocus();
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import 'package:contextmenu/contextmenu.dart';
|
import 'package:contextmenu/contextmenu.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peer_widget.dart';
|
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||||
import 'package:flutter_hbb/models/ab_model.dart';
|
import 'package:flutter_hbb/models/ab_model.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../desktop/pages/desktop_home_page.dart';
|
import '../../desktop/pages/desktop_home_page.dart';
|
||||||
|
import '../../mobile/pages/settings_page.dart';
|
||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
|
|
||||||
class AddressBook extends StatefulWidget {
|
class AddressBook extends StatefulWidget {
|
||||||
@ -37,11 +38,16 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
handleLogin() {
|
handleLogin() {
|
||||||
|
// TODO refactor login dialog for desktop and mobile
|
||||||
|
if (isDesktop) {
|
||||||
loginDialog().then((success) {
|
loginDialog().then((success) {
|
||||||
if (success) {
|
if (success) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
showLogin(gFFI.dialogManager);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Widget> buildAddressBook(BuildContext context) async {
|
Future<Widget> buildAddressBook(BuildContext context) async {
|
||||||
@ -174,7 +180,7 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
child: AddressBookPeerWidget()),
|
child: AddressBookPeersView()),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
@ -77,8 +77,11 @@ class _PeerCardState extends State<_PeerCard>
|
|||||||
subtitle: Text('${peer.username}@${peer.hostname}'),
|
subtitle: Text('${peer.username}@${peer.hostname}'),
|
||||||
title: Text(peer.alias.isEmpty ? formatID(peer.id) : peer.alias),
|
title: Text(peer.alias.isEmpty ? formatID(peer.id) : peer.alias),
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: const EdgeInsets.all(6),
|
decoration: BoxDecoration(
|
||||||
color: str2color('${peer.id}${peer.platform}', 0x7f),
|
color: str2color('${peer.id}${peer.platform}', 0x7f),
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(6),
|
||||||
child: getPlatformImage(peer.platform)),
|
child: getPlatformImage(peer.platform)),
|
||||||
trailing: InkWell(
|
trailing: InkWell(
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
@ -458,7 +461,7 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
await bind.mainSetPeerOption(id: id, key: option, value: value);
|
await bind.mainSetPeerOption(id: id, key: option, value: value);
|
||||||
},
|
},
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,7 +492,6 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
await bind.mainRemovePeer(id: id);
|
await bind.mainRemovePeer(id: id);
|
||||||
removePreference(id);
|
removePreference(id);
|
||||||
await reloadFunc();
|
await reloadFunc();
|
||||||
// Get.forceAppUpdate(); // TODO use inner model / state
|
|
||||||
}();
|
}();
|
||||||
},
|
},
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
@ -544,7 +546,6 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
if (favs.remove(id)) {
|
if (favs.remove(id)) {
|
||||||
await bind.mainStoreFav(favs: favs);
|
await bind.mainStoreFav(favs: favs);
|
||||||
await reloadFunc();
|
await reloadFunc();
|
||||||
// Get.forceAppUpdate(); // TODO use inner model / state
|
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
},
|
},
|
||||||
@ -589,8 +590,6 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
|
||||||
child: Form(
|
child: Form(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
@ -625,15 +624,13 @@ class RecentPeerCard extends BasePeerCard {
|
|||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
|
||||||
];
|
];
|
||||||
MenuEntryBase<String>? rdpAction;
|
if (isDesktop) {
|
||||||
if (peer.platform == 'Windows') {
|
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||||
rdpAction = _rdpAction(context, peer.id);
|
|
||||||
}
|
}
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
if (rdpAction != null) {
|
if (peer.platform == 'Windows') {
|
||||||
menuItems.add(rdpAction);
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
}
|
}
|
||||||
menuItems.add(_wolAction(peer.id));
|
menuItems.add(_wolAction(peer.id));
|
||||||
menuItems.add(MenuEntryDivider());
|
menuItems.add(MenuEntryDivider());
|
||||||
@ -657,15 +654,13 @@ class FavoritePeerCard extends BasePeerCard {
|
|||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
|
||||||
];
|
];
|
||||||
MenuEntryBase<String>? rdpAction;
|
if (isDesktop) {
|
||||||
if (peer.platform == 'Windows') {
|
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||||
rdpAction = _rdpAction(context, peer.id);
|
|
||||||
}
|
}
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
if (rdpAction != null) {
|
if (peer.platform == 'Windows') {
|
||||||
menuItems.add(rdpAction);
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
}
|
}
|
||||||
menuItems.add(_wolAction(peer.id));
|
menuItems.add(_wolAction(peer.id));
|
||||||
menuItems.add(MenuEntryDivider());
|
menuItems.add(MenuEntryDivider());
|
||||||
@ -691,15 +686,13 @@ class DiscoveredPeerCard extends BasePeerCard {
|
|||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
|
||||||
];
|
];
|
||||||
MenuEntryBase<String>? rdpAction;
|
if (isDesktop) {
|
||||||
if (peer.platform == 'Windows') {
|
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||||
rdpAction = _rdpAction(context, peer.id);
|
|
||||||
}
|
}
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
if (rdpAction != null) {
|
if (peer.platform == 'Windows') {
|
||||||
menuItems.add(rdpAction);
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
}
|
}
|
||||||
menuItems.add(_wolAction(peer.id));
|
menuItems.add(_wolAction(peer.id));
|
||||||
menuItems.add(MenuEntryDivider());
|
menuItems.add(MenuEntryDivider());
|
||||||
@ -722,15 +715,13 @@ class AddressBookPeerCard extends BasePeerCard {
|
|||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
|
||||||
];
|
];
|
||||||
MenuEntryBase<String>? rdpAction;
|
if (isDesktop) {
|
||||||
if (peer.platform == 'Windows') {
|
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||||
rdpAction = _rdpAction(context, peer.id);
|
|
||||||
}
|
}
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
if (rdpAction != null) {
|
if (peer.platform == 'Windows') {
|
||||||
menuItems.add(rdpAction);
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
}
|
}
|
||||||
menuItems.add(_wolAction(peer.id));
|
menuItems.add(_wolAction(peer.id));
|
||||||
menuItems.add(MenuEntryDivider());
|
menuItems.add(MenuEntryDivider());
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peer_widget.dart';
|
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peercard_widget.dart';
|
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ class _PeerTabPageState extends State<PeerTabPage>
|
|||||||
color: _tabIndex.value == t.key
|
color: _tabIndex.value == t.key
|
||||||
? MyTheme.color(context).bg
|
? MyTheme.color(context).bg
|
||||||
: null,
|
: null,
|
||||||
borderRadius: BorderRadius.circular(2),
|
borderRadius: BorderRadius.circular(isDesktop ? 2 : 6),
|
||||||
),
|
),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
|
@ -11,34 +11,34 @@ import 'package:window_manager/window_manager.dart';
|
|||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../models/peer_model.dart';
|
import '../../models/peer_model.dart';
|
||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
import 'peercard_widget.dart';
|
import 'peer_card.dart';
|
||||||
|
|
||||||
typedef OffstageFunc = bool Function(Peer peer);
|
typedef OffstageFunc = bool Function(Peer peer);
|
||||||
typedef PeerCardWidgetFunc = Widget Function(Peer peer);
|
typedef PeerCardBuilder = BasePeerCard Function(Peer peer);
|
||||||
|
|
||||||
/// for peer search text, global obs value
|
/// for peer search text, global obs value
|
||||||
final peerSearchText = "".obs;
|
final peerSearchText = "".obs;
|
||||||
final peerSearchTextController =
|
final peerSearchTextController =
|
||||||
TextEditingController(text: peerSearchText.value);
|
TextEditingController(text: peerSearchText.value);
|
||||||
|
|
||||||
class _PeerWidget extends StatefulWidget {
|
class _PeersView extends StatefulWidget {
|
||||||
final Peers peers;
|
final Peers peers;
|
||||||
final OffstageFunc offstageFunc;
|
final OffstageFunc offstageFunc;
|
||||||
final PeerCardWidgetFunc peerCardWidgetFunc;
|
final PeerCardBuilder peerCardBuilder;
|
||||||
|
|
||||||
const _PeerWidget(
|
const _PeersView(
|
||||||
{required this.peers,
|
{required this.peers,
|
||||||
required this.offstageFunc,
|
required this.offstageFunc,
|
||||||
required this.peerCardWidgetFunc,
|
required this.peerCardBuilder,
|
||||||
Key? key})
|
Key? key})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_PeerWidgetState createState() => _PeerWidgetState();
|
_PeersViewState createState() => _PeersViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State for the peer widget.
|
/// State for the peer widget.
|
||||||
class _PeerWidgetState extends State<_PeerWidget> with WindowListener {
|
class _PeersViewState extends State<_PeersView> with WindowListener {
|
||||||
static const int _maxQueryCount = 3;
|
static const int _maxQueryCount = 3;
|
||||||
final space = isDesktop ? 12.0 : 8.0;
|
final space = isDesktop ? 12.0 : 8.0;
|
||||||
final _curPeers = <String>{};
|
final _curPeers = <String>{};
|
||||||
@ -60,7 +60,7 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener {
|
|||||||
return width;
|
return width;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
_PeerWidgetState() {
|
_PeersViewState() {
|
||||||
_startCheckOnlines();
|
_startCheckOnlines();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener {
|
|||||||
}
|
}
|
||||||
_lastChangeTime = DateTime.now();
|
_lastChangeTime = DateTime.now();
|
||||||
},
|
},
|
||||||
child: widget.peerCardWidgetFunc(peer),
|
child: widget.peerCardBuilder(peer),
|
||||||
);
|
);
|
||||||
cards.add(Offstage(
|
cards.add(Offstage(
|
||||||
key: ValueKey("off${peer.id}"),
|
key: ValueKey("off${peer.id}"),
|
||||||
@ -198,39 +198,39 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BasePeerWidget extends StatelessWidget {
|
abstract class BasePeersView extends StatelessWidget {
|
||||||
final String name;
|
final String name;
|
||||||
final String loadEvent;
|
final String loadEvent;
|
||||||
final OffstageFunc offstageFunc;
|
final OffstageFunc offstageFunc;
|
||||||
final PeerCardWidgetFunc peerCardWidgetFunc;
|
final PeerCardBuilder peerCardBuilder;
|
||||||
final List<Peer> initPeers;
|
final List<Peer> initPeers;
|
||||||
|
|
||||||
const BasePeerWidget({
|
const BasePeersView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.loadEvent,
|
required this.loadEvent,
|
||||||
required this.offstageFunc,
|
required this.offstageFunc,
|
||||||
required this.peerCardWidgetFunc,
|
required this.peerCardBuilder,
|
||||||
required this.initPeers,
|
required this.initPeers,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return _PeerWidget(
|
return _PeersView(
|
||||||
peers: Peers(name: name, loadEvent: loadEvent, peers: initPeers),
|
peers: Peers(name: name, loadEvent: loadEvent, peers: initPeers),
|
||||||
offstageFunc: offstageFunc,
|
offstageFunc: offstageFunc,
|
||||||
peerCardWidgetFunc: peerCardWidgetFunc);
|
peerCardBuilder: peerCardBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecentPeerWidget extends BasePeerWidget {
|
class RecentPeersView extends BasePeersView {
|
||||||
RecentPeerWidget({Key? key})
|
RecentPeersView({Key? key})
|
||||||
: super(
|
: super(
|
||||||
key: key,
|
key: key,
|
||||||
name: 'recent peer',
|
name: 'recent peer',
|
||||||
loadEvent: 'load_recent_peers',
|
loadEvent: 'load_recent_peers',
|
||||||
offstageFunc: (Peer peer) => false,
|
offstageFunc: (Peer peer) => false,
|
||||||
peerCardWidgetFunc: (Peer peer) => RecentPeerCard(
|
peerCardBuilder: (Peer peer) => RecentPeerCard(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
),
|
),
|
||||||
initPeers: [],
|
initPeers: [],
|
||||||
@ -244,14 +244,14 @@ class RecentPeerWidget extends BasePeerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FavoritePeerWidget extends BasePeerWidget {
|
class FavoritePeersView extends BasePeersView {
|
||||||
FavoritePeerWidget({Key? key})
|
FavoritePeersView({Key? key})
|
||||||
: super(
|
: super(
|
||||||
key: key,
|
key: key,
|
||||||
name: 'favorite peer',
|
name: 'favorite peer',
|
||||||
loadEvent: 'load_fav_peers',
|
loadEvent: 'load_fav_peers',
|
||||||
offstageFunc: (Peer peer) => false,
|
offstageFunc: (Peer peer) => false,
|
||||||
peerCardWidgetFunc: (Peer peer) => FavoritePeerCard(
|
peerCardBuilder: (Peer peer) => FavoritePeerCard(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
),
|
),
|
||||||
initPeers: [],
|
initPeers: [],
|
||||||
@ -265,14 +265,14 @@ class FavoritePeerWidget extends BasePeerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiscoveredPeerWidget extends BasePeerWidget {
|
class DiscoveredPeersView extends BasePeersView {
|
||||||
DiscoveredPeerWidget({Key? key})
|
DiscoveredPeersView({Key? key})
|
||||||
: super(
|
: super(
|
||||||
key: key,
|
key: key,
|
||||||
name: 'discovered peer',
|
name: 'discovered peer',
|
||||||
loadEvent: 'load_lan_peers',
|
loadEvent: 'load_lan_peers',
|
||||||
offstageFunc: (Peer peer) => false,
|
offstageFunc: (Peer peer) => false,
|
||||||
peerCardWidgetFunc: (Peer peer) => DiscoveredPeerCard(
|
peerCardBuilder: (Peer peer) => DiscoveredPeerCard(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
),
|
),
|
||||||
initPeers: [],
|
initPeers: [],
|
||||||
@ -286,15 +286,15 @@ class DiscoveredPeerWidget extends BasePeerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddressBookPeerWidget extends BasePeerWidget {
|
class AddressBookPeersView extends BasePeersView {
|
||||||
AddressBookPeerWidget({Key? key})
|
AddressBookPeersView({Key? key})
|
||||||
: super(
|
: super(
|
||||||
key: key,
|
key: key,
|
||||||
name: 'address book peer',
|
name: 'address book peer',
|
||||||
loadEvent: 'load_address_book_peers',
|
loadEvent: 'load_address_book_peers',
|
||||||
offstageFunc: (Peer peer) =>
|
offstageFunc: (Peer peer) =>
|
||||||
!_hitTag(gFFI.abModel.selectedTags, peer.tags),
|
!_hitTag(gFFI.abModel.selectedTags, peer.tags),
|
||||||
peerCardWidgetFunc: (Peer peer) => AddressBookPeerCard(
|
peerCardBuilder: (Peer peer) => AddressBookPeerCard(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
),
|
),
|
||||||
initPeers: _loadPeers(),
|
initPeers: _loadPeers(),
|
@ -11,7 +11,7 @@ import 'package:url_launcher/url_launcher_string.dart';
|
|||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../common/formatter/id_formatter.dart';
|
import '../../common/formatter/id_formatter.dart';
|
||||||
import '../../common/widgets/peer_tab_page.dart';
|
import '../../common/widgets/peer_tab_page.dart';
|
||||||
import '../../common/widgets/peer_widget.dart';
|
import '../../common/widgets/peers_view.dart';
|
||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
|
|
||||||
/// Connection page for connecting to a remote peer.
|
/// Connection page for connecting to a remote peer.
|
||||||
@ -74,9 +74,9 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
translate('Address Book')
|
translate('Address Book')
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
RecentPeerWidget(),
|
RecentPeersView(),
|
||||||
FavoritePeerWidget(),
|
FavoritePeersView(),
|
||||||
DiscoveredPeerWidget(),
|
DiscoveredPeersView(),
|
||||||
const AddressBook(),
|
const AddressBook(),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
|
@ -331,7 +331,7 @@ Future<bool> loginDialog() async {
|
|||||||
var userNameMsg = "";
|
var userNameMsg = "";
|
||||||
String pass = "";
|
String pass = "";
|
||||||
var passMsg = "";
|
var passMsg = "";
|
||||||
var userContontroller = TextEditingController(text: userName);
|
var userController = TextEditingController(text: userName);
|
||||||
var pwdController = TextEditingController(text: pass);
|
var pwdController = TextEditingController(text: pass);
|
||||||
|
|
||||||
var isInProgress = false;
|
var isInProgress = false;
|
||||||
@ -349,7 +349,7 @@ Future<bool> loginDialog() async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
userName = userContontroller.text;
|
userName = userController.text;
|
||||||
pass = pwdController.text;
|
pass = pwdController.text;
|
||||||
if (userName.isEmpty) {
|
if (userName.isEmpty) {
|
||||||
userNameMsg = translate("Username missed");
|
userNameMsg = translate("Username missed");
|
||||||
@ -385,6 +385,7 @@ Future<bool> loginDialog() async {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 登录dialog
|
||||||
return CustomAlertDialog(
|
return CustomAlertDialog(
|
||||||
title: Text(translate("Login")),
|
title: Text(translate("Login")),
|
||||||
content: ConstrainedBox(
|
content: ConstrainedBox(
|
||||||
@ -411,7 +412,7 @@ Future<bool> loginDialog() async {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
errorText: userNameMsg.isNotEmpty ? userNameMsg : null),
|
errorText: userNameMsg.isNotEmpty ? userNameMsg : null),
|
||||||
controller: userContontroller,
|
controller: userController,
|
||||||
focusNode: FocusNode()..requestFocus(),
|
focusNode: FocusNode()..requestFocus(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -48,7 +48,7 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
|
|||||||
_TabInfo('Security', Icons.enhanced_encryption_outlined,
|
_TabInfo('Security', Icons.enhanced_encryption_outlined,
|
||||||
Icons.enhanced_encryption),
|
Icons.enhanced_encryption),
|
||||||
_TabInfo('Network', Icons.link_outlined, Icons.link),
|
_TabInfo('Network', Icons.link_outlined, Icons.link),
|
||||||
_TabInfo('Acount', Icons.person_outline, Icons.person),
|
_TabInfo('Account', Icons.person_outline, Icons.person),
|
||||||
_TabInfo('About', Icons.info_outline, Icons.info)
|
_TabInfo('About', Icons.info_outline, Icons.info)
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
|
|||||||
_General(),
|
_General(),
|
||||||
_Safety(),
|
_Safety(),
|
||||||
_Network(),
|
_Network(),
|
||||||
_Acount(),
|
_Account(),
|
||||||
_About(),
|
_About(),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
@ -641,14 +641,14 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Acount extends StatefulWidget {
|
class _Account extends StatefulWidget {
|
||||||
const _Acount({Key? key}) : super(key: key);
|
const _Account({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_Acount> createState() => _AcountState();
|
State<_Account> createState() => _AccountState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AcountState extends State<_Acount> {
|
class _AccountState extends State<_Account> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scrollController = ScrollController();
|
final scrollController = ScrollController();
|
||||||
@ -658,12 +658,12 @@ class _AcountState extends State<_Acount> {
|
|||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
children: [
|
children: [
|
||||||
_Card(title: 'Acount', children: [login()]),
|
_Card(title: 'Account', children: [accountAction()]),
|
||||||
],
|
],
|
||||||
).marginOnly(bottom: _kListViewBottomMargin));
|
).marginOnly(bottom: _kListViewBottomMargin));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget login() {
|
Widget accountAction() {
|
||||||
return _futureBuilder(future: () async {
|
return _futureBuilder(future: () async {
|
||||||
return await gFFI.userModel.getUserName();
|
return await gFFI.userModel.getUserName();
|
||||||
}(), hasData: (data) {
|
}(), hasData: (data) {
|
||||||
@ -671,12 +671,14 @@ class _AcountState extends State<_Acount> {
|
|||||||
return _Button(
|
return _Button(
|
||||||
username.isEmpty ? 'Login' : 'Logout',
|
username.isEmpty ? 'Login' : 'Logout',
|
||||||
() => {
|
() => {
|
||||||
loginDialog().then((success) {
|
username.isEmpty
|
||||||
|
? loginDialog().then((success) {
|
||||||
if (success) {
|
if (success) {
|
||||||
// refresh frame
|
// refresh frame
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
: gFFI.userModel.logOut()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||||
import 'package:flutter_hbb/mobile/pages/file_manager_page.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@ -10,12 +9,11 @@ import 'package:url_launcher/url_launcher.dart';
|
|||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../common/widgets/address_book.dart';
|
import '../../common/widgets/address_book.dart';
|
||||||
import '../../common/widgets/peer_tab_page.dart';
|
import '../../common/widgets/peer_tab_page.dart';
|
||||||
import '../../common/widgets/peer_widget.dart';
|
import '../../common/widgets/peers_view.dart';
|
||||||
import '../../consts.dart';
|
import '../../consts.dart';
|
||||||
import '../../models/model.dart';
|
import '../../models/model.dart';
|
||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
import 'home_page.dart';
|
import 'home_page.dart';
|
||||||
import 'remote_page.dart';
|
|
||||||
import 'scan_page.dart';
|
import 'scan_page.dart';
|
||||||
import 'settings_page.dart';
|
import 'settings_page.dart';
|
||||||
|
|
||||||
@ -84,9 +82,9 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
translate('Address Book')
|
translate('Address Book')
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
RecentPeerWidget(),
|
RecentPeersView(),
|
||||||
FavoritePeerWidget(),
|
FavoritePeersView(),
|
||||||
DiscoveredPeerWidget(),
|
DiscoveredPeersView(),
|
||||||
const AddressBook(),
|
const AddressBook(),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
@ -97,38 +95,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
/// Connects to the selected peer.
|
/// Connects to the selected peer.
|
||||||
void onConnect() {
|
void onConnect() {
|
||||||
var id = _idController.id;
|
var id = _idController.id;
|
||||||
connect(id);
|
connect(context, id);
|
||||||
}
|
|
||||||
|
|
||||||
/// Connect to a peer with [id].
|
|
||||||
/// If [isFileTransfer], starts a session only for file transfer.
|
|
||||||
void connect(String id, {bool isFileTransfer = false}) async {
|
|
||||||
if (id == '') return;
|
|
||||||
id = id.replaceAll(' ', '');
|
|
||||||
if (isFileTransfer) {
|
|
||||||
if (!await PermissionManager.check("file")) {
|
|
||||||
if (!await PermissionManager.request("file")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (BuildContext context) => FileManagerPage(id: id),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (BuildContext context) => RemotePage(id: id),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
|
||||||
if (!currentFocus.hasPrimaryFocus) {
|
|
||||||
currentFocus.unfocus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UI for software update.
|
/// UI for software update.
|
||||||
|
@ -25,14 +25,13 @@ class SettingsPage extends StatefulWidget implements PageShape {
|
|||||||
final appBarActions = [ScanButton()];
|
final appBarActions = [ScanButton()];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SettingsState createState() => _SettingsState();
|
State<SettingsPage> createState() => _SettingsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = 'https://rustdesk.com/';
|
const url = 'https://rustdesk.com/';
|
||||||
final _hasIgnoreBattery = androidVersion >= 26;
|
final _hasIgnoreBattery = androidVersion >= 26;
|
||||||
var _ignoreBatteryOpt = false;
|
var _ignoreBatteryOpt = false;
|
||||||
var _enableAbr = false;
|
var _enableAbr = false;
|
||||||
var _isDarkMode = false;
|
|
||||||
|
|
||||||
class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
||||||
String? username;
|
String? username;
|
||||||
@ -60,8 +59,6 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
_enableAbr = enableAbrRes;
|
_enableAbr = enableAbrRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _isDarkMode = MyTheme.currentDarkMode(); // TODO
|
|
||||||
|
|
||||||
if (update) {
|
if (update) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
@ -100,7 +97,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
Provider.of<FfiModel>(context);
|
Provider.of<FfiModel>(context);
|
||||||
final enhancementsTiles = [
|
final enhancementsTiles = [
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: Text(translate('Adaptive Bitrate') + ' (beta)'),
|
title: Text('${translate('Adaptive Bitrate')} (beta)'),
|
||||||
initialValue: _enableAbr,
|
initialValue: _enableAbr,
|
||||||
onToggle: (v) {
|
onToggle: (v) {
|
||||||
bind.mainSetOption(key: "enable-abr", value: v ? "" : "N");
|
bind.mainSetOption(key: "enable-abr", value: v ? "" : "N");
|
||||||
@ -152,7 +149,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
SettingsTile.navigation(
|
SettingsTile.navigation(
|
||||||
title: Text(username == null
|
title: Text(username == null
|
||||||
? translate("Login")
|
? translate("Login")
|
||||||
: translate("Logout") + ' ($username)'),
|
: '${translate("Logout")} ($username)'),
|
||||||
leading: Icon(Icons.person),
|
leading: Icon(Icons.person),
|
||||||
onPressed: (context) {
|
onPressed: (context) {
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
@ -177,15 +174,11 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
onPressed: (context) {
|
onPressed: (context) {
|
||||||
showLanguageSettings(gFFI.dialogManager);
|
showLanguageSettings(gFFI.dialogManager);
|
||||||
}),
|
}),
|
||||||
SettingsTile.switchTile(
|
SettingsTile.navigation(
|
||||||
title: Text(translate('Dark Theme')),
|
title: Text(translate('Dark Theme')),
|
||||||
leading: Icon(Icons.dark_mode),
|
leading: Icon(Icons.dark_mode),
|
||||||
initialValue: _isDarkMode,
|
onPressed: (context) {
|
||||||
onToggle: (v) {
|
showThemeSettings(gFFI.dialogManager);
|
||||||
setState(() {
|
|
||||||
_isDarkMode = !_isDarkMode;
|
|
||||||
// MyTheme.changeDarkMode(_isDarkMode); // TODO
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
@ -232,7 +225,7 @@ void showLanguageSettings(OverlayDialogManager dialogManager) async {
|
|||||||
final langs = json.decode(await bind.mainGetLangs()) as List<dynamic>;
|
final langs = json.decode(await bind.mainGetLangs()) as List<dynamic>;
|
||||||
var lang = await bind.mainGetLocalOption(key: "lang");
|
var lang = await bind.mainGetLocalOption(key: "lang");
|
||||||
dialogManager.show((setState, close) {
|
dialogManager.show((setState, close) {
|
||||||
final setLang = (v) {
|
setLang(v) {
|
||||||
if (lang != v) {
|
if (lang != v) {
|
||||||
setState(() {
|
setState(() {
|
||||||
lang = v;
|
lang = v;
|
||||||
@ -241,7 +234,8 @@ void showLanguageSettings(OverlayDialogManager dialogManager) async {
|
|||||||
HomePage.homeKey.currentState?.refreshPages();
|
HomePage.homeKey.currentState?.refreshPages();
|
||||||
Future.delayed(Duration(milliseconds: 200), close);
|
Future.delayed(Duration(milliseconds: 200), close);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return CustomAlertDialog(
|
return CustomAlertDialog(
|
||||||
title: SizedBox.shrink(),
|
title: SizedBox.shrink(),
|
||||||
content: Column(
|
content: Column(
|
||||||
@ -257,13 +251,41 @@ void showLanguageSettings(OverlayDialogManager dialogManager) async {
|
|||||||
),
|
),
|
||||||
actions: []);
|
actions: []);
|
||||||
}, backDismiss: true, clickMaskDismiss: true);
|
}, backDismiss: true, clickMaskDismiss: true);
|
||||||
} catch (_e) {}
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showThemeSettings(OverlayDialogManager dialogManager) async {
|
||||||
|
var themeMode = MyTheme.getThemeModePreference();
|
||||||
|
|
||||||
|
dialogManager.show((setState, close) {
|
||||||
|
setTheme(v) {
|
||||||
|
if (themeMode != v) {
|
||||||
|
setState(() {
|
||||||
|
themeMode = v;
|
||||||
|
});
|
||||||
|
MyTheme.changeDarkMode(themeMode);
|
||||||
|
Future.delayed(Duration(milliseconds: 200), close);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CustomAlertDialog(
|
||||||
|
title: SizedBox.shrink(),
|
||||||
|
contentPadding: 10,
|
||||||
|
content: Column(children: [
|
||||||
|
getRadio('Light', ThemeMode.light, themeMode, setTheme),
|
||||||
|
getRadio('Dark', ThemeMode.dark, themeMode, setTheme),
|
||||||
|
getRadio('Follow System', ThemeMode.system, themeMode, setTheme)
|
||||||
|
]),
|
||||||
|
actions: []);
|
||||||
|
}, backDismiss: true, clickMaskDismiss: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showAbout(OverlayDialogManager dialogManager) {
|
void showAbout(OverlayDialogManager dialogManager) {
|
||||||
dialogManager.show((setState, close) {
|
dialogManager.show((setState, close) {
|
||||||
return CustomAlertDialog(
|
return CustomAlertDialog(
|
||||||
title: Text(translate('About') + ' RustDesk'),
|
title: Text('${translate('About')} RustDesk'),
|
||||||
content: Wrap(direction: Axis.vertical, spacing: 12, children: [
|
content: Wrap(direction: Axis.vertical, spacing: 12, children: [
|
||||||
Text('Version: $version'),
|
Text('Version: $version'),
|
||||||
InkWell(
|
InkWell(
|
||||||
@ -429,7 +451,7 @@ void showLogin(OverlayDialogManager dialogManager) {
|
|||||||
),
|
),
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
),
|
),
|
||||||
PasswordWidget(controller: passwordController),
|
PasswordWidget(controller: passwordController, autoFocus: false),
|
||||||
]),
|
]),
|
||||||
actions: (loading
|
actions: (loading
|
||||||
? <Widget>[CircularProgressIndicator()]
|
? <Widget>[CircularProgressIndicator()]
|
||||||
|
@ -6,8 +6,7 @@ import '../../models/model.dart';
|
|||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
|
|
||||||
void clientClose(OverlayDialogManager dialogManager) {
|
void clientClose(OverlayDialogManager dialogManager) {
|
||||||
msgBox('', 'Close', 'Are you sure to close the connection?',
|
msgBox('', 'Close', 'Are you sure to close the connection?', dialogManager);
|
||||||
dialogManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSuccess() {
|
void showSuccess() {
|
||||||
@ -131,7 +130,7 @@ void setTemporaryPasswordLengthDialog(
|
|||||||
if (index < 0) index = 0;
|
if (index < 0) index = 0;
|
||||||
length = lengths[index];
|
length = lengths[index];
|
||||||
dialogManager.show((setState, close) {
|
dialogManager.show((setState, close) {
|
||||||
final setLength = (newValue) {
|
setLength(newValue) {
|
||||||
final oldValue = length;
|
final oldValue = length;
|
||||||
if (oldValue == newValue) return;
|
if (oldValue == newValue) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -143,7 +142,8 @@ void setTemporaryPasswordLengthDialog(
|
|||||||
close();
|
close();
|
||||||
showSuccess();
|
showSuccess();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
return CustomAlertDialog(
|
return CustomAlertDialog(
|
||||||
title: Text(translate("Set temporary password length")),
|
title: Text(translate("Set temporary password length")),
|
||||||
content: Column(
|
content: Column(
|
||||||
@ -230,12 +230,14 @@ void wrongPasswordDialog(String id, OverlayDialogManager dialogManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PasswordWidget extends StatefulWidget {
|
class PasswordWidget extends StatefulWidget {
|
||||||
PasswordWidget({Key? key, required this.controller}) : super(key: key);
|
PasswordWidget({Key? key, required this.controller, this.autoFocus = true})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
final bool autoFocus;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_PasswordWidgetState createState() => _PasswordWidgetState();
|
State<PasswordWidget> createState() => _PasswordWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PasswordWidgetState extends State<PasswordWidget> {
|
class _PasswordWidgetState extends State<PasswordWidget> {
|
||||||
@ -245,8 +247,10 @@ class _PasswordWidgetState extends State<PasswordWidget> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
if (widget.autoFocus) {
|
||||||
Timer(Duration(milliseconds: 50), () => _focusNode.requestFocus());
|
Timer(Duration(milliseconds: 50), () => _focusNode.requestFocus());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "适应窗口"),
|
("Scale adaptive", "适应窗口"),
|
||||||
("General", "常规"),
|
("General", "常规"),
|
||||||
("Security", "安全"),
|
("Security", "安全"),
|
||||||
("Acount", "账户"),
|
("Account", "账户"),
|
||||||
("Theme", "主题"),
|
("Theme", "主题"),
|
||||||
("Dark Theme", "暗黑主题"),
|
("Dark Theme", "暗黑主题"),
|
||||||
("Enable hardware codec", "使用硬件编解码"),
|
("Enable hardware codec", "使用硬件编解码"),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Měřítko adaptivní"),
|
("Scale adaptive", "Měřítko adaptivní"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Skala adaptiv"),
|
("Scale adaptive", "Skala adaptiv"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Adaptiv skalieren"),
|
("Scale adaptive", "Adaptiv skalieren"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Skalo adapta"),
|
("Scale adaptive", "Skalo adapta"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -337,7 +337,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Adaptable a escala"),
|
("Scale adaptive", "Adaptable a escala"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Échelle adaptative"),
|
("Scale adaptive", "Échelle adaptative"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Skála adaptív"),
|
("Scale adaptive", "Skála adaptív"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -337,7 +337,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Skala adaptif"),
|
("Scale adaptive", "Skala adaptif"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -323,7 +323,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Translate mode", ""),
|
("Translate mode", ""),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -321,7 +321,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "フィットウィンドウ"),
|
("Scale adaptive", "フィットウィンドウ"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -318,7 +318,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "맞는 창"),
|
("Scale adaptive", "맞는 창"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -322,7 +322,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Skala adaptacyjna"),
|
("Scale adaptive", "Skala adaptacyjna"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -318,7 +318,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Escala adaptável"),
|
("Scale adaptive", "Escala adaptável"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", ""),
|
("Scale adaptive", ""),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Масштаб адаптивный"),
|
("Scale adaptive", "Масштаб адаптивный"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Prispôsobivá mierka"),
|
("Scale adaptive", "Prispôsobivá mierka"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", ""),
|
("Scale adaptive", ""),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -337,7 +337,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Ölçek uyarlanabilir"),
|
("Scale adaptive", "Ölçek uyarlanabilir"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "適應窗口"),
|
("Scale adaptive", "適應窗口"),
|
||||||
("General", "常規"),
|
("General", "常規"),
|
||||||
("Security", "安全"),
|
("Security", "安全"),
|
||||||
("Acount", "賬戶"),
|
("Account", "賬戶"),
|
||||||
("Theme", "主題"),
|
("Theme", "主題"),
|
||||||
("Dark Theme", "暗黑主題"),
|
("Dark Theme", "暗黑主題"),
|
||||||
("Enable hardware codec", "使用硬件編解碼"),
|
("Enable hardware codec", "使用硬件編解碼"),
|
||||||
|
@ -324,7 +324,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Quy mô thích ứng"),
|
("Scale adaptive", "Quy mô thích ứng"),
|
||||||
("General", ""),
|
("General", ""),
|
||||||
("Security", ""),
|
("Security", ""),
|
||||||
("Acount", ""),
|
("Account", ""),
|
||||||
("Theme", ""),
|
("Theme", ""),
|
||||||
("Dark Theme", ""),
|
("Dark Theme", ""),
|
||||||
("Enable hardware codec", ""),
|
("Enable hardware codec", ""),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user