commit
f5b7c34c81
@ -197,30 +197,39 @@ class MyTheme {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
static changeTo(bool dark) {
|
static ThemeMode getThemeModePreference() {
|
||||||
if (isDarkTheme() != dark) {
|
return themeModeFromString(
|
||||||
Get.find<SharedPreferences>().setString("darkTheme", dark ? "Y" : "");
|
Get.find<SharedPreferences>().getString("themeMode") ?? "");
|
||||||
Get.changeThemeMode(dark ? ThemeMode.dark : ThemeMode.light);
|
}
|
||||||
|
|
||||||
|
static void changeDarkMode(ThemeMode mode) {
|
||||||
|
final preference = getThemeModePreference();
|
||||||
|
if (preference != mode) {
|
||||||
|
if (mode == ThemeMode.system) {
|
||||||
|
Get.find<SharedPreferences>().setString("themeMode", "");
|
||||||
|
} else {
|
||||||
|
Get.find<SharedPreferences>()
|
||||||
|
.setString("themeMode", mode.toShortString());
|
||||||
|
}
|
||||||
|
Get.changeThemeMode(mode);
|
||||||
if (desktopType == DesktopType.main) {
|
if (desktopType == DesktopType.main) {
|
||||||
bind.mainChangeTheme(dark: dark);
|
bind.mainChangeTheme(dark: currentThemeMode().toShortString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _themeInitialed = false;
|
static ThemeMode currentThemeMode() {
|
||||||
|
final preference = getThemeModePreference();
|
||||||
static ThemeMode initialThemeMode({bool mainPage = false}) {
|
if (preference == ThemeMode.system) {
|
||||||
bool dark;
|
if (WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
||||||
// Brightnesss is always light on windows, Flutter 3.0.5
|
Brightness.light) {
|
||||||
if (_themeInitialed || !mainPage || Platform.isWindows) {
|
return ThemeMode.light;
|
||||||
dark = isDarkTheme();
|
} else {
|
||||||
|
return ThemeMode.dark;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dark = WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
return preference;
|
||||||
Brightness.dark;
|
|
||||||
Get.find<SharedPreferences>().setString("darkTheme", dark ? "Y" : "");
|
|
||||||
}
|
}
|
||||||
_themeInitialed = true;
|
|
||||||
return dark ? ThemeMode.dark : ThemeMode.light;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ColorThemeExtension color(BuildContext context) {
|
static ColorThemeExtension color(BuildContext context) {
|
||||||
@ -230,10 +239,23 @@ class MyTheme {
|
|||||||
static TabbarTheme tabbar(BuildContext context) {
|
static TabbarTheme tabbar(BuildContext context) {
|
||||||
return Theme.of(context).extension<TabbarTheme>()!;
|
return Theme.of(context).extension<TabbarTheme>()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ThemeMode themeModeFromString(String v) {
|
||||||
|
switch (v) {
|
||||||
|
case "light":
|
||||||
|
return ThemeMode.light;
|
||||||
|
case "dark":
|
||||||
|
return ThemeMode.dark;
|
||||||
|
default:
|
||||||
|
return ThemeMode.system;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDarkTheme() {
|
extension ParseToString on ThemeMode {
|
||||||
return "Y" == Get.find<SharedPreferences>().getString("darkTheme");
|
String toShortString() {
|
||||||
|
return toString().split('.').last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ButtonStyle flatButtonStyle = TextButton.styleFrom(
|
final ButtonStyle flatButtonStyle = TextButton.styleFrom(
|
||||||
|
@ -303,7 +303,7 @@ class AddressBookPeerWidget extends BasePeerWidget {
|
|||||||
static List<Peer> _loadPeers() {
|
static List<Peer> _loadPeers() {
|
||||||
debugPrint("_loadPeers : ${gFFI.abModel.peers.toString()}");
|
debugPrint("_loadPeers : ${gFFI.abModel.peers.toString()}");
|
||||||
return gFFI.abModel.peers.map((e) {
|
return gFFI.abModel.peers.map((e) {
|
||||||
return Peer.fromJson(e['id'], e);
|
return Peer.fromJson(e);
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +27,11 @@ final peerCardUiType = PeerUiType.grid.obs;
|
|||||||
|
|
||||||
class _PeerCard extends StatefulWidget {
|
class _PeerCard extends StatefulWidget {
|
||||||
final Peer peer;
|
final Peer peer;
|
||||||
final RxString alias;
|
|
||||||
final Function(BuildContext, String) connect;
|
final Function(BuildContext, String) connect;
|
||||||
final PopupMenuEntryBuilder popupMenuEntryBuilder;
|
final PopupMenuEntryBuilder popupMenuEntryBuilder;
|
||||||
|
|
||||||
const _PeerCard(
|
const _PeerCard(
|
||||||
{required this.peer,
|
{required this.peer,
|
||||||
required this.alias,
|
|
||||||
required this.connect,
|
required this.connect,
|
||||||
required this.popupMenuEntryBuilder,
|
required this.popupMenuEntryBuilder,
|
||||||
Key? key})
|
Key? key})
|
||||||
@ -77,7 +75,7 @@ class _PeerCardState extends State<_PeerCard>
|
|||||||
child: ListTile(
|
child: ListTile(
|
||||||
contentPadding: const EdgeInsets.only(left: 12),
|
contentPadding: const EdgeInsets.only(left: 12),
|
||||||
subtitle: Text('${peer.username}@${peer.hostname}'),
|
subtitle: Text('${peer.username}@${peer.hostname}'),
|
||||||
title: Text(formatID(peer.id)),
|
title: Text(peer.alias.isEmpty ? formatID(peer.id) : peer.alias),
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: const EdgeInsets.all(6),
|
padding: const EdgeInsets.all(6),
|
||||||
color: str2color('${peer.id}${peer.platform}', 0x7f),
|
color: str2color('${peer.id}${peer.platform}', 0x7f),
|
||||||
@ -216,6 +214,7 @@ class _PeerCardState extends State<_PeerCard>
|
|||||||
|
|
||||||
Widget _buildPeerCard(
|
Widget _buildPeerCard(
|
||||||
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
|
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
|
||||||
|
final name = '${peer.username}@${peer.hostname}';
|
||||||
return Card(
|
return Card(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@ -246,24 +245,18 @@ class _PeerCardState extends State<_PeerCard>
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(() {
|
child: Tooltip(
|
||||||
final name = widget.alias.value.isEmpty
|
message: name,
|
||||||
? '${peer.username}@${peer.hostname}'
|
waitDuration: const Duration(seconds: 1),
|
||||||
: widget.alias.value;
|
child: Text(
|
||||||
return Tooltip(
|
name,
|
||||||
message: name,
|
style: const TextStyle(
|
||||||
waitDuration:
|
color: Colors.white70,
|
||||||
const Duration(seconds: 1),
|
fontSize: 12),
|
||||||
child: Text(
|
textAlign: TextAlign.center,
|
||||||
name,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
),
|
||||||
color: Colors.white70,
|
),
|
||||||
fontSize: 12),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -287,7 +280,8 @@ class _PeerCardState extends State<_PeerCard>
|
|||||||
backgroundColor: peer.online
|
backgroundColor: peer.online
|
||||||
? Colors.green
|
? Colors.green
|
||||||
: Colors.yellow)),
|
: Colors.yellow)),
|
||||||
Text(formatID(peer.id))
|
Text(
|
||||||
|
peer.alias.isEmpty ? formatID(peer.id) : peer.alias)
|
||||||
]).paddingSymmetric(vertical: 8),
|
]).paddingSymmetric(vertical: 8),
|
||||||
_actionMore(peer),
|
_actionMore(peer),
|
||||||
],
|
],
|
||||||
@ -338,20 +332,14 @@ class _PeerCardState extends State<_PeerCard>
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class BasePeerCard extends StatelessWidget {
|
abstract class BasePeerCard extends StatelessWidget {
|
||||||
final RxString alias = ''.obs;
|
|
||||||
final Peer peer;
|
final Peer peer;
|
||||||
|
|
||||||
BasePeerCard({required this.peer, Key? key}) : super(key: key) {
|
BasePeerCard({required this.peer, Key? key}) : super(key: key);
|
||||||
bind
|
|
||||||
.mainGetPeerOption(id: peer.id, key: 'alias')
|
|
||||||
.then((value) => alias.value = value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return _PeerCard(
|
return _PeerCard(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
alias: alias,
|
|
||||||
connect: (BuildContext context, String id) => connect(context, id),
|
connect: (BuildContext context, String id) => connect(context, id),
|
||||||
popupMenuEntryBuilder: _buildPopupMenuEntry,
|
popupMenuEntryBuilder: _buildPopupMenuEntry,
|
||||||
);
|
);
|
||||||
@ -379,7 +367,7 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
bool isRDP = false}) {
|
bool isRDP = false}) {
|
||||||
return MenuEntryButton<String>(
|
return MenuEntryButton<String>(
|
||||||
childBuilder: (TextStyle? style) => Text(
|
childBuilder: (TextStyle? style) => Text(
|
||||||
translate(title),
|
title,
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
proc: () {
|
proc: () {
|
||||||
@ -396,8 +384,13 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MenuEntryBase<String> _connectAction(BuildContext context, String id) {
|
MenuEntryBase<String> _connectAction(BuildContext context, Peer peer) {
|
||||||
return _connectCommonAction(context, id, 'Connect');
|
return _connectCommonAction(
|
||||||
|
context,
|
||||||
|
peer.id,
|
||||||
|
peer.alias.isEmpty
|
||||||
|
? translate('Connect')
|
||||||
|
: "${translate('Connect')} ${peer.id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
@ -405,7 +398,7 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
return _connectCommonAction(
|
return _connectCommonAction(
|
||||||
context,
|
context,
|
||||||
id,
|
id,
|
||||||
'Transfer File',
|
translate('Transfer File'),
|
||||||
isFileTransfer: true,
|
isFileTransfer: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -415,7 +408,7 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
return _connectCommonAction(
|
return _connectCommonAction(
|
||||||
context,
|
context,
|
||||||
id,
|
id,
|
||||||
'TCP Tunneling',
|
translate('TCP Tunneling'),
|
||||||
isTcpTunneling: true,
|
isTcpTunneling: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -578,7 +571,7 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
|
|
||||||
void _rename(String id, bool isAddressBook) async {
|
void _rename(String id, bool isAddressBook) async {
|
||||||
RxBool isInProgress = false.obs;
|
RxBool isInProgress = false.obs;
|
||||||
var name = await bind.mainGetPeerOption(id: id, key: 'alias');
|
var name = peer.alias;
|
||||||
var controller = TextEditingController(text: name);
|
var controller = TextEditingController(text: name);
|
||||||
if (isAddressBook) {
|
if (isAddressBook) {
|
||||||
final peer = gFFI.abModel.peers.firstWhere((p) => id == p['id']);
|
final peer = gFFI.abModel.peers.firstWhere((p) => id == p['id']);
|
||||||
@ -597,7 +590,12 @@ abstract class BasePeerCard extends StatelessWidget {
|
|||||||
gFFI.abModel.setPeerOption(id, 'alias', name);
|
gFFI.abModel.setPeerOption(id, 'alias', name);
|
||||||
await gFFI.abModel.updateAb();
|
await gFFI.abModel.updateAb();
|
||||||
}
|
}
|
||||||
alias.value = await bind.mainGetPeerOption(id: peer.id, key: 'alias');
|
if (isAddressBook) {
|
||||||
|
gFFI.abModel.getAb();
|
||||||
|
} else {
|
||||||
|
bind.mainLoadRecentPeers();
|
||||||
|
bind.mainLoadFavPeers();
|
||||||
|
}
|
||||||
close();
|
close();
|
||||||
isInProgress.value = false;
|
isInProgress.value = false;
|
||||||
}
|
}
|
||||||
@ -642,7 +640,7 @@ class RecentPeerCard extends BasePeerCard {
|
|||||||
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
||||||
BuildContext context) async {
|
BuildContext context) async {
|
||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer.id),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
_tcpTunnelingAction(context, peer.id),
|
||||||
];
|
];
|
||||||
@ -674,7 +672,7 @@ class FavoritePeerCard extends BasePeerCard {
|
|||||||
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
||||||
BuildContext context) async {
|
BuildContext context) async {
|
||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer.id),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
_tcpTunnelingAction(context, peer.id),
|
||||||
];
|
];
|
||||||
@ -708,7 +706,7 @@ class DiscoveredPeerCard extends BasePeerCard {
|
|||||||
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
||||||
BuildContext context) async {
|
BuildContext context) async {
|
||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer.id),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
_tcpTunnelingAction(context, peer.id),
|
||||||
];
|
];
|
||||||
@ -739,7 +737,7 @@ class AddressBookPeerCard extends BasePeerCard {
|
|||||||
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
Future<List<MenuEntryBase<String>>> _buildMenuItems(
|
||||||
BuildContext context) async {
|
BuildContext context) async {
|
||||||
final List<MenuEntryBase<String>> menuItems = [
|
final List<MenuEntryBase<String>> menuItems = [
|
||||||
_connectAction(context, peer.id),
|
_connectAction(context, peer),
|
||||||
_transferFileAction(context, peer.id),
|
_transferFileAction(context, peer.id),
|
||||||
_tcpTunnelingAction(context, peer.id),
|
_tcpTunnelingAction(context, peer.id),
|
||||||
];
|
];
|
||||||
|
@ -205,22 +205,28 @@ class _GeneralState extends State<_General> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget theme() {
|
Widget theme() {
|
||||||
change() {
|
final current = MyTheme.getThemeModePreference().toShortString();
|
||||||
MyTheme.changeTo(!isDarkTheme());
|
onChanged(String value) {
|
||||||
|
MyTheme.changeDarkMode(MyTheme.themeModeFromString(value));
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
return _Card(title: 'Theme', children: [
|
return _Card(title: 'Theme', children: [
|
||||||
GestureDetector(
|
_Radio<String>(context,
|
||||||
onTap: change,
|
value: "light",
|
||||||
child: Row(
|
groupValue: current,
|
||||||
children: [
|
label: "Light",
|
||||||
Checkbox(value: isDarkTheme(), onChanged: (_) => change())
|
onChanged: onChanged),
|
||||||
.marginOnly(right: 5),
|
_Radio<String>(context,
|
||||||
Expanded(child: Text(translate('Dark Theme'))),
|
value: "dark",
|
||||||
],
|
groupValue: current,
|
||||||
).marginOnly(left: _kCheckBoxLeftMargin),
|
label: "Dark",
|
||||||
)
|
onChanged: onChanged),
|
||||||
|
_Radio<String>(context,
|
||||||
|
value: "system",
|
||||||
|
groupValue: current,
|
||||||
|
label: "Follow System",
|
||||||
|
onChanged: onChanged),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ class _PortForwardPageState extends State<PortForwardPage>
|
|||||||
height: _kRowHeight,
|
height: _kRowHeight,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: index % 2 == 0
|
color: index % 2 == 0
|
||||||
? isDarkTheme()
|
? MyTheme.currentThemeMode() == ThemeMode.dark
|
||||||
? const Color(0xFF202020)
|
? const Color(0xFF202020)
|
||||||
: const Color(0xFFF4F5F6)
|
: const Color(0xFFF4F5F6)
|
||||||
: MyTheme.color(context).bg),
|
: MyTheme.color(context).bg),
|
||||||
|
@ -120,7 +120,7 @@ void runRemoteScreen(Map<String, dynamic> argument) async {
|
|||||||
title: 'RustDesk - Remote Desktop',
|
title: 'RustDesk - Remote Desktop',
|
||||||
theme: MyTheme.lightTheme,
|
theme: MyTheme.lightTheme,
|
||||||
darkTheme: MyTheme.darkTheme,
|
darkTheme: MyTheme.darkTheme,
|
||||||
themeMode: MyTheme.initialThemeMode(),
|
themeMode: MyTheme.currentThemeMode(),
|
||||||
home: DesktopRemoteScreen(
|
home: DesktopRemoteScreen(
|
||||||
params: argument,
|
params: argument,
|
||||||
),
|
),
|
||||||
@ -146,7 +146,7 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
|
|||||||
title: 'RustDesk - File Transfer',
|
title: 'RustDesk - File Transfer',
|
||||||
theme: MyTheme.lightTheme,
|
theme: MyTheme.lightTheme,
|
||||||
darkTheme: MyTheme.darkTheme,
|
darkTheme: MyTheme.darkTheme,
|
||||||
themeMode: MyTheme.initialThemeMode(),
|
themeMode: MyTheme.currentThemeMode(),
|
||||||
home: DesktopFileTransferScreen(params: argument),
|
home: DesktopFileTransferScreen(params: argument),
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
@ -171,7 +171,7 @@ void runPortForwardScreen(Map<String, dynamic> argument) async {
|
|||||||
title: 'RustDesk - Port Forward',
|
title: 'RustDesk - Port Forward',
|
||||||
theme: MyTheme.lightTheme,
|
theme: MyTheme.lightTheme,
|
||||||
darkTheme: MyTheme.darkTheme,
|
darkTheme: MyTheme.darkTheme,
|
||||||
themeMode: MyTheme.initialThemeMode(),
|
themeMode: MyTheme.currentThemeMode(),
|
||||||
home: DesktopPortForwardScreen(params: argument),
|
home: DesktopPortForwardScreen(params: argument),
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
@ -196,7 +196,7 @@ void runConnectionManagerScreen() async {
|
|||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: MyTheme.lightTheme,
|
theme: MyTheme.lightTheme,
|
||||||
darkTheme: MyTheme.darkTheme,
|
darkTheme: MyTheme.darkTheme,
|
||||||
themeMode: MyTheme.initialThemeMode(),
|
themeMode: MyTheme.currentThemeMode(),
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
GlobalWidgetsLocalizations.delegate,
|
GlobalWidgetsLocalizations.delegate,
|
||||||
@ -233,12 +233,21 @@ class _AppState extends State<App> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.window.onPlatformBrightnessChanged = () {
|
WidgetsBinding.instance.window.onPlatformBrightnessChanged = () {
|
||||||
|
final userPreference = MyTheme.getThemeModePreference();
|
||||||
|
if (userPreference != ThemeMode.system) return;
|
||||||
WidgetsBinding.instance.handlePlatformBrightnessChanged();
|
WidgetsBinding.instance.handlePlatformBrightnessChanged();
|
||||||
var system =
|
final systemIsDark =
|
||||||
WidgetsBinding.instance.platformDispatcher.platformBrightness;
|
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
||||||
var current = isDarkTheme() ? Brightness.dark : Brightness.light;
|
Brightness.dark;
|
||||||
if (current != system) {
|
final ThemeMode to;
|
||||||
MyTheme.changeTo(system == Brightness.dark);
|
if (systemIsDark) {
|
||||||
|
to = ThemeMode.dark;
|
||||||
|
} else {
|
||||||
|
to = ThemeMode.light;
|
||||||
|
}
|
||||||
|
Get.changeThemeMode(to);
|
||||||
|
if (desktopType == DesktopType.main) {
|
||||||
|
bind.mainChangeTheme(dark: to.toShortString());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -263,7 +272,7 @@ class _AppState extends State<App> {
|
|||||||
title: 'RustDesk',
|
title: 'RustDesk',
|
||||||
theme: MyTheme.lightTheme,
|
theme: MyTheme.lightTheme,
|
||||||
darkTheme: MyTheme.darkTheme,
|
darkTheme: MyTheme.darkTheme,
|
||||||
themeMode: MyTheme.initialThemeMode(mainPage: true),
|
themeMode: MyTheme.currentThemeMode(),
|
||||||
home: isDesktop
|
home: isDesktop
|
||||||
? const DesktopTabPage()
|
? const DesktopTabPage()
|
||||||
: !isAndroid
|
: !isAndroid
|
||||||
@ -309,7 +318,7 @@ _registerEventHandler() {
|
|||||||
platformFFI.registerEventHandler('theme', 'theme', (evt) async {
|
platformFFI.registerEventHandler('theme', 'theme', (evt) async {
|
||||||
String? dark = evt['dark'];
|
String? dark = evt['dark'];
|
||||||
if (dark != null) {
|
if (dark != null) {
|
||||||
MyTheme.changeTo(dark == 'true');
|
MyTheme.changeDarkMode(MyTheme.themeModeFromString(dark));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
platformFFI.registerEventHandler('language', 'language', (_) async {
|
platformFFI.registerEventHandler('language', 'language', (_) async {
|
||||||
|
@ -60,7 +60,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
_enableAbr = enableAbrRes;
|
_enableAbr = enableAbrRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
_enableAbr = isDarkTheme();
|
// _isDarkMode = MyTheme.currentDarkMode(); // TODO
|
||||||
|
|
||||||
if (update) {
|
if (update) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -184,7 +184,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
onToggle: (v) {
|
onToggle: (v) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isDarkMode = !_isDarkMode;
|
_isDarkMode = !_isDarkMode;
|
||||||
MyTheme.changeTo(_isDarkMode);
|
// MyTheme.changeDarkMode(_isDarkMode); // TODO
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,6 @@ import '../common.dart';
|
|||||||
import '../common/shared_state.dart';
|
import '../common/shared_state.dart';
|
||||||
import '../utils/image.dart' as img;
|
import '../utils/image.dart' as img;
|
||||||
import '../mobile/widgets/dialog.dart';
|
import '../mobile/widgets/dialog.dart';
|
||||||
import 'peer_model.dart';
|
|
||||||
import 'platform_model.dart';
|
import 'platform_model.dart';
|
||||||
|
|
||||||
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
|
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
|
||||||
@ -1107,23 +1106,6 @@ class FFI {
|
|||||||
id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
|
id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List the saved peers.
|
|
||||||
Future<List<Peer>> peers() async {
|
|
||||||
try {
|
|
||||||
var str = await bind.mainGetRecentPeers();
|
|
||||||
if (str == '') return [];
|
|
||||||
List<dynamic> peers = json.decode(str);
|
|
||||||
return peers
|
|
||||||
.map((s) => s as List<dynamic>)
|
|
||||||
.map((s) =>
|
|
||||||
Peer.fromJson(s[0] as String, s[1] as Map<String, dynamic>))
|
|
||||||
.toList();
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('peers(): $e');
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Connect with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].
|
/// Connect with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].
|
||||||
connect(String id,
|
connect(String id,
|
||||||
{bool isFileTransfer = false,
|
{bool isFileTransfer = false,
|
||||||
|
@ -7,13 +7,16 @@ class Peer {
|
|||||||
final String username;
|
final String username;
|
||||||
final String hostname;
|
final String hostname;
|
||||||
final String platform;
|
final String platform;
|
||||||
|
final String alias;
|
||||||
final List<dynamic> tags;
|
final List<dynamic> tags;
|
||||||
bool online = false;
|
bool online = false;
|
||||||
|
|
||||||
Peer.fromJson(this.id, Map<String, dynamic> json)
|
Peer.fromJson(Map<String, dynamic> json)
|
||||||
: username = json['username'] ?? '',
|
: id = json['id'] ?? '',
|
||||||
|
username = json['username'] ?? '',
|
||||||
hostname = json['hostname'] ?? '',
|
hostname = json['hostname'] ?? '',
|
||||||
platform = json['platform'] ?? '',
|
platform = json['platform'] ?? '',
|
||||||
|
alias = json['alias'] ?? '',
|
||||||
tags = json['tags'] ?? [];
|
tags = json['tags'] ?? [];
|
||||||
|
|
||||||
Peer({
|
Peer({
|
||||||
@ -21,6 +24,7 @@ class Peer {
|
|||||||
required this.username,
|
required this.username,
|
||||||
required this.hostname,
|
required this.hostname,
|
||||||
required this.platform,
|
required this.platform,
|
||||||
|
required this.alias,
|
||||||
required this.tags,
|
required this.tags,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -30,6 +34,7 @@ class Peer {
|
|||||||
username: '...',
|
username: '...',
|
||||||
hostname: '...',
|
hostname: '...',
|
||||||
platform: '...',
|
platform: '...',
|
||||||
|
alias: '',
|
||||||
tags: []);
|
tags: []);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,11 +114,9 @@ class Peers extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
if (peersStr == "") return [];
|
if (peersStr == "") return [];
|
||||||
List<dynamic> peers = json.decode(peersStr);
|
List<dynamic> peers = json.decode(peersStr);
|
||||||
return peers
|
return peers.map((peer) {
|
||||||
.map((s) => s as List<dynamic>)
|
return Peer.fromJson(peer as Map<String, dynamic>);
|
||||||
.map((s) =>
|
}).toList();
|
||||||
Peer.fromJson(s[0] as String, s[1] as Map<String, dynamic>))
|
|
||||||
.toList();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('peers(): $e');
|
debugPrint('peers(): $e');
|
||||||
}
|
}
|
||||||
|
@ -379,8 +379,8 @@ pub mod connection_manager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_theme(&self, dark: bool) {
|
fn change_theme(&self, dark: String) {
|
||||||
self.push_event("theme", vec![("dark", &dark.to_string())]);
|
self.push_event("theme", vec![("dark", &dark)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_language(&self) {
|
fn change_language(&self) {
|
||||||
|
@ -7,11 +7,11 @@ use std::{
|
|||||||
use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
|
use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use hbb_common::ResultType;
|
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
config::{self, LocalConfig, PeerConfig, ONLINE},
|
config::{self, LocalConfig, PeerConfig, ONLINE},
|
||||||
fs, log,
|
fs, log,
|
||||||
};
|
};
|
||||||
|
use hbb_common::{message_proto::Hash, ResultType};
|
||||||
|
|
||||||
use crate::flutter::{self, SESSIONS};
|
use crate::flutter::{self, SESSIONS};
|
||||||
use crate::start_server;
|
use crate::start_server;
|
||||||
@ -567,9 +567,20 @@ pub fn main_forget_password(id: String) {
|
|||||||
|
|
||||||
pub fn main_get_recent_peers() -> String {
|
pub fn main_get_recent_peers() -> String {
|
||||||
if !config::APP_DIR.read().unwrap().is_empty() {
|
if !config::APP_DIR.read().unwrap().is_empty() {
|
||||||
let peers: Vec<(String, config::PeerInfoSerde)> = PeerConfig::peers()
|
let peers: Vec<HashMap<&str, String>> = PeerConfig::peers()
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|(id, _, p)| (id, p.info))
|
.map(|(id, _, p)| {
|
||||||
|
HashMap::<&str, String>::from_iter([
|
||||||
|
("id", id),
|
||||||
|
("username", p.info.username.clone()),
|
||||||
|
("hostname", p.info.hostname.clone()),
|
||||||
|
("platform", p.info.platform.clone()),
|
||||||
|
(
|
||||||
|
"alias",
|
||||||
|
p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
serde_json::ser::to_string(&peers).unwrap_or("".to_owned())
|
serde_json::ser::to_string(&peers).unwrap_or("".to_owned())
|
||||||
} else {
|
} else {
|
||||||
@ -579,9 +590,20 @@ pub fn main_get_recent_peers() -> String {
|
|||||||
|
|
||||||
pub fn main_load_recent_peers() {
|
pub fn main_load_recent_peers() {
|
||||||
if !config::APP_DIR.read().unwrap().is_empty() {
|
if !config::APP_DIR.read().unwrap().is_empty() {
|
||||||
let peers: Vec<(String, config::PeerInfoSerde)> = PeerConfig::peers()
|
let peers: Vec<HashMap<&str, String>> = PeerConfig::peers()
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|(id, _, p)| (id, p.info))
|
.map(|(id, _, p)| {
|
||||||
|
HashMap::<&str, String>::from_iter([
|
||||||
|
("id", id),
|
||||||
|
("username", p.info.username.clone()),
|
||||||
|
("hostname", p.info.hostname.clone()),
|
||||||
|
("platform", p.info.platform.clone()),
|
||||||
|
(
|
||||||
|
"alias",
|
||||||
|
p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(s) = flutter::GLOBAL_EVENT_STREAM
|
if let Some(s) = flutter::GLOBAL_EVENT_STREAM
|
||||||
.read()
|
.read()
|
||||||
@ -603,11 +625,20 @@ pub fn main_load_recent_peers() {
|
|||||||
pub fn main_load_fav_peers() {
|
pub fn main_load_fav_peers() {
|
||||||
if !config::APP_DIR.read().unwrap().is_empty() {
|
if !config::APP_DIR.read().unwrap().is_empty() {
|
||||||
let favs = get_fav();
|
let favs = get_fav();
|
||||||
let peers: Vec<(String, config::PeerInfoSerde)> = PeerConfig::peers()
|
let peers: Vec<HashMap<&str, String>> = PeerConfig::peers()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(id, _, peer)| {
|
.filter_map(|(id, _, p)| {
|
||||||
if favs.contains(&id) {
|
if favs.contains(&id) {
|
||||||
Some((id, peer.info))
|
Some(HashMap::<&str, String>::from_iter([
|
||||||
|
("id", id),
|
||||||
|
("username", p.info.username.clone()),
|
||||||
|
("hostname", p.info.hostname.clone()),
|
||||||
|
("platform", p.info.platform.clone()),
|
||||||
|
(
|
||||||
|
"alias",
|
||||||
|
p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(),
|
||||||
|
),
|
||||||
|
]))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -661,10 +692,10 @@ fn main_broadcast_message(data: &HashMap<&str, &str>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_change_theme(dark: bool) {
|
pub fn main_change_theme(dark: String) {
|
||||||
main_broadcast_message(&HashMap::from([
|
main_broadcast_message(&HashMap::from([
|
||||||
("name", "theme"),
|
("name", "theme"),
|
||||||
("dark", &dark.to_string()),
|
("dark", &dark),
|
||||||
]));
|
]));
|
||||||
send_to_cm(&crate::ipc::Data::Theme(dark));
|
send_to_cm(&crate::ipc::Data::Theme(dark));
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ pub enum Data {
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
|
||||||
Mouse(DataMouse),
|
Mouse(DataMouse),
|
||||||
Control(DataControl),
|
Control(DataControl),
|
||||||
Theme(bool),
|
Theme(String),
|
||||||
Language(String),
|
Language(String),
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
17
src/ui.rs
17
src/ui.rs
@ -18,7 +18,7 @@ use hbb_common::{
|
|||||||
tokio::{self, sync::mpsc, time},
|
tokio::{self, sync::mpsc, time},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::common::{get_app_name};
|
use crate::common::get_app_name;
|
||||||
use crate::ipc;
|
use crate::ipc;
|
||||||
use crate::ui_interface::{
|
use crate::ui_interface::{
|
||||||
check_mouse_time, closing, create_shortcut, current_is_wayland, fix_login_wayland,
|
check_mouse_time, closing, create_shortcut, current_is_wayland, fix_login_wayland,
|
||||||
@ -73,9 +73,7 @@ fn check_connect_status(
|
|||||||
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
|
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
|
||||||
let password = Arc::new(Mutex::new(String::default()));
|
let password = Arc::new(Mutex::new(String::default()));
|
||||||
let cloned_password = password.clone();
|
let cloned_password = password.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || crate::ui_interface::check_connect_status_(reconnect, rx));
|
||||||
crate::ui_interface::check_connect_status_(reconnect, rx)
|
|
||||||
});
|
|
||||||
(status, options, tx, password)
|
(status, options, tx, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,9 +523,16 @@ impl UI {
|
|||||||
fn get_lan_peers(&self) -> String {
|
fn get_lan_peers(&self) -> String {
|
||||||
let peers = get_lan_peers()
|
let peers = get_lan_peers()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, peer)| (id, peer.username, peer.hostname, peer.platform))
|
.map(|mut peer| {
|
||||||
|
(
|
||||||
|
peer.remove("id").unwrap_or_default(),
|
||||||
|
peer.remove("username").unwrap_or_default(),
|
||||||
|
peer.remove("hostname").unwrap_or_default(),
|
||||||
|
peer.remove("platform").unwrap_or_default(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect::<Vec<(String, String, String, String)>>();
|
.collect::<Vec<(String, String, String, String)>>();
|
||||||
serde_json::to_string(&peers).unwrap_or_default()
|
serde_json::to_string(&get_lan_peers()).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_uuid(&self) -> String {
|
fn get_uuid(&self) -> String {
|
||||||
|
@ -48,7 +48,7 @@ impl InvokeUiCM for SciterHandler {
|
|||||||
self.call("newMessage", &make_args!(id, text));
|
self.call("newMessage", &make_args!(id, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_theme(&self, _dark: bool) {
|
fn change_theme(&self, _dark: String) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ pub trait InvokeUiCM: Send + Clone + 'static + Sized {
|
|||||||
|
|
||||||
fn new_message(&self, id: i32, text: String);
|
fn new_message(&self, id: i32, text: String);
|
||||||
|
|
||||||
fn change_theme(&self, dark: bool);
|
fn change_theme(&self, dark: String);
|
||||||
|
|
||||||
fn change_language(&self);
|
fn change_language(&self);
|
||||||
}
|
}
|
||||||
|
@ -648,19 +648,17 @@ pub fn discover() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_lan_peers() -> Vec<(String, config::PeerInfoSerde)> {
|
pub fn get_lan_peers() -> Vec<HashMap<&'static str, String>> {
|
||||||
config::LanPeers::load()
|
config::LanPeers::load()
|
||||||
.peers
|
.peers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|peer| {
|
.map(|peer| {
|
||||||
(
|
HashMap::<&str, String>::from_iter([
|
||||||
peer.id.clone(),
|
("id", peer.id.clone()),
|
||||||
config::PeerInfoSerde {
|
("username", peer.username.clone()),
|
||||||
username: peer.username.clone(),
|
("hostname", peer.hostname.clone()),
|
||||||
hostname: peer.hostname.clone(),
|
("platform", peer.platform.clone()),
|
||||||
platform: peer.platform.clone(),
|
])
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user