mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-05-11 10:26:19 +02:00
refact: web ui (#9217)
* refact: web ui Signed-off-by: fufesou <linlong1266@gmail.com> * refact: remove AppBar shadow Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
bf390611ab
commit
ae339f039d
6 changed files with 188 additions and 126 deletions
|
@ -350,6 +350,9 @@ class MyTheme {
|
||||||
hoverColor: Color.fromARGB(255, 224, 224, 224),
|
hoverColor: Color.fromARGB(255, 224, 224, 224),
|
||||||
scaffoldBackgroundColor: Colors.white,
|
scaffoldBackgroundColor: Colors.white,
|
||||||
dialogBackgroundColor: Colors.white,
|
dialogBackgroundColor: Colors.white,
|
||||||
|
appBarTheme: AppBarTheme(
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
),
|
||||||
dialogTheme: DialogTheme(
|
dialogTheme: DialogTheme(
|
||||||
elevation: 15,
|
elevation: 15,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
|
@ -445,6 +448,9 @@ class MyTheme {
|
||||||
hoverColor: Color.fromARGB(255, 45, 46, 53),
|
hoverColor: Color.fromARGB(255, 45, 46, 53),
|
||||||
scaffoldBackgroundColor: Color(0xFF18191E),
|
scaffoldBackgroundColor: Color(0xFF18191E),
|
||||||
dialogBackgroundColor: Color(0xFF18191E),
|
dialogBackgroundColor: Color(0xFF18191E),
|
||||||
|
appBarTheme: AppBarTheme(
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
),
|
||||||
dialogTheme: DialogTheme(
|
dialogTheme: DialogTheme(
|
||||||
elevation: 15,
|
elevation: 15,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
|
@ -550,7 +556,7 @@ class MyTheme {
|
||||||
|
|
||||||
static void changeDarkMode(ThemeMode mode) async {
|
static void changeDarkMode(ThemeMode mode) async {
|
||||||
Get.changeThemeMode(mode);
|
Get.changeThemeMode(mode);
|
||||||
if (desktopType == DesktopType.main || isAndroid || isIOS) {
|
if (desktopType == DesktopType.main || isAndroid || isIOS || isWeb) {
|
||||||
if (mode == ThemeMode.system) {
|
if (mode == ThemeMode.system) {
|
||||||
await bind.mainSetLocalOption(
|
await bind.mainSetLocalOption(
|
||||||
key: kCommConfKeyTheme, value: defaultOptionTheme);
|
key: kCommConfKeyTheme, value: defaultOptionTheme);
|
||||||
|
@ -558,7 +564,7 @@ class MyTheme {
|
||||||
await bind.mainSetLocalOption(
|
await bind.mainSetLocalOption(
|
||||||
key: kCommConfKeyTheme, value: mode.toShortString());
|
key: kCommConfKeyTheme, value: mode.toShortString());
|
||||||
}
|
}
|
||||||
await bind.mainChangeTheme(dark: mode.toShortString());
|
if (!isWeb) await bind.mainChangeTheme(dark: mode.toShortString());
|
||||||
// Synchronize the window theme of the system.
|
// Synchronize the window theme of the system.
|
||||||
updateSystemWindowTheme();
|
updateSystemWindowTheme();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,8 @@ class DesktopSettingPage extends StatefulWidget {
|
||||||
final SettingsTabKey initialTabkey;
|
final SettingsTabKey initialTabkey;
|
||||||
static final List<SettingsTabKey> tabKeys = [
|
static final List<SettingsTabKey> tabKeys = [
|
||||||
SettingsTabKey.general,
|
SettingsTabKey.general,
|
||||||
if (!bind.isOutgoingOnly() &&
|
if (!isWeb &&
|
||||||
|
!bind.isOutgoingOnly() &&
|
||||||
!bind.isDisableSettings() &&
|
!bind.isDisableSettings() &&
|
||||||
bind.mainGetBuildinOption(key: kOptionHideSecuritySetting) != 'Y')
|
bind.mainGetBuildinOption(key: kOptionHideSecuritySetting) != 'Y')
|
||||||
SettingsTabKey.safety,
|
SettingsTabKey.safety,
|
||||||
|
@ -216,7 +217,7 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
|
||||||
width: _kTabWidth,
|
width: _kTabWidth,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_header(),
|
_header(context),
|
||||||
Flexible(child: _listView(tabs: _settingTabs())),
|
Flexible(child: _listView(tabs: _settingTabs())),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -239,21 +240,40 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _header() {
|
Widget _header(BuildContext context) {
|
||||||
|
final settingsText = Text(
|
||||||
|
translate('Settings'),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: _accentColor,
|
||||||
|
fontSize: _kTitleFontSize,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
);
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
if (isWeb)
|
||||||
height: 62,
|
IconButton(
|
||||||
child: Text(
|
onPressed: () {
|
||||||
translate('Settings'),
|
if (Navigator.canPop(context)) {
|
||||||
textAlign: TextAlign.left,
|
Navigator.pop(context);
|
||||||
style: const TextStyle(
|
}
|
||||||
color: _accentColor,
|
},
|
||||||
fontSize: _kTitleFontSize,
|
icon: Icon(Icons.arrow_back),
|
||||||
fontWeight: FontWeight.w400,
|
).marginOnly(left: 5),
|
||||||
|
if (isWeb)
|
||||||
|
SizedBox(
|
||||||
|
height: 62,
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: settingsText,
|
||||||
),
|
),
|
||||||
),
|
).marginOnly(left: 20),
|
||||||
).marginOnly(left: 20, top: 10),
|
if (!isWeb)
|
||||||
|
SizedBox(
|
||||||
|
height: 62,
|
||||||
|
child: settingsText,
|
||||||
|
).marginOnly(left: 20, top: 10),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -322,7 +342,8 @@ class _General extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GeneralState extends State<_General> {
|
class _GeneralState extends State<_General> {
|
||||||
final RxBool serviceStop = Get.find<RxBool>(tag: 'stop-service');
|
final RxBool serviceStop =
|
||||||
|
isWeb ? RxBool(false) : Get.find<RxBool>(tag: 'stop-service');
|
||||||
RxBool serviceBtnEnabled = true.obs;
|
RxBool serviceBtnEnabled = true.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -334,13 +355,13 @@ class _GeneralState extends State<_General> {
|
||||||
physics: DraggableNeverScrollableScrollPhysics(),
|
physics: DraggableNeverScrollableScrollPhysics(),
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
children: [
|
children: [
|
||||||
service(),
|
if (!isWeb) service(),
|
||||||
theme(),
|
theme(),
|
||||||
_Card(title: 'Language', children: [language()]),
|
_Card(title: 'Language', children: [language()]),
|
||||||
hwcodec(),
|
if (!isWeb) hwcodec(),
|
||||||
audio(context),
|
if (!isWeb) audio(context),
|
||||||
record(context),
|
if (!isWeb) record(context),
|
||||||
WaylandCard(),
|
if (!isWeb) WaylandCard(),
|
||||||
other()
|
other()
|
||||||
],
|
],
|
||||||
).marginOnly(bottom: _kListViewBottomMargin));
|
).marginOnly(bottom: _kListViewBottomMargin));
|
||||||
|
@ -394,13 +415,13 @@ class _GeneralState extends State<_General> {
|
||||||
|
|
||||||
Widget other() {
|
Widget other() {
|
||||||
final children = <Widget>[
|
final children = <Widget>[
|
||||||
if (!bind.isIncomingOnly())
|
if (!isWeb && !bind.isIncomingOnly())
|
||||||
_OptionCheckBox(context, 'Confirm before closing multiple tabs',
|
_OptionCheckBox(context, 'Confirm before closing multiple tabs',
|
||||||
kOptionEnableConfirmClosingTabs,
|
kOptionEnableConfirmClosingTabs,
|
||||||
isServer: false),
|
isServer: false),
|
||||||
_OptionCheckBox(context, 'Adaptive bitrate', kOptionEnableAbr),
|
_OptionCheckBox(context, 'Adaptive bitrate', kOptionEnableAbr),
|
||||||
wallpaper(),
|
if (!isWeb) wallpaper(),
|
||||||
if (!bind.isIncomingOnly()) ...[
|
if (!isWeb && !bind.isIncomingOnly()) ...[
|
||||||
_OptionCheckBox(
|
_OptionCheckBox(
|
||||||
context,
|
context,
|
||||||
'Open connection in new tab',
|
'Open connection in new tab',
|
||||||
|
@ -417,18 +438,19 @@ class _GeneralState extends State<_General> {
|
||||||
kOptionAllowAlwaysSoftwareRender,
|
kOptionAllowAlwaysSoftwareRender,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Tooltip(
|
if (!isWeb)
|
||||||
message: translate('texture_render_tip'),
|
Tooltip(
|
||||||
child: _OptionCheckBox(
|
message: translate('texture_render_tip'),
|
||||||
context,
|
child: _OptionCheckBox(
|
||||||
"Use texture rendering",
|
context,
|
||||||
kOptionTextureRender,
|
"Use texture rendering",
|
||||||
optGetter: bind.mainGetUseTextureRender,
|
kOptionTextureRender,
|
||||||
optSetter: (k, v) async =>
|
optGetter: bind.mainGetUseTextureRender,
|
||||||
await bind.mainSetLocalOption(key: k, value: v ? 'Y' : 'N'),
|
optSetter: (k, v) async =>
|
||||||
|
await bind.mainSetLocalOption(key: k, value: v ? 'Y' : 'N'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (!isWeb && !bind.isCustomClient())
|
||||||
if (!bind.isCustomClient())
|
|
||||||
_OptionCheckBox(
|
_OptionCheckBox(
|
||||||
context,
|
context,
|
||||||
'Check for software update on startup',
|
'Check for software update on startup',
|
||||||
|
@ -443,7 +465,7 @@ class _GeneralState extends State<_General> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
if (bind.mainShowOption(key: kOptionAllowLinuxHeadless)) {
|
if (!isWeb && bind.mainShowOption(key: kOptionAllowLinuxHeadless)) {
|
||||||
children.add(_OptionCheckBox(
|
children.add(_OptionCheckBox(
|
||||||
context, 'Allow linux headless', kOptionAllowLinuxHeadless));
|
context, 'Allow linux headless', kOptionAllowLinuxHeadless));
|
||||||
}
|
}
|
||||||
|
@ -641,8 +663,9 @@ class _GeneralState extends State<_General> {
|
||||||
initialKey: currentKey,
|
initialKey: currentKey,
|
||||||
onChanged: (key) async {
|
onChanged: (key) async {
|
||||||
await bind.mainSetLocalOption(key: kCommConfKeyLang, value: key);
|
await bind.mainSetLocalOption(key: kCommConfKeyLang, value: key);
|
||||||
reloadAllWindows();
|
if (isWeb) reloadCurrentWindow();
|
||||||
bind.mainChangeLanguage(lang: key);
|
if (!isWeb) reloadAllWindows();
|
||||||
|
if (!isWeb) bind.mainChangeLanguage(lang: key);
|
||||||
},
|
},
|
||||||
enabled: !isOptFixed,
|
enabled: !isOptFixed,
|
||||||
).marginOnly(left: _kContentHMargin);
|
).marginOnly(left: _kContentHMargin);
|
||||||
|
@ -1337,7 +1360,7 @@ class _Network extends StatefulWidget {
|
||||||
class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
|
class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
|
||||||
@override
|
@override
|
||||||
bool get wantKeepAlive => true;
|
bool get wantKeepAlive => true;
|
||||||
bool locked = bind.mainIsInstalled();
|
bool locked = !isWeb && bind.mainIsInstalled();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -1346,8 +1369,9 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
|
||||||
final scrollController = ScrollController();
|
final scrollController = ScrollController();
|
||||||
final hideServer =
|
final hideServer =
|
||||||
bind.mainGetBuildinOption(key: kOptionHideServerSetting) == 'Y';
|
bind.mainGetBuildinOption(key: kOptionHideServerSetting) == 'Y';
|
||||||
|
// TODO: support web proxy
|
||||||
final hideProxy =
|
final hideProxy =
|
||||||
bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y';
|
isWeb || bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y';
|
||||||
return DesktopScrollWrapper(
|
return DesktopScrollWrapper(
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
|
@ -1467,7 +1491,7 @@ class _DisplayState extends State<_Display> {
|
||||||
scrollStyle(context),
|
scrollStyle(context),
|
||||||
imageQuality(context),
|
imageQuality(context),
|
||||||
codec(context),
|
codec(context),
|
||||||
privacyModeImpl(context),
|
if (!isWeb) privacyModeImpl(context),
|
||||||
other(context),
|
other(context),
|
||||||
]).marginOnly(bottom: _kListViewBottomMargin));
|
]).marginOnly(bottom: _kListViewBottomMargin));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,16 @@ import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:flutter_hbb/models/peer_model.dart';
|
import 'package:flutter_hbb/models/peer_model.dart';
|
||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../common/widgets/login.dart';
|
|
||||||
import '../../common/widgets/peer_tab_page.dart';
|
import '../../common/widgets/peer_tab_page.dart';
|
||||||
import '../../common/widgets/autocomplete.dart';
|
import '../../common/widgets/autocomplete.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 'scan_page.dart';
|
|
||||||
import 'settings_page.dart';
|
|
||||||
|
|
||||||
/// Connection page for connecting to a remote peer.
|
/// Connection page for connecting to a remote peer.
|
||||||
class ConnectionPage extends StatefulWidget implements PageShape {
|
class ConnectionPage extends StatefulWidget implements PageShape {
|
||||||
ConnectionPage({Key? key}) : super(key: key);
|
ConnectionPage({Key? key, required this.appBarActions}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final icon = const Icon(Icons.connected_tv);
|
final icon = const Icon(Icons.connected_tv);
|
||||||
|
@ -30,7 +27,7 @@ class ConnectionPage extends StatefulWidget implements PageShape {
|
||||||
final title = translate("Connection");
|
final title = translate("Connection");
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final appBarActions = isWeb ? <Widget>[const WebMenu()] : <Widget>[];
|
final List<Widget> appBarActions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ConnectionPage> createState() => _ConnectionPageState();
|
State<ConnectionPage> createState() => _ConnectionPageState();
|
||||||
|
@ -356,73 +353,3 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebMenu extends StatefulWidget {
|
|
||||||
const WebMenu({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<WebMenu> createState() => _WebMenuState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebMenuState extends State<WebMenu> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Provider.of<FfiModel>(context);
|
|
||||||
return PopupMenuButton<String>(
|
|
||||||
tooltip: "",
|
|
||||||
icon: const Icon(Icons.more_vert),
|
|
||||||
itemBuilder: (context) {
|
|
||||||
return (isIOS
|
|
||||||
? [
|
|
||||||
const PopupMenuItem(
|
|
||||||
value: "scan",
|
|
||||||
child: Icon(Icons.qr_code_scanner, color: Colors.black),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
: <PopupMenuItem<String>>[]) +
|
|
||||||
[
|
|
||||||
PopupMenuItem(
|
|
||||||
value: "server",
|
|
||||||
child: Text(translate('ID/Relay Server')),
|
|
||||||
)
|
|
||||||
] +
|
|
||||||
[
|
|
||||||
PopupMenuItem(
|
|
||||||
value: "login",
|
|
||||||
child: Text(gFFI.userModel.userName.value.isEmpty
|
|
||||||
? translate("Login")
|
|
||||||
: '${translate("Logout")} (${gFFI.userModel.userName.value})'),
|
|
||||||
)
|
|
||||||
] +
|
|
||||||
[
|
|
||||||
PopupMenuItem(
|
|
||||||
value: "about",
|
|
||||||
child: Text(translate('About RustDesk')),
|
|
||||||
)
|
|
||||||
];
|
|
||||||
},
|
|
||||||
onSelected: (value) {
|
|
||||||
if (value == 'server') {
|
|
||||||
showServerSettings(gFFI.dialogManager);
|
|
||||||
}
|
|
||||||
if (value == 'about') {
|
|
||||||
showAbout(gFFI.dialogManager);
|
|
||||||
}
|
|
||||||
if (value == 'login') {
|
|
||||||
if (gFFI.userModel.userName.value.isEmpty) {
|
|
||||||
loginDialog();
|
|
||||||
} else {
|
|
||||||
logOutConfirmDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (value == 'scan') {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (BuildContext context) => ScanPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/mobile/pages/server_page.dart';
|
import 'package:flutter_hbb/mobile/pages/server_page.dart';
|
||||||
import 'package:flutter_hbb/mobile/pages/settings_page.dart';
|
import 'package:flutter_hbb/mobile/pages/settings_page.dart';
|
||||||
|
import 'package:flutter_hbb/web/settings_page.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../common/widgets/chat_page.dart';
|
import '../../common/widgets/chat_page.dart';
|
||||||
|
@ -45,7 +46,10 @@ class HomePageState extends State<HomePage> {
|
||||||
|
|
||||||
void initPages() {
|
void initPages() {
|
||||||
_pages.clear();
|
_pages.clear();
|
||||||
if (!bind.isIncomingOnly()) _pages.add(ConnectionPage());
|
if (!bind.isIncomingOnly())
|
||||||
|
_pages.add(ConnectionPage(
|
||||||
|
appBarActions: [],
|
||||||
|
));
|
||||||
if (isAndroid && !bind.isOutgoingOnly()) {
|
if (isAndroid && !bind.isOutgoingOnly()) {
|
||||||
_chatPageTabIndex = _pages.length;
|
_chatPageTabIndex = _pages.length;
|
||||||
_pages.addAll([ChatPage(type: ChatPageType.mobileMain), ServerPage()]);
|
_pages.addAll([ChatPage(type: ChatPageType.mobileMain), ServerPage()]);
|
||||||
|
@ -149,7 +153,8 @@ class HomePageState extends State<HomePage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebHomePage extends StatelessWidget {
|
class WebHomePage extends StatelessWidget {
|
||||||
final connectionPage = ConnectionPage();
|
final connectionPage =
|
||||||
|
ConnectionPage(appBarActions: <Widget>[const WebSettingsPage()]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -736,7 +736,8 @@ class RustdeskImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mainGetLicense({dynamic hint}) {
|
Future<String> mainGetLicense({dynamic hint}) {
|
||||||
throw UnimplementedError();
|
// TODO: implement
|
||||||
|
return Future(() => '');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mainGetVersion({dynamic hint}) {
|
Future<String> mainGetVersion({dynamic hint}) {
|
||||||
|
@ -975,10 +976,11 @@ class RustdeskImpl {
|
||||||
|
|
||||||
Future<void> mainSetUserDefaultOption(
|
Future<void> mainSetUserDefaultOption(
|
||||||
{required String key, required String value, dynamic hint}) {
|
{required String key, required String value, dynamic hint}) {
|
||||||
return js.context.callMethod('getByName', [
|
js.context.callMethod('setByName', [
|
||||||
'option:user:default',
|
'option:user:default',
|
||||||
jsonEncode({'name': key, 'value': value})
|
jsonEncode({'name': key, 'value': value})
|
||||||
]);
|
]);
|
||||||
|
return Future.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
String mainGetUserDefaultOption({required String key, dynamic hint}) {
|
String mainGetUserDefaultOption({required String key, dynamic hint}) {
|
||||||
|
@ -1052,7 +1054,7 @@ class RustdeskImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mainGetLangs({dynamic hint}) {
|
Future<String> mainGetLangs({dynamic hint}) {
|
||||||
throw UnimplementedError();
|
return Future(() => js.context.callMethod('getByName', ['langs']));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mainGetTemporaryPassword({dynamic hint}) {
|
Future<String> mainGetTemporaryPassword({dynamic hint}) {
|
||||||
|
@ -1064,7 +1066,8 @@ class RustdeskImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mainGetFingerprint({dynamic hint}) {
|
Future<String> mainGetFingerprint({dynamic hint}) {
|
||||||
throw UnimplementedError();
|
// TODO: implement
|
||||||
|
return Future.value('');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> cmGetClientsState({dynamic hint}) {
|
Future<String> cmGetClientsState({dynamic hint}) {
|
||||||
|
@ -1106,7 +1109,7 @@ class RustdeskImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
String mainSupportedHwdecodings({dynamic hint}) {
|
String mainSupportedHwdecodings({dynamic hint}) {
|
||||||
throw UnimplementedError();
|
return '{}';
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> mainIsRoot({dynamic hint}) {
|
Future<bool> mainIsRoot({dynamic hint}) {
|
||||||
|
@ -1295,8 +1298,7 @@ class RustdeskImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mainGetBuildDate({dynamic hint}) {
|
Future<String> mainGetBuildDate({dynamic hint}) {
|
||||||
// TODO
|
return Future(() => js.context.callMethod('getByName', ['build_date']));
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String translate(
|
String translate(
|
||||||
|
|
98
flutter/lib/web/settings_page.dart
Normal file
98
flutter/lib/web/settings_page.dart
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
|
||||||
|
import 'package:flutter_hbb/mobile/pages/scan_page.dart';
|
||||||
|
import 'package:flutter_hbb/mobile/pages/settings_page.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../common.dart';
|
||||||
|
import '../../common/widgets/login.dart';
|
||||||
|
import '../../models/model.dart';
|
||||||
|
|
||||||
|
class WebSettingsPage extends StatelessWidget {
|
||||||
|
const WebSettingsPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (isWebDesktop) {
|
||||||
|
return _buildDesktopButton(context);
|
||||||
|
} else {
|
||||||
|
return _buildMobileMenu(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDesktopButton(BuildContext context) {
|
||||||
|
return IconButton(
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (BuildContext context) =>
|
||||||
|
DesktopSettingPage(initialTabkey: SettingsTabKey.general),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMobileMenu(BuildContext context) {
|
||||||
|
Provider.of<FfiModel>(context);
|
||||||
|
return PopupMenuButton<String>(
|
||||||
|
tooltip: "",
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
itemBuilder: (context) {
|
||||||
|
return (isIOS
|
||||||
|
? [
|
||||||
|
const PopupMenuItem(
|
||||||
|
value: "scan",
|
||||||
|
child: Icon(Icons.qr_code_scanner, color: Colors.black),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
: <PopupMenuItem<String>>[]) +
|
||||||
|
[
|
||||||
|
PopupMenuItem(
|
||||||
|
value: "server",
|
||||||
|
child: Text(translate('ID/Relay Server')),
|
||||||
|
)
|
||||||
|
] +
|
||||||
|
[
|
||||||
|
PopupMenuItem(
|
||||||
|
value: "login",
|
||||||
|
child: Text(gFFI.userModel.userName.value.isEmpty
|
||||||
|
? translate("Login")
|
||||||
|
: '${translate("Logout")} (${gFFI.userModel.userName.value})'),
|
||||||
|
)
|
||||||
|
] +
|
||||||
|
[
|
||||||
|
PopupMenuItem(
|
||||||
|
value: "about",
|
||||||
|
child: Text(translate('About RustDesk')),
|
||||||
|
)
|
||||||
|
];
|
||||||
|
},
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value == 'server') {
|
||||||
|
showServerSettings(gFFI.dialogManager);
|
||||||
|
}
|
||||||
|
if (value == 'about') {
|
||||||
|
showAbout(gFFI.dialogManager);
|
||||||
|
}
|
||||||
|
if (value == 'login') {
|
||||||
|
if (gFFI.userModel.userName.value.isEmpty) {
|
||||||
|
loginDialog();
|
||||||
|
} else {
|
||||||
|
logOutConfirmDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value == 'scan') {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (BuildContext context) => ScanPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue