fix, settings on main window
Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
parent
d49dd9377e
commit
b80051bb35
@ -1269,6 +1269,19 @@ String bool2option(String option, bool b) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainSetBoolOption(String key, bool value) async {
|
||||||
|
String v = bool2option(key, value);
|
||||||
|
await bind.mainSetOption(key: key, value: v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> mainGetBoolOption(String key) async {
|
||||||
|
return option2bool(key, await bind.mainGetOption(key: key));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mainGetBoolOptionSync(String key) {
|
||||||
|
return option2bool(key, bind.mainGetOptionSync(key: key));
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> matchPeer(String searchText, Peer peer) async {
|
Future<bool> matchPeer(String searchText, Peer peer) async {
|
||||||
if (searchText.isEmpty) {
|
if (searchText.isEmpty) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -385,20 +385,17 @@ class _GeneralState extends State<_General> {
|
|||||||
|
|
||||||
Widget record(BuildContext context) {
|
Widget record(BuildContext context) {
|
||||||
return futureBuilder(future: () async {
|
return futureBuilder(future: () async {
|
||||||
String customDirectory =
|
|
||||||
await bind.mainGetOption(key: 'video-save-directory');
|
|
||||||
String defaultDirectory = await bind.mainDefaultVideoSaveDirectory();
|
String defaultDirectory = await bind.mainDefaultVideoSaveDirectory();
|
||||||
String dir;
|
|
||||||
if (customDirectory.isNotEmpty) {
|
|
||||||
dir = customDirectory;
|
|
||||||
} else {
|
|
||||||
dir = defaultDirectory;
|
|
||||||
}
|
|
||||||
// canLaunchUrl blocked on windows portable, user SYSTEM
|
// canLaunchUrl blocked on windows portable, user SYSTEM
|
||||||
return {'dir': dir, 'canlaunch': true};
|
return {'dir': defaultDirectory, 'canlaunch': true};
|
||||||
}(), hasData: (data) {
|
}(), hasData: (data) {
|
||||||
Map<String, dynamic> map = data as Map<String, dynamic>;
|
Map<String, dynamic> map = data as Map<String, dynamic>;
|
||||||
String dir = map['dir']!;
|
String dir = map['dir']!;
|
||||||
|
String customDirectory =
|
||||||
|
bind.mainGetOptionSync(key: 'video-save-directory');
|
||||||
|
if (customDirectory.isNotEmpty) {
|
||||||
|
dir = customDirectory;
|
||||||
|
}
|
||||||
bool canlaunch = map['canlaunch']! as bool;
|
bool canlaunch = map['canlaunch']! as bool;
|
||||||
|
|
||||||
return _Card(title: 'Recording', children: [
|
return _Card(title: 'Recording', children: [
|
||||||
@ -444,8 +441,7 @@ class _GeneralState extends State<_General> {
|
|||||||
Widget language() {
|
Widget language() {
|
||||||
return futureBuilder(future: () async {
|
return futureBuilder(future: () async {
|
||||||
String langs = await bind.mainGetLangs();
|
String langs = await bind.mainGetLangs();
|
||||||
String lang = bind.mainGetLocalOption(key: kCommConfKeyLang);
|
return {'langs': langs};
|
||||||
return {'langs': langs, 'lang': lang};
|
|
||||||
}(), hasData: (res) {
|
}(), hasData: (res) {
|
||||||
Map<String, String> data = res as Map<String, String>;
|
Map<String, String> data = res as Map<String, String>;
|
||||||
List<dynamic> langsList = jsonDecode(data['langs']!);
|
List<dynamic> langsList = jsonDecode(data['langs']!);
|
||||||
@ -454,7 +450,7 @@ class _GeneralState extends State<_General> {
|
|||||||
List<String> values = langsMap.values.toList();
|
List<String> values = langsMap.values.toList();
|
||||||
keys.insert(0, '');
|
keys.insert(0, '');
|
||||||
values.insert(0, translate('Default'));
|
values.insert(0, translate('Default'));
|
||||||
String currentKey = data['lang']!;
|
String currentKey = bind.mainGetLocalOption(key: kCommConfKeyLang);
|
||||||
if (!keys.contains(currentKey)) {
|
if (!keys.contains(currentKey)) {
|
||||||
currentKey = '';
|
currentKey = '';
|
||||||
}
|
}
|
||||||
@ -529,79 +525,75 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
|||||||
|
|
||||||
Widget permissions(context) {
|
Widget permissions(context) {
|
||||||
bool enabled = !locked;
|
bool enabled = !locked;
|
||||||
return futureBuilder(future: () async {
|
String accessMode = bind.mainGetOptionSync(key: 'access-mode');
|
||||||
return await bind.mainGetOption(key: 'access-mode');
|
_AccessMode mode;
|
||||||
}(), hasData: (data) {
|
if (accessMode == 'full') {
|
||||||
String accessMode = data! as String;
|
mode = _AccessMode.full;
|
||||||
_AccessMode mode;
|
} else if (accessMode == 'view') {
|
||||||
if (accessMode == 'full') {
|
mode = _AccessMode.view;
|
||||||
mode = _AccessMode.full;
|
} else {
|
||||||
} else if (accessMode == 'view') {
|
mode = _AccessMode.custom;
|
||||||
mode = _AccessMode.view;
|
}
|
||||||
} else {
|
String initialKey;
|
||||||
mode = _AccessMode.custom;
|
bool? fakeValue;
|
||||||
}
|
switch (mode) {
|
||||||
String initialKey;
|
case _AccessMode.custom:
|
||||||
bool? fakeValue;
|
initialKey = '';
|
||||||
switch (mode) {
|
fakeValue = null;
|
||||||
case _AccessMode.custom:
|
break;
|
||||||
initialKey = '';
|
case _AccessMode.full:
|
||||||
fakeValue = null;
|
initialKey = 'full';
|
||||||
break;
|
fakeValue = true;
|
||||||
case _AccessMode.full:
|
break;
|
||||||
initialKey = 'full';
|
case _AccessMode.view:
|
||||||
fakeValue = true;
|
initialKey = 'view';
|
||||||
break;
|
fakeValue = false;
|
||||||
case _AccessMode.view:
|
break;
|
||||||
initialKey = 'view';
|
}
|
||||||
fakeValue = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _Card(title: 'Permissions', children: [
|
return _Card(title: 'Permissions', children: [
|
||||||
_ComboBox(
|
_ComboBox(
|
||||||
keys: [
|
keys: [
|
||||||
'',
|
'',
|
||||||
'full',
|
'full',
|
||||||
'view',
|
'view',
|
||||||
],
|
|
||||||
values: [
|
|
||||||
translate('Custom'),
|
|
||||||
translate('Full Access'),
|
|
||||||
translate('Screen Share'),
|
|
||||||
],
|
|
||||||
enabled: enabled,
|
|
||||||
initialKey: initialKey,
|
|
||||||
onChanged: (mode) async {
|
|
||||||
await bind.mainSetOption(key: 'access-mode', value: mode);
|
|
||||||
setState(() {});
|
|
||||||
}).marginOnly(left: _kContentHMargin),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
_OptionCheckBox(context, 'Enable Keyboard/Mouse', 'enable-keyboard',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(context, 'Enable Clipboard', 'enable-clipboard',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(
|
|
||||||
context, 'Enable File Transfer', 'enable-file-transfer',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(context, 'Enable Audio', 'enable-audio',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(context, 'Enable TCP Tunneling', 'enable-tunnel',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(
|
|
||||||
context, 'Enable Remote Restart', 'enable-remote-restart',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(
|
|
||||||
context, 'Enable Recording Session', 'enable-record-session',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
_OptionCheckBox(context, 'Enable remote configuration modification',
|
|
||||||
'allow-remote-config-modification',
|
|
||||||
enabled: enabled, fakeValue: fakeValue),
|
|
||||||
],
|
],
|
||||||
),
|
values: [
|
||||||
]);
|
translate('Custom'),
|
||||||
});
|
translate('Full Access'),
|
||||||
|
translate('Screen Share'),
|
||||||
|
],
|
||||||
|
enabled: enabled,
|
||||||
|
initialKey: initialKey,
|
||||||
|
onChanged: (mode) async {
|
||||||
|
await bind.mainSetOption(key: 'access-mode', value: mode);
|
||||||
|
setState(() {});
|
||||||
|
}).marginOnly(left: _kContentHMargin),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
_OptionCheckBox(context, 'Enable Keyboard/Mouse', 'enable-keyboard',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(context, 'Enable Clipboard', 'enable-clipboard',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(
|
||||||
|
context, 'Enable File Transfer', 'enable-file-transfer',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(context, 'Enable Audio', 'enable-audio',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(context, 'Enable TCP Tunneling', 'enable-tunnel',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(
|
||||||
|
context, 'Enable Remote Restart', 'enable-remote-restart',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(
|
||||||
|
context, 'Enable Recording Session', 'enable-record-session',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
_OptionCheckBox(context, 'Enable remote configuration modification',
|
||||||
|
'allow-remote-config-modification',
|
||||||
|
enabled: enabled, fakeValue: fakeValue),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget password(BuildContext context) {
|
Widget password(BuildContext context) {
|
||||||
@ -759,106 +751,94 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
|||||||
return [
|
return [
|
||||||
_OptionCheckBox(context, 'Enable Direct IP Access', 'direct-server',
|
_OptionCheckBox(context, 'Enable Direct IP Access', 'direct-server',
|
||||||
update: update, enabled: !locked),
|
update: update, enabled: !locked),
|
||||||
futureBuilder(
|
() {
|
||||||
future: () async {
|
bool enabled = option2bool(
|
||||||
String enabled = await bind.mainGetOption(key: 'direct-server');
|
'direct-server', bind.mainGetOptionSync(key: 'direct-server'));
|
||||||
String port = await bind.mainGetOption(key: 'direct-access-port');
|
if (!enabled) applyEnabled.value = false;
|
||||||
return {'enabled': enabled, 'port': port};
|
controller.text = bind.mainGetOptionSync(key: 'direct-access-port');
|
||||||
}(),
|
return Offstage(
|
||||||
hasData: (data) {
|
offstage: !enabled,
|
||||||
bool enabled =
|
child: _SubLabeledWidget(
|
||||||
option2bool('direct-server', data['enabled'].toString());
|
context,
|
||||||
if (!enabled) applyEnabled.value = false;
|
'Port',
|
||||||
controller.text = data['port'].toString();
|
Row(children: [
|
||||||
return Offstage(
|
SizedBox(
|
||||||
offstage: !enabled,
|
width: 95,
|
||||||
child: _SubLabeledWidget(
|
child: TextField(
|
||||||
context,
|
controller: controller,
|
||||||
'Port',
|
enabled: enabled && !locked,
|
||||||
Row(children: [
|
onChanged: (_) => applyEnabled.value = true,
|
||||||
SizedBox(
|
inputFormatters: [
|
||||||
width: 95,
|
FilteringTextInputFormatter.allow(RegExp(
|
||||||
child: TextField(
|
r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')),
|
||||||
controller: controller,
|
],
|
||||||
enabled: enabled && !locked,
|
decoration: const InputDecoration(
|
||||||
onChanged: (_) => applyEnabled.value = true,
|
hintText: '21118',
|
||||||
inputFormatters: [
|
contentPadding:
|
||||||
FilteringTextInputFormatter.allow(RegExp(
|
EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||||
r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')),
|
),
|
||||||
],
|
).marginOnly(right: 15),
|
||||||
decoration: const InputDecoration(
|
),
|
||||||
hintText: '21118',
|
Obx(() => ElevatedButton(
|
||||||
contentPadding:
|
onPressed: applyEnabled.value && enabled && !locked
|
||||||
EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
? () async {
|
||||||
|
applyEnabled.value = false;
|
||||||
|
await bind.mainSetOption(
|
||||||
|
key: 'direct-access-port',
|
||||||
|
value: controller.text);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Text(
|
||||||
|
translate('Apply'),
|
||||||
),
|
),
|
||||||
).marginOnly(right: 15),
|
))
|
||||||
),
|
]),
|
||||||
Obx(() => ElevatedButton(
|
enabled: enabled && !locked,
|
||||||
onPressed: applyEnabled.value && enabled && !locked
|
),
|
||||||
? () async {
|
);
|
||||||
applyEnabled.value = false;
|
}(),
|
||||||
await bind.mainSetOption(
|
|
||||||
key: 'direct-access-port',
|
|
||||||
value: controller.text);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: Text(
|
|
||||||
translate('Apply'),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
]),
|
|
||||||
enabled: enabled && !locked,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget whitelist() {
|
Widget whitelist() {
|
||||||
bool enabled = !locked;
|
bool enabled = !locked;
|
||||||
return futureBuilder(future: () async {
|
RxBool hasWhitelist =
|
||||||
return await bind.mainGetOption(key: 'whitelist');
|
bind.mainGetOptionSync(key: 'whitelist').isNotEmpty.obs;
|
||||||
}(), hasData: (data) {
|
update() async {
|
||||||
RxBool hasWhitelist = (data as String).isNotEmpty.obs;
|
hasWhitelist.value = bind.mainGetOptionSync(key: 'whitelist').isNotEmpty;
|
||||||
update() async {
|
}
|
||||||
hasWhitelist.value =
|
|
||||||
(await bind.mainGetOption(key: 'whitelist')).isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
onChanged(bool? checked) async {
|
onChanged(bool? checked) async {
|
||||||
changeWhiteList(callback: update);
|
changeWhiteList(callback: update);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: translate('whitelist_tip'),
|
message: translate('whitelist_tip'),
|
||||||
child: Obx(() => Row(
|
child: Obx(() => Row(
|
||||||
children: [
|
children: [
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: hasWhitelist.value,
|
value: hasWhitelist.value,
|
||||||
onChanged: enabled ? onChanged : null)
|
onChanged: enabled ? onChanged : null)
|
||||||
|
.marginOnly(right: 5),
|
||||||
|
Offstage(
|
||||||
|
offstage: !hasWhitelist.value,
|
||||||
|
child: const Icon(Icons.warning_amber_rounded,
|
||||||
|
color: Color.fromARGB(255, 255, 204, 0))
|
||||||
.marginOnly(right: 5),
|
.marginOnly(right: 5),
|
||||||
Offstage(
|
),
|
||||||
offstage: !hasWhitelist.value,
|
Expanded(
|
||||||
child: const Icon(Icons.warning_amber_rounded,
|
child: Text(
|
||||||
color: Color.fromARGB(255, 255, 204, 0))
|
translate('Use IP Whitelisting'),
|
||||||
.marginOnly(right: 5),
|
style: TextStyle(color: _disabledTextColor(context, enabled)),
|
||||||
),
|
))
|
||||||
Expanded(
|
],
|
||||||
child: Text(
|
)),
|
||||||
translate('Use IP Whitelisting'),
|
),
|
||||||
style:
|
onTap: () {
|
||||||
TextStyle(color: _disabledTextColor(context, enabled)),
|
onChanged(!hasWhitelist.value);
|
||||||
))
|
},
|
||||||
],
|
).marginOnly(left: _kCheckBoxLeftMargin);
|
||||||
)),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
onChanged(!hasWhitelist.value);
|
|
||||||
},
|
|
||||||
).marginOnly(left: _kCheckBoxLeftMargin);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget hide_cm(bool enabled) {
|
Widget hide_cm(bool enabled) {
|
||||||
@ -943,154 +923,150 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
server(bool enabled) {
|
server(bool enabled) {
|
||||||
return futureBuilder(future: () async {
|
// Setting page is not modal, oldOptions should only be used when getting options, never when setting.
|
||||||
return await bind.mainGetOptions();
|
Map<String, dynamic> oldOptions =
|
||||||
}(), hasData: (data) {
|
jsonDecode(bind.mainGetOptionsSync() as String);
|
||||||
// Setting page is not modal, oldOptions should only be used when getting options, never when setting.
|
old(String key) {
|
||||||
Map<String, dynamic> oldOptions = jsonDecode(data! as String);
|
return (oldOptions[key] ?? '').trim();
|
||||||
old(String key) {
|
}
|
||||||
return (oldOptions[key] ?? '').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
RxString idErrMsg = ''.obs;
|
RxString idErrMsg = ''.obs;
|
||||||
RxString relayErrMsg = ''.obs;
|
RxString relayErrMsg = ''.obs;
|
||||||
RxString apiErrMsg = ''.obs;
|
RxString apiErrMsg = ''.obs;
|
||||||
var idController =
|
var idController =
|
||||||
TextEditingController(text: old('custom-rendezvous-server'));
|
TextEditingController(text: old('custom-rendezvous-server'));
|
||||||
var relayController = TextEditingController(text: old('relay-server'));
|
var relayController = TextEditingController(text: old('relay-server'));
|
||||||
var apiController = TextEditingController(text: old('api-server'));
|
var apiController = TextEditingController(text: old('api-server'));
|
||||||
var keyController = TextEditingController(text: old('key'));
|
var keyController = TextEditingController(text: old('key'));
|
||||||
|
|
||||||
set(String idServer, String relayServer, String apiServer,
|
set(String idServer, String relayServer, String apiServer,
|
||||||
String key) async {
|
String key) async {
|
||||||
idServer = idServer.trim();
|
idServer = idServer.trim();
|
||||||
relayServer = relayServer.trim();
|
relayServer = relayServer.trim();
|
||||||
apiServer = apiServer.trim();
|
apiServer = apiServer.trim();
|
||||||
key = key.trim();
|
key = key.trim();
|
||||||
if (idServer.isNotEmpty) {
|
if (idServer.isNotEmpty) {
|
||||||
idErrMsg.value =
|
idErrMsg.value =
|
||||||
translate(await bind.mainTestIfValidServer(server: idServer));
|
translate(await bind.mainTestIfValidServer(server: idServer));
|
||||||
if (idErrMsg.isNotEmpty) {
|
if (idErrMsg.isNotEmpty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (relayServer.isNotEmpty) {
|
|
||||||
relayErrMsg.value =
|
|
||||||
translate(await bind.mainTestIfValidServer(server: relayServer));
|
|
||||||
if (relayErrMsg.isNotEmpty) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (apiServer.isNotEmpty) {
|
|
||||||
if (!apiServer.startsWith('http://') &&
|
|
||||||
!apiServer.startsWith('https://')) {
|
|
||||||
apiErrMsg.value =
|
|
||||||
'${translate("API Server")}: ${translate("invalid_http")}';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final old = await bind.mainGetOption(key: 'custom-rendezvous-server');
|
|
||||||
if (old.isNotEmpty && old != idServer) {
|
|
||||||
await gFFI.userModel.logOut();
|
|
||||||
}
|
|
||||||
// should set one by one
|
|
||||||
await bind.mainSetOption(
|
|
||||||
key: 'custom-rendezvous-server', value: idServer);
|
|
||||||
await bind.mainSetOption(key: 'relay-server', value: relayServer);
|
|
||||||
await bind.mainSetOption(key: 'api-server', value: apiServer);
|
|
||||||
await bind.mainSetOption(key: 'key', value: key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() async {
|
|
||||||
bool result = await set(idController.text, relayController.text,
|
|
||||||
apiController.text, keyController.text);
|
|
||||||
if (result) {
|
|
||||||
setState(() {});
|
|
||||||
showToast(translate('Successful'));
|
|
||||||
} else {
|
|
||||||
showToast(translate('Failed'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (relayServer.isNotEmpty) {
|
||||||
|
relayErrMsg.value =
|
||||||
|
translate(await bind.mainTestIfValidServer(server: relayServer));
|
||||||
|
if (relayErrMsg.isNotEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (apiServer.isNotEmpty) {
|
||||||
|
if (!apiServer.startsWith('http://') &&
|
||||||
|
!apiServer.startsWith('https://')) {
|
||||||
|
apiErrMsg.value =
|
||||||
|
'${translate("API Server")}: ${translate("invalid_http")}';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final old = await bind.mainGetOption(key: 'custom-rendezvous-server');
|
||||||
|
if (old.isNotEmpty && old != idServer) {
|
||||||
|
await gFFI.userModel.logOut();
|
||||||
|
}
|
||||||
|
// should set one by one
|
||||||
|
await bind.mainSetOption(
|
||||||
|
key: 'custom-rendezvous-server', value: idServer);
|
||||||
|
await bind.mainSetOption(key: 'relay-server', value: relayServer);
|
||||||
|
await bind.mainSetOption(key: 'api-server', value: apiServer);
|
||||||
|
await bind.mainSetOption(key: 'key', value: key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
import() {
|
submit() async {
|
||||||
Clipboard.getData(Clipboard.kTextPlain).then((value) {
|
bool result = await set(idController.text, relayController.text,
|
||||||
final text = value?.text;
|
apiController.text, keyController.text);
|
||||||
if (text != null && text.isNotEmpty) {
|
if (result) {
|
||||||
try {
|
setState(() {});
|
||||||
final sc = ServerConfig.decode(text);
|
showToast(translate('Successful'));
|
||||||
if (sc.idServer.isNotEmpty) {
|
} else {
|
||||||
idController.text = sc.idServer;
|
showToast(translate('Failed'));
|
||||||
relayController.text = sc.relayServer;
|
}
|
||||||
apiController.text = sc.apiServer;
|
}
|
||||||
keyController.text = sc.key;
|
|
||||||
Future<bool> success =
|
import() {
|
||||||
set(sc.idServer, sc.relayServer, sc.apiServer, sc.key);
|
Clipboard.getData(Clipboard.kTextPlain).then((value) {
|
||||||
success.then((value) {
|
final text = value?.text;
|
||||||
if (value) {
|
if (text != null && text.isNotEmpty) {
|
||||||
showToast(
|
try {
|
||||||
translate('Import server configuration successfully'));
|
final sc = ServerConfig.decode(text);
|
||||||
} else {
|
if (sc.idServer.isNotEmpty) {
|
||||||
showToast(translate('Invalid server configuration'));
|
idController.text = sc.idServer;
|
||||||
}
|
relayController.text = sc.relayServer;
|
||||||
});
|
apiController.text = sc.apiServer;
|
||||||
} else {
|
keyController.text = sc.key;
|
||||||
showToast(translate('Invalid server configuration'));
|
Future<bool> success =
|
||||||
}
|
set(sc.idServer, sc.relayServer, sc.apiServer, sc.key);
|
||||||
} catch (e) {
|
success.then((value) {
|
||||||
|
if (value) {
|
||||||
|
showToast(
|
||||||
|
translate('Import server configuration successfully'));
|
||||||
|
} else {
|
||||||
|
showToast(translate('Invalid server configuration'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
showToast(translate('Invalid server configuration'));
|
showToast(translate('Invalid server configuration'));
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
showToast(translate('Clipboard is empty'));
|
showToast(translate('Invalid server configuration'));
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
}
|
showToast(translate('Clipboard is empty'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export() {
|
export() {
|
||||||
final text = ServerConfig(
|
final text = ServerConfig(
|
||||||
idServer: idController.text,
|
idServer: idController.text,
|
||||||
relayServer: relayController.text,
|
relayServer: relayController.text,
|
||||||
apiServer: apiController.text,
|
apiServer: apiController.text,
|
||||||
key: keyController.text)
|
key: keyController.text)
|
||||||
.encode();
|
.encode();
|
||||||
debugPrint("ServerConfig export: $text");
|
debugPrint("ServerConfig export: $text");
|
||||||
|
|
||||||
Clipboard.setData(ClipboardData(text: text));
|
Clipboard.setData(ClipboardData(text: text));
|
||||||
showToast(translate('Export server configuration successfully'));
|
showToast(translate('Export server configuration successfully'));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool secure = !enabled;
|
bool secure = !enabled;
|
||||||
return _Card(title: 'ID/Relay Server', title_suffix: [
|
return _Card(title: 'ID/Relay Server', title_suffix: [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: translate('Import Server Config'),
|
message: translate('Import Server Config'),
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(Icons.paste, color: Colors.grey),
|
||||||
|
onPressed: enabled ? import : null),
|
||||||
|
),
|
||||||
|
Tooltip(
|
||||||
|
message: translate('Export Server Config'),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.paste, color: Colors.grey),
|
icon: Icon(Icons.copy, color: Colors.grey),
|
||||||
onPressed: enabled ? import : null),
|
onPressed: enabled ? export : null)),
|
||||||
),
|
], children: [
|
||||||
Tooltip(
|
Column(
|
||||||
message: translate('Export Server Config'),
|
children: [
|
||||||
child: IconButton(
|
Obx(() => _LabeledTextField(context, 'ID Server', idController,
|
||||||
icon: Icon(Icons.copy, color: Colors.grey),
|
idErrMsg.value, enabled, secure)),
|
||||||
onPressed: enabled ? export : null)),
|
Obx(() => _LabeledTextField(context, 'Relay Server', relayController,
|
||||||
], children: [
|
relayErrMsg.value, enabled, secure)),
|
||||||
Column(
|
Obx(() => _LabeledTextField(context, 'API Server', apiController,
|
||||||
children: [
|
apiErrMsg.value, enabled, secure)),
|
||||||
Obx(() => _LabeledTextField(context, 'ID Server', idController,
|
_LabeledTextField(context, 'Key', keyController, '', enabled, secure),
|
||||||
idErrMsg.value, enabled, secure)),
|
Row(
|
||||||
Obx(() => _LabeledTextField(context, 'Relay Server',
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
relayController, relayErrMsg.value, enabled, secure)),
|
children: [_Button('Apply', submit, enabled: enabled)],
|
||||||
Obx(() => _LabeledTextField(context, 'API Server', apiController,
|
).marginOnly(top: 10),
|
||||||
apiErrMsg.value, enabled, secure)),
|
],
|
||||||
_LabeledTextField(
|
)
|
||||||
context, 'Key', keyController, '', enabled, secure),
|
]);
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [_Button('Apply', submit, enabled: enabled)],
|
|
||||||
).marginOnly(top: 10),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1662,53 +1638,47 @@ Widget _OptionCheckBox(BuildContext context, String label, String key,
|
|||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
Icon? checkedIcon,
|
Icon? checkedIcon,
|
||||||
bool? fakeValue}) {
|
bool? fakeValue}) {
|
||||||
return futureBuilder(
|
bool value = mainGetBoolOptionSync(key);
|
||||||
future: bind.mainGetOption(key: key),
|
if (reverse) value = !value;
|
||||||
hasData: (data) {
|
var ref = value.obs;
|
||||||
bool value = option2bool(key, data.toString());
|
onChanged(option) async {
|
||||||
if (reverse) value = !value;
|
if (option != null) {
|
||||||
var ref = value.obs;
|
if (reverse) option = !option;
|
||||||
onChanged(option) async {
|
await mainSetBoolOption(key, option);
|
||||||
if (option != null) {
|
ref.value = mainGetBoolOptionSync(key);
|
||||||
ref.value = option;
|
update?.call();
|
||||||
if (reverse) option = !option;
|
}
|
||||||
String value = bool2option(key, option);
|
}
|
||||||
await bind.mainSetOption(key: key, value: value);
|
|
||||||
update?.call();
|
if (fakeValue != null) {
|
||||||
|
ref.value = fakeValue;
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
child: Obx(
|
||||||
|
() => Row(
|
||||||
|
children: [
|
||||||
|
Checkbox(value: ref.value, onChanged: enabled ? onChanged : null)
|
||||||
|
.marginOnly(right: 5),
|
||||||
|
Offstage(
|
||||||
|
offstage: !ref.value || checkedIcon == null,
|
||||||
|
child: checkedIcon?.marginOnly(right: 5),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
translate(label),
|
||||||
|
style: TextStyle(color: _disabledTextColor(context, enabled)),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).marginOnly(left: _kCheckBoxLeftMargin),
|
||||||
|
onTap: enabled
|
||||||
|
? () {
|
||||||
|
onChanged(!ref.value);
|
||||||
}
|
}
|
||||||
}
|
: null,
|
||||||
|
);
|
||||||
if (fakeValue != null) {
|
|
||||||
ref.value = fakeValue;
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
child: Obx(
|
|
||||||
() => Row(
|
|
||||||
children: [
|
|
||||||
Checkbox(
|
|
||||||
value: ref.value, onChanged: enabled ? onChanged : null)
|
|
||||||
.marginOnly(right: 5),
|
|
||||||
Offstage(
|
|
||||||
offstage: !ref.value || checkedIcon == null,
|
|
||||||
child: checkedIcon?.marginOnly(right: 5),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
translate(label),
|
|
||||||
style: TextStyle(color: _disabledTextColor(context, enabled)),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
).marginOnly(left: _kCheckBoxLeftMargin),
|
|
||||||
onTap: enabled
|
|
||||||
? () {
|
|
||||||
onChanged(!ref.value);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
|
@ -606,6 +606,10 @@ pub fn main_get_option(key: String) -> String {
|
|||||||
get_option(key)
|
get_option(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main_get_option_sync(key: String) -> SyncReturn<String> {
|
||||||
|
SyncReturn(get_option(key))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main_get_error() -> String {
|
pub fn main_get_error() -> String {
|
||||||
get_error()
|
get_error()
|
||||||
}
|
}
|
||||||
@ -626,6 +630,10 @@ pub fn main_get_options() -> String {
|
|||||||
get_options()
|
get_options()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main_get_options_sync() -> SyncReturn<String> {
|
||||||
|
SyncReturn(get_options())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main_set_options(json: String) {
|
pub fn main_set_options(json: String) {
|
||||||
let map: HashMap<String, String> = serde_json::from_str(&json).unwrap_or(HashMap::new());
|
let map: HashMap<String, String> = serde_json::from_str(&json).unwrap_or(HashMap::new());
|
||||||
if !map.is_empty() {
|
if !map.is_empty() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user