mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk
This commit is contained in:
74
flutter/lib/common/widgets/dialog.dart
Normal file
74
flutter/lib/common/widgets/dialog.dart
Normal file
@@ -0,0 +1,74 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
|
||||
void changeIdDialog() {
|
||||
var newId = "";
|
||||
var msg = "";
|
||||
var isInProgress = false;
|
||||
TextEditingController controller = TextEditingController();
|
||||
gFFI.dialogManager.show((setState, close) {
|
||||
submit() async {
|
||||
debugPrint("onSubmit");
|
||||
newId = controller.text.trim();
|
||||
setState(() {
|
||||
msg = "";
|
||||
isInProgress = true;
|
||||
bind.mainChangeId(newId: newId);
|
||||
});
|
||||
|
||||
var status = await bind.mainGetAsyncStatus();
|
||||
while (status == " ") {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
status = await bind.mainGetAsyncStatus();
|
||||
}
|
||||
if (status.isEmpty) {
|
||||
// ok
|
||||
close();
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
isInProgress = false;
|
||||
msg = translate(status);
|
||||
});
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Change ID")),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(translate("id_change_tip")),
|
||||
const SizedBox(
|
||||
height: 12.0,
|
||||
),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: msg.isEmpty ? null : translate(msg)),
|
||||
inputFormatters: [
|
||||
LengthLimitingTextInputFormatter(16),
|
||||
// FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
|
||||
],
|
||||
maxLength: 16,
|
||||
controller: controller,
|
||||
focusNode: FocusNode()..requestFocus(),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
Offstage(
|
||||
offstage: !isInProgress, child: const LinearProgressIndicator())
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: close, child: Text(translate("Cancel"))),
|
||||
TextButton(onPressed: submit, child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import 'package:tray_manager/tray_manager.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../../common/widgets/dialog.dart';
|
||||
|
||||
class _MenubarTheme {
|
||||
static const Color commonColor = MyTheme.accent;
|
||||
// kMinInteractiveDimension
|
||||
|
||||
@@ -11,6 +11,8 @@ import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
import '../../common/widgets/dialog.dart';
|
||||
|
||||
const double _kTabWidth = 235;
|
||||
const double _kTabHeight = 42;
|
||||
const double _kCardFixedWidth = 560;
|
||||
@@ -219,17 +221,12 @@ class _GeneralState extends State<_General> {
|
||||
}
|
||||
|
||||
Widget hwcodec() {
|
||||
return _futureBuilder(
|
||||
future: bind.mainHasHwcodec(),
|
||||
hasData: (data) {
|
||||
return Offstage(
|
||||
offstage: !(data as bool),
|
||||
child: _Card(title: 'Hardware Codec', children: [
|
||||
_OptionCheckBox(
|
||||
context, 'Enable hardware codec', 'enable-hwcodec'),
|
||||
]),
|
||||
);
|
||||
});
|
||||
return Offstage(
|
||||
offstage: !bind.mainHasHwcodec(),
|
||||
child: _Card(title: 'Hardware Codec', children: [
|
||||
_OptionCheckBox(context, 'Enable hardware codec', 'enable-hwcodec'),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
Widget audio(BuildContext context) {
|
||||
@@ -1501,82 +1498,4 @@ void changeSocks5Proxy() async {
|
||||
});
|
||||
}
|
||||
|
||||
void changeIdDialog() {
|
||||
var newId = "";
|
||||
var msg = "";
|
||||
var isInProgress = false;
|
||||
TextEditingController controller = TextEditingController();
|
||||
gFFI.dialogManager.show((setState, close) {
|
||||
submit() async {
|
||||
newId = controller.text.trim();
|
||||
setState(() {
|
||||
msg = "";
|
||||
isInProgress = true;
|
||||
bind.mainChangeId(newId: newId);
|
||||
});
|
||||
|
||||
var status = await bind.mainGetAsyncStatus();
|
||||
while (status == " ") {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
status = await bind.mainGetAsyncStatus();
|
||||
}
|
||||
if (status.isEmpty) {
|
||||
// ok
|
||||
close();
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
isInProgress = false;
|
||||
msg = translate(status);
|
||||
});
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Change ID")),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(translate("id_change_tip")),
|
||||
const SizedBox(
|
||||
height: 8.0,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Text("ID:").marginOnly(bottom: 16.0),
|
||||
const SizedBox(
|
||||
width: 24.0,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: msg.isEmpty ? null : translate(msg)),
|
||||
inputFormatters: [
|
||||
LengthLimitingTextInputFormatter(16),
|
||||
// FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
|
||||
],
|
||||
maxLength: 16,
|
||||
controller: controller,
|
||||
focusNode: FocusNode()..requestFocus(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
Offstage(
|
||||
offstage: !isInProgress, child: const LinearProgressIndicator())
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: close, child: Text(translate("Cancel"))),
|
||||
TextButton(onPressed: submit, child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
||||
@@ -298,25 +299,35 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
}
|
||||
|
||||
Widget _buildDisplay(BuildContext context) {
|
||||
return mod_menu.PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(
|
||||
Icons.tv,
|
||||
color: _MenubarTheme.commonColor,
|
||||
),
|
||||
tooltip: translate('Display Settings'),
|
||||
position: mod_menu.PopupMenuPosition.under,
|
||||
itemBuilder: (BuildContext context) => _getDisplayMenu()
|
||||
.map((entry) => entry.build(
|
||||
context,
|
||||
const MenuConfig(
|
||||
commonColor: _MenubarTheme.commonColor,
|
||||
height: _MenubarTheme.height,
|
||||
dividerHeight: _MenubarTheme.dividerHeight,
|
||||
)))
|
||||
.expand((i) => i)
|
||||
.toList(),
|
||||
);
|
||||
return FutureBuilder(future: () async {
|
||||
final supportedHwcodec =
|
||||
await bind.sessionSupportedHwcodec(id: widget.id);
|
||||
return {'supportedHwcodec': supportedHwcodec};
|
||||
}(), builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return mod_menu.PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(
|
||||
Icons.tv,
|
||||
color: _MenubarTheme.commonColor,
|
||||
),
|
||||
tooltip: translate('Display Settings'),
|
||||
position: mod_menu.PopupMenuPosition.under,
|
||||
itemBuilder: (BuildContext context) => _getDisplayMenu(snapshot.data!)
|
||||
.map((entry) => entry.build(
|
||||
context,
|
||||
const MenuConfig(
|
||||
commonColor: _MenubarTheme.commonColor,
|
||||
height: _MenubarTheme.height,
|
||||
dividerHeight: _MenubarTheme.dividerHeight,
|
||||
)))
|
||||
.expand((i) => i)
|
||||
.toList(),
|
||||
);
|
||||
} else {
|
||||
return const Offstage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildKeyboard(BuildContext context) {
|
||||
@@ -532,7 +543,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
return displayMenu;
|
||||
}
|
||||
|
||||
List<MenuEntryBase<String>> _getDisplayMenu() {
|
||||
List<MenuEntryBase<String>> _getDisplayMenu(dynamic futureData) {
|
||||
final displayMenu = [
|
||||
MenuEntryRadios<String>(
|
||||
text: translate('Ratio'),
|
||||
@@ -653,33 +664,74 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
}
|
||||
}),
|
||||
MenuEntryDivider<String>(),
|
||||
// {show_codec ? <div>
|
||||
// MenuEntryDivider<String>(),
|
||||
() {
|
||||
final state = ShowRemoteCursorState.find(widget.id);
|
||||
return MenuEntrySwitch2<String>(
|
||||
text: translate('Show remote cursor'),
|
||||
getter: () {
|
||||
return state;
|
||||
];
|
||||
|
||||
/// Show Codec Preference
|
||||
if (bind.mainHasHwcodec()) {
|
||||
final List<bool> codecs = [];
|
||||
try {
|
||||
final Map codecsJson = jsonDecode(futureData['supportedHwcodec']);
|
||||
final h264 = codecsJson['h264'] ?? false;
|
||||
final h265 = codecsJson['h265'] ?? false;
|
||||
codecs.add(h264);
|
||||
codecs.add(h265);
|
||||
} finally {}
|
||||
if (codecs.length == 2 && (codecs[0] || codecs[1])) {
|
||||
displayMenu.add(MenuEntryRadios<String>(
|
||||
text: translate('Codec Preference'),
|
||||
optionsGetter: () {
|
||||
final list = [
|
||||
MenuEntryRadioOption(text: translate('Auto'), value: 'auto'),
|
||||
MenuEntryRadioOption(text: 'VP9', value: 'vp9'),
|
||||
];
|
||||
if (codecs[0]) {
|
||||
list.add(MenuEntryRadioOption(text: 'H264', value: 'h264'));
|
||||
}
|
||||
if (codecs[1]) {
|
||||
list.add(MenuEntryRadioOption(text: 'H265', value: 'h265'));
|
||||
}
|
||||
return list;
|
||||
},
|
||||
setter: (bool v) async {
|
||||
state.value = v;
|
||||
await bind.sessionToggleOption(
|
||||
id: widget.id, value: 'show-remote-cursor');
|
||||
});
|
||||
}(),
|
||||
MenuEntrySwitch<String>(
|
||||
text: translate('Show quality monitor'),
|
||||
getter: () async {
|
||||
return bind.sessionGetToggleOptionSync(
|
||||
id: widget.id, arg: 'show-quality-monitor');
|
||||
curOptionGetter: () async {
|
||||
return await bind.sessionGetOption(
|
||||
id: widget.id, arg: 'codec-preference') ??
|
||||
'auto';
|
||||
},
|
||||
optionSetter: (String oldValue, String newValue) async {
|
||||
await bind.sessionPeerOption(
|
||||
id: widget.id, name: "codec-preference", value: newValue);
|
||||
bind.sessionChangePreferCodec(id: widget.id);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// Show remote cursor
|
||||
displayMenu.add(() {
|
||||
final state = ShowRemoteCursorState.find(widget.id);
|
||||
return MenuEntrySwitch2<String>(
|
||||
text: translate('Show remote cursor'),
|
||||
getter: () {
|
||||
return state;
|
||||
},
|
||||
setter: (bool v) async {
|
||||
state.value = v;
|
||||
await bind.sessionToggleOption(
|
||||
id: widget.id, value: 'show-quality-monitor');
|
||||
widget.ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
||||
}),
|
||||
];
|
||||
id: widget.id, value: 'show-remote-cursor');
|
||||
});
|
||||
}());
|
||||
|
||||
/// Show quality monitor
|
||||
displayMenu.add(MenuEntrySwitch<String>(
|
||||
text: translate('Show quality monitor'),
|
||||
getter: () async {
|
||||
return bind.sessionGetToggleOptionSync(
|
||||
id: widget.id, arg: 'show-quality-monitor');
|
||||
},
|
||||
setter: (bool v) async {
|
||||
await bind.sessionToggleOption(
|
||||
id: widget.id, value: 'show-quality-monitor');
|
||||
widget.ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
||||
}));
|
||||
|
||||
final perms = widget.ffi.ffiModel.permissions;
|
||||
final pi = widget.ffi.ffiModel.pi;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
@@ -1011,17 +1012,22 @@ class QualityMonitor extends StatelessWidget {
|
||||
void showOptions(String id, OverlayDialogManager dialogManager) async {
|
||||
String quality = await bind.sessionGetImageQuality(id: id) ?? 'balanced';
|
||||
if (quality == '') quality = 'balanced';
|
||||
String codec =
|
||||
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? 'auto';
|
||||
if (codec == '') codec = 'auto';
|
||||
String viewStyle =
|
||||
await bind.sessionGetOption(id: id, arg: 'view-style') ?? '';
|
||||
|
||||
var displays = <Widget>[];
|
||||
final pi = gFFI.ffiModel.pi;
|
||||
final image = gFFI.ffiModel.getConnectionImage();
|
||||
if (image != null)
|
||||
if (image != null) {
|
||||
displays.add(Padding(padding: const EdgeInsets.only(top: 8), child: image));
|
||||
}
|
||||
if (pi.displays.length > 1) {
|
||||
final cur = pi.currentDisplay;
|
||||
final children = <Widget>[];
|
||||
for (var i = 0; i < pi.displays.length; ++i)
|
||||
for (var i = 0; i < pi.displays.length; ++i) {
|
||||
children.add(InkWell(
|
||||
onTap: () {
|
||||
if (i == cur) return;
|
||||
@@ -1038,6 +1044,7 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
|
||||
child: Text((i + 1).toString(),
|
||||
style: TextStyle(
|
||||
color: i == cur ? Colors.white : Colors.black87))))));
|
||||
}
|
||||
displays.add(Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Wrap(
|
||||
@@ -1047,9 +1054,21 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
|
||||
)));
|
||||
}
|
||||
if (displays.isNotEmpty) {
|
||||
displays.add(Divider(color: MyTheme.border));
|
||||
displays.add(const Divider(color: MyTheme.border));
|
||||
}
|
||||
final perms = gFFI.ffiModel.permissions;
|
||||
final hasHwcodec = bind.mainHasHwcodec();
|
||||
final List<bool> codecs = [];
|
||||
if (hasHwcodec) {
|
||||
try {
|
||||
final Map codecsJson =
|
||||
jsonDecode(await bind.sessionSupportedHwcodec(id: id));
|
||||
final h264 = codecsJson['h264'] ?? false;
|
||||
final h265 = codecsJson['h265'] ?? false;
|
||||
codecs.add(h264);
|
||||
codecs.add(h265);
|
||||
} finally {}
|
||||
}
|
||||
|
||||
dialogManager.show((setState, close) {
|
||||
final more = <Widget>[];
|
||||
@@ -1057,50 +1076,77 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
|
||||
more.add(getToggle(id, setState, 'disable-audio', 'Mute'));
|
||||
}
|
||||
if (perms['keyboard'] != false) {
|
||||
if (perms['clipboard'] != false)
|
||||
if (perms['clipboard'] != false) {
|
||||
more.add(
|
||||
getToggle(id, setState, 'disable-clipboard', 'Disable clipboard'));
|
||||
}
|
||||
more.add(getToggle(
|
||||
id, setState, 'lock-after-session-end', 'Lock after session end'));
|
||||
if (pi.platform == 'Windows') {
|
||||
more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode'));
|
||||
}
|
||||
}
|
||||
var setQuality = (String? value) {
|
||||
setQuality(String? value) {
|
||||
if (value == null) return;
|
||||
setState(() {
|
||||
quality = value;
|
||||
bind.sessionSetImageQuality(id: id, value: value);
|
||||
});
|
||||
};
|
||||
var setViewStyle = (String? value) {
|
||||
}
|
||||
|
||||
setViewStyle(String? value) {
|
||||
if (value == null) return;
|
||||
setState(() {
|
||||
viewStyle = value;
|
||||
bind.sessionPeerOption(id: id, name: "view-style", value: value);
|
||||
gFFI.canvasModel.updateViewStyle();
|
||||
bind
|
||||
.sessionPeerOption(id: id, name: "view-style", value: value)
|
||||
.then((_) => gFFI.canvasModel.updateViewStyle());
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
setCodec(String? value) {
|
||||
if (value == null) return;
|
||||
setState(() {
|
||||
codec = value;
|
||||
bind
|
||||
.sessionPeerOption(id: id, name: "codec-preference", value: value)
|
||||
.then((_) => bind.sessionChangePreferCodec(id: id));
|
||||
});
|
||||
}
|
||||
|
||||
final radios = [
|
||||
getRadio('Scale original', 'original', viewStyle, setViewStyle),
|
||||
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
|
||||
const Divider(color: MyTheme.border),
|
||||
getRadio('Good image quality', 'best', quality, setQuality),
|
||||
getRadio('Balanced', 'balanced', quality, setQuality),
|
||||
getRadio('Optimize reaction time', 'low', quality, setQuality),
|
||||
const Divider(color: MyTheme.border)
|
||||
];
|
||||
|
||||
if (hasHwcodec && codecs.length == 2 && (codecs[0] || codecs[1])) {
|
||||
radios.addAll([
|
||||
getRadio(translate('Auto'), 'auto', codec, setCodec),
|
||||
getRadio('VP9', 'vp9', codec, setCodec),
|
||||
]);
|
||||
if (codecs[0]) {
|
||||
radios.add(getRadio('H264', 'h264', codec, setCodec));
|
||||
}
|
||||
if (codecs[1]) {
|
||||
radios.add(getRadio('H265', 'h265', codec, setCodec));
|
||||
}
|
||||
radios.add(const Divider(color: MyTheme.border));
|
||||
}
|
||||
|
||||
final toggles = [
|
||||
getToggle(id, setState, 'show-remote-cursor', 'Show remote cursor'),
|
||||
getToggle(id, setState, 'show-quality-monitor', 'Show quality monitor'),
|
||||
];
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: SizedBox.shrink(),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: displays +
|
||||
<Widget>[
|
||||
getRadio('Scale Original', 'original', viewStyle, setViewStyle),
|
||||
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
|
||||
Divider(color: MyTheme.border),
|
||||
getRadio('Good image quality', 'best', quality, setQuality),
|
||||
getRadio('Balanced', 'balanced', quality, setQuality),
|
||||
getRadio('Optimize reaction time', 'low', quality, setQuality),
|
||||
Divider(color: MyTheme.border),
|
||||
getToggle(
|
||||
id, setState, 'show-remote-cursor', 'Show remote cursor'),
|
||||
getToggle(id, setState, 'show-quality-monitor',
|
||||
'Show quality monitor'),
|
||||
] +
|
||||
more),
|
||||
actions: [],
|
||||
children: displays + radios + toggles + more),
|
||||
contentPadding: 0,
|
||||
);
|
||||
}, clickMaskDismiss: true, backDismiss: true);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_hbb/mobile/widgets/dialog.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../common/widgets/dialog.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../../models/server_model.dart';
|
||||
import 'home_page.dart';
|
||||
@@ -12,51 +13,49 @@ class ServerPage extends StatefulWidget implements PageShape {
|
||||
final title = translate("Share Screen");
|
||||
|
||||
@override
|
||||
final icon = Icon(Icons.mobile_screen_share);
|
||||
final icon = const Icon(Icons.mobile_screen_share);
|
||||
|
||||
@override
|
||||
final appBarActions = [
|
||||
PopupMenuButton<String>(
|
||||
icon: Icon(Icons.more_vert),
|
||||
icon: const Icon(Icons.more_vert),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Change ID")),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
value: "changeID",
|
||||
enabled: false,
|
||||
child: Text(translate("Change ID")),
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Set permanent password")),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
value: "setPermanentPassword",
|
||||
enabled:
|
||||
gFFI.serverModel.verificationMethod != kUseTemporaryPassword,
|
||||
child: Text(translate("Set permanent password")),
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Set temporary password length")),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
value: "setTemporaryPasswordLength",
|
||||
enabled:
|
||||
gFFI.serverModel.verificationMethod != kUsePermanentPassword,
|
||||
child: Text(translate("Set temporary password length")),
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.symmetric(horizontal: 0.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 0.0),
|
||||
value: kUseTemporaryPassword,
|
||||
child: Container(
|
||||
child: ListTile(
|
||||
title: Text(translate("Use temporary password")),
|
||||
trailing: Icon(
|
||||
Icons.check,
|
||||
color: gFFI.serverModel.verificationMethod ==
|
||||
kUseTemporaryPassword
|
||||
? null
|
||||
: Color(0xFFFFFFFF),
|
||||
))),
|
||||
child: ListTile(
|
||||
title: Text(translate("Use temporary password")),
|
||||
trailing: Icon(
|
||||
Icons.check,
|
||||
color: gFFI.serverModel.verificationMethod ==
|
||||
kUseTemporaryPassword
|
||||
? null
|
||||
: Colors.transparent,
|
||||
)),
|
||||
),
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.symmetric(horizontal: 0.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 0.0),
|
||||
value: kUsePermanentPassword,
|
||||
child: ListTile(
|
||||
title: Text(translate("Use permanent password")),
|
||||
@@ -65,11 +64,11 @@ class ServerPage extends StatefulWidget implements PageShape {
|
||||
color: gFFI.serverModel.verificationMethod ==
|
||||
kUsePermanentPassword
|
||||
? null
|
||||
: Color(0xFFFFFFFF),
|
||||
: Colors.transparent,
|
||||
)),
|
||||
),
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.symmetric(horizontal: 0.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 0.0),
|
||||
value: kUseBothPasswords,
|
||||
child: ListTile(
|
||||
title: Text(translate("Use both passwords")),
|
||||
@@ -80,14 +79,14 @@ class ServerPage extends StatefulWidget implements PageShape {
|
||||
gFFI.serverModel.verificationMethod !=
|
||||
kUsePermanentPassword
|
||||
? null
|
||||
: Color(0xFFFFFFFF),
|
||||
: Colors.transparent,
|
||||
)),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {
|
||||
if (value == "changeID") {
|
||||
// TODO
|
||||
changeIdDialog();
|
||||
} else if (value == "setPermanentPassword") {
|
||||
setPermanentPasswordDialog(gFFI.dialogManager);
|
||||
} else if (value == "setTemporaryPasswordLength") {
|
||||
@@ -101,6 +100,8 @@ class ServerPage extends StatefulWidget implements PageShape {
|
||||
})
|
||||
];
|
||||
|
||||
ServerPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ServerPageState();
|
||||
}
|
||||
@@ -125,9 +126,9 @@ class _ServerPageState extends State<ServerPage> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
ServerInfo(),
|
||||
PermissionChecker(),
|
||||
ConnectionManager(),
|
||||
SizedBox.fromSize(size: Size(0, 15.0)),
|
||||
const PermissionChecker(),
|
||||
const ConnectionManager(),
|
||||
SizedBox.fromSize(size: const Size(0, 15.0)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -148,6 +149,8 @@ class ServerInfo extends StatelessWidget {
|
||||
final model = gFFI.serverModel;
|
||||
final emptyController = TextEditingController(text: "-");
|
||||
|
||||
ServerInfo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isPermanent = model.verificationMethod == kUsePermanentPassword;
|
||||
@@ -158,7 +161,7 @@ class ServerInfo extends StatelessWidget {
|
||||
children: [
|
||||
TextFormField(
|
||||
readOnly: true,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MyTheme.accent),
|
||||
@@ -166,14 +169,14 @@ class ServerInfo extends StatelessWidget {
|
||||
decoration: InputDecoration(
|
||||
icon: const Icon(Icons.perm_identity),
|
||||
labelText: translate("ID"),
|
||||
labelStyle: TextStyle(
|
||||
labelStyle: const TextStyle(
|
||||
fontWeight: FontWeight.bold, color: MyTheme.accent50),
|
||||
),
|
||||
onSaved: (String? value) {},
|
||||
),
|
||||
TextFormField(
|
||||
readOnly: true,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MyTheme.accent),
|
||||
@@ -181,7 +184,7 @@ class ServerInfo extends StatelessWidget {
|
||||
decoration: InputDecoration(
|
||||
icon: const Icon(Icons.lock),
|
||||
labelText: translate("Password"),
|
||||
labelStyle: TextStyle(
|
||||
labelStyle: const TextStyle(
|
||||
fontWeight: FontWeight.bold, color: MyTheme.accent50),
|
||||
suffix: isPermanent
|
||||
? null
|
||||
@@ -200,13 +203,13 @@ class ServerInfo extends StatelessWidget {
|
||||
Center(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.warning_amber_sharp,
|
||||
const Icon(Icons.warning_amber_sharp,
|
||||
color: Colors.redAccent, size: 24),
|
||||
SizedBox(width: 10),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
translate("Service is not running"),
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontFamily: 'WorkSans',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
@@ -215,11 +218,11 @@ class ServerInfo extends StatelessWidget {
|
||||
))
|
||||
],
|
||||
)),
|
||||
SizedBox(height: 5),
|
||||
const SizedBox(height: 5),
|
||||
Center(
|
||||
child: Text(
|
||||
translate("android_start_service_tip"),
|
||||
style: TextStyle(fontSize: 12, color: MyTheme.darkGray),
|
||||
style: const TextStyle(fontSize: 12, color: MyTheme.darkGray),
|
||||
))
|
||||
],
|
||||
));
|
||||
@@ -227,8 +230,10 @@ class ServerInfo extends StatelessWidget {
|
||||
}
|
||||
|
||||
class PermissionChecker extends StatefulWidget {
|
||||
const PermissionChecker({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PermissionCheckerState createState() => _PermissionCheckerState();
|
||||
State<PermissionChecker> createState() => _PermissionCheckerState();
|
||||
}
|
||||
|
||||
class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
@@ -236,7 +241,7 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
Widget build(BuildContext context) {
|
||||
final serverModel = Provider.of<ServerModel>(context);
|
||||
final hasAudioPermission = androidVersion >= 30;
|
||||
final status;
|
||||
final String status;
|
||||
if (serverModel.connectStatus == -1) {
|
||||
status = 'not_ready_status';
|
||||
} else if (serverModel.connectStatus == 0) {
|
||||
@@ -260,9 +265,9 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
serverModel.toggleAudio)
|
||||
: Text(
|
||||
"* ${translate("android_version_audio_tip")}",
|
||||
style: TextStyle(color: MyTheme.darkGray),
|
||||
style: const TextStyle(color: MyTheme.darkGray),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@@ -273,11 +278,11 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(Colors.red)),
|
||||
icon: Icon(Icons.stop),
|
||||
icon: const Icon(Icons.stop),
|
||||
onPressed: serverModel.toggleService,
|
||||
label: Text(translate("Stop service")))
|
||||
: ElevatedButton.icon(
|
||||
icon: Icon(Icons.play_arrow),
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
onPressed: serverModel.toggleService,
|
||||
label: Text(translate("Start Service")))),
|
||||
Expanded(
|
||||
@@ -287,8 +292,8 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
Expanded(
|
||||
flex: 0,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(left: 20, right: 5),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20, right: 5),
|
||||
child: Icon(Icons.circle,
|
||||
color: serverModel.connectStatus > 0
|
||||
? Colors.greenAccent
|
||||
@@ -297,12 +302,12 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
Expanded(
|
||||
child: Text(translate(status),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: MyTheme.accent50)))
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink())
|
||||
: const SizedBox.shrink())
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -311,7 +316,8 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
}
|
||||
|
||||
class PermissionRow extends StatelessWidget {
|
||||
PermissionRow(this.name, this.isOk, this.onPressed);
|
||||
const PermissionRow(this.name, this.isOk, this.onPressed, {Key? key})
|
||||
: super(key: key);
|
||||
|
||||
final String name;
|
||||
final bool isOk;
|
||||
@@ -327,8 +333,8 @@ class PermissionRow extends StatelessWidget {
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(name,
|
||||
style:
|
||||
TextStyle(fontSize: 16.0, color: MyTheme.accent50)))),
|
||||
style: const TextStyle(
|
||||
fontSize: 16.0, color: MyTheme.accent50)))),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: FittedBox(
|
||||
@@ -347,7 +353,7 @@ class PermissionRow extends StatelessWidget {
|
||||
onPressed: onPressed,
|
||||
child: Text(
|
||||
translate(isOk ? "CLOSE" : "OPEN"),
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
)))),
|
||||
],
|
||||
);
|
||||
@@ -355,6 +361,8 @@ class PermissionRow extends StatelessWidget {
|
||||
}
|
||||
|
||||
class ConnectionManager extends StatelessWidget {
|
||||
const ConnectionManager({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serverModel = Provider.of<ServerModel>(context);
|
||||
@@ -377,7 +385,7 @@ class ConnectionManager extends StatelessWidget {
|
||||
Expanded(
|
||||
flex: -1,
|
||||
child: client.isFileTransfer || !client.authorized
|
||||
? SizedBox.shrink()
|
||||
? const SizedBox.shrink()
|
||||
: IconButton(
|
||||
onPressed: () {
|
||||
gFFI.chatModel.changeCurrentID(client.id);
|
||||
@@ -388,24 +396,24 @@ class ConnectionManager extends StatelessWidget {
|
||||
bar.onTap!(1);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
icon: const Icon(
|
||||
Icons.chat,
|
||||
color: MyTheme.accent80,
|
||||
)))
|
||||
],
|
||||
),
|
||||
client.authorized
|
||||
? SizedBox.shrink()
|
||||
? const SizedBox.shrink()
|
||||
: Text(
|
||||
translate("android_new_connection_tip"),
|
||||
style: TextStyle(color: Colors.black54),
|
||||
style: const TextStyle(color: Colors.black54),
|
||||
),
|
||||
client.authorized
|
||||
? ElevatedButton.icon(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(Colors.red)),
|
||||
icon: Icon(Icons.close),
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
bind.cmCloseConnection(connId: client.id);
|
||||
gFFI.invokeMethod(
|
||||
@@ -418,7 +426,7 @@ class ConnectionManager extends StatelessWidget {
|
||||
onPressed: () {
|
||||
serverModel.sendLoginResponse(client, false);
|
||||
}),
|
||||
SizedBox(width: 20),
|
||||
const SizedBox(width: 20),
|
||||
ElevatedButton(
|
||||
child: Text(translate("Accept")),
|
||||
onPressed: () {
|
||||
@@ -432,7 +440,8 @@ class ConnectionManager extends StatelessWidget {
|
||||
}
|
||||
|
||||
class PaddingCard extends StatelessWidget {
|
||||
PaddingCard({required this.child, this.title, this.titleIcon});
|
||||
const PaddingCard({Key? key, required this.child, this.title, this.titleIcon})
|
||||
: super(key: key);
|
||||
|
||||
final String? title;
|
||||
final IconData? titleIcon;
|
||||
@@ -445,18 +454,18 @@ class PaddingCard extends StatelessWidget {
|
||||
children.insert(
|
||||
0,
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 5.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
titleIcon != null
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: Icon(titleIcon,
|
||||
color: MyTheme.accent80, size: 30))
|
||||
: SizedBox.shrink(),
|
||||
: const SizedBox.shrink(),
|
||||
Text(
|
||||
title!,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontFamily: 'WorkSans',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
@@ -466,12 +475,13 @@ class PaddingCard extends StatelessWidget {
|
||||
],
|
||||
)));
|
||||
}
|
||||
return Container(
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: Card(
|
||||
margin: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0),
|
||||
margin: const EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children,
|
||||
@@ -483,27 +493,29 @@ class PaddingCard extends StatelessWidget {
|
||||
|
||||
Widget clientInfo(Client client) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: -1,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 12),
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: CircleAvatar(
|
||||
child: Text(client.name[0]),
|
||||
backgroundColor: MyTheme.border))),
|
||||
backgroundColor: MyTheme.border,
|
||||
child: Text(client.name[0])))),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(client.name,
|
||||
style: TextStyle(color: MyTheme.idColor, fontSize: 18)),
|
||||
SizedBox(width: 8),
|
||||
style: const TextStyle(
|
||||
color: MyTheme.idColor, fontSize: 18)),
|
||||
const SizedBox(width: 8),
|
||||
Text(client.peerId,
|
||||
style: TextStyle(color: MyTheme.idColor, fontSize: 10))
|
||||
style:
|
||||
const TextStyle(color: MyTheme.idColor, fontSize: 10))
|
||||
]))
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user