mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-05 04:59:05 +08:00
278 lines
8.4 KiB
Dart
278 lines
8.4 KiB
Dart
|
import 'package:debounce_throttle/debounce_throttle.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter/services.dart';
|
||
|
import 'package:flutter_hbb/common.dart';
|
||
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||
|
import 'package:get/get.dart';
|
||
|
|
||
|
customImageQualityWidget(
|
||
|
{required double initQuality,
|
||
|
required double initFps,
|
||
|
required Function(double) setQuality,
|
||
|
required Function(double) setFps,
|
||
|
required bool showFps}) {
|
||
|
final qualityValue = initQuality.obs;
|
||
|
final fpsValue = initFps.obs;
|
||
|
|
||
|
final RxBool moreQualityChecked = RxBool(qualityValue.value > 100);
|
||
|
final debouncerQuality = Debouncer<double>(
|
||
|
Duration(milliseconds: 1000),
|
||
|
onChanged: (double v) {
|
||
|
setQuality(v);
|
||
|
},
|
||
|
initialValue: qualityValue.value,
|
||
|
);
|
||
|
final debouncerFps = Debouncer<double>(
|
||
|
Duration(milliseconds: 1000),
|
||
|
onChanged: (double v) {
|
||
|
setFps(v);
|
||
|
},
|
||
|
initialValue: fpsValue.value,
|
||
|
);
|
||
|
|
||
|
onMoreChanged(bool? value) {
|
||
|
if (value == null) return;
|
||
|
moreQualityChecked.value = value;
|
||
|
if (!value && qualityValue.value > 100) {
|
||
|
qualityValue.value = 100;
|
||
|
}
|
||
|
debouncerQuality.value = qualityValue.value;
|
||
|
}
|
||
|
|
||
|
return Column(
|
||
|
children: [
|
||
|
Obx(() => Row(
|
||
|
children: [
|
||
|
Expanded(
|
||
|
flex: 3,
|
||
|
child: Slider(
|
||
|
value: qualityValue.value,
|
||
|
min: 10.0,
|
||
|
max: moreQualityChecked.value ? 2000 : 100,
|
||
|
divisions: moreQualityChecked.value ? 199 : 18,
|
||
|
onChanged: (double value) async {
|
||
|
qualityValue.value = value;
|
||
|
debouncerQuality.value = value;
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
Expanded(
|
||
|
flex: 1,
|
||
|
child: Text(
|
||
|
'${qualityValue.value.round()}%',
|
||
|
style: const TextStyle(fontSize: 15),
|
||
|
)),
|
||
|
Expanded(
|
||
|
flex: isMobile ? 2 : 1,
|
||
|
child: Text(
|
||
|
translate('Bitrate'),
|
||
|
style: const TextStyle(fontSize: 15),
|
||
|
)),
|
||
|
// mobile doesn't have enough space
|
||
|
if (!isMobile)
|
||
|
Expanded(
|
||
|
flex: 1,
|
||
|
child: Row(
|
||
|
children: [
|
||
|
Checkbox(
|
||
|
value: moreQualityChecked.value,
|
||
|
onChanged: onMoreChanged,
|
||
|
),
|
||
|
Expanded(
|
||
|
child: Text(translate('More')),
|
||
|
)
|
||
|
],
|
||
|
))
|
||
|
],
|
||
|
)),
|
||
|
if (isMobile)
|
||
|
Obx(() => Row(
|
||
|
children: [
|
||
|
Expanded(
|
||
|
child: Align(
|
||
|
alignment: Alignment.centerRight,
|
||
|
child: Checkbox(
|
||
|
value: moreQualityChecked.value,
|
||
|
onChanged: onMoreChanged,
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
Expanded(
|
||
|
child: Text(translate('More')),
|
||
|
)
|
||
|
],
|
||
|
)),
|
||
|
if (showFps)
|
||
|
Obx(() => Row(
|
||
|
children: [
|
||
|
Expanded(
|
||
|
flex: 3,
|
||
|
child: Slider(
|
||
|
value: fpsValue.value,
|
||
|
min: 5.0,
|
||
|
max: 120.0,
|
||
|
divisions: 23,
|
||
|
onChanged: (double value) async {
|
||
|
fpsValue.value = value;
|
||
|
debouncerFps.value = value;
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
Expanded(
|
||
|
flex: 1,
|
||
|
child: Text(
|
||
|
'${fpsValue.value.round()}',
|
||
|
style: const TextStyle(fontSize: 15),
|
||
|
)),
|
||
|
Expanded(
|
||
|
flex: 2,
|
||
|
child: Text(
|
||
|
translate('FPS'),
|
||
|
style: const TextStyle(fontSize: 15),
|
||
|
))
|
||
|
],
|
||
|
)),
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
|
||
|
customImageQualitySetting() {
|
||
|
final qualityKey = 'custom_image_quality';
|
||
|
final fpsKey = 'custom-fps';
|
||
|
|
||
|
var initQuality =
|
||
|
(double.tryParse(bind.mainGetUserDefaultOption(key: qualityKey)) ?? 50.0);
|
||
|
if (initQuality < 10 || initQuality > 2000) {
|
||
|
initQuality = 50;
|
||
|
}
|
||
|
var initFps =
|
||
|
(double.tryParse(bind.mainGetUserDefaultOption(key: fpsKey)) ?? 30.0);
|
||
|
if (initFps < 5 || initFps > 120) {
|
||
|
initFps = 30;
|
||
|
}
|
||
|
|
||
|
return customImageQualityWidget(
|
||
|
initQuality: initQuality,
|
||
|
initFps: initFps,
|
||
|
setQuality: (v) {
|
||
|
bind.mainSetUserDefaultOption(key: qualityKey, value: v.toString());
|
||
|
},
|
||
|
setFps: (v) {
|
||
|
bind.mainSetUserDefaultOption(key: fpsKey, value: v.toString());
|
||
|
},
|
||
|
showFps: true);
|
||
|
}
|
||
|
|
||
|
Future<bool> setServerConfig(
|
||
|
List<TextEditingController> controllers,
|
||
|
List<RxString> errMsgs,
|
||
|
ServerConfig config,
|
||
|
) async {
|
||
|
config.idServer = config.idServer.trim();
|
||
|
config.relayServer = config.relayServer.trim();
|
||
|
config.apiServer = config.apiServer.trim();
|
||
|
config.key = config.key.trim();
|
||
|
// id
|
||
|
if (config.idServer.isNotEmpty) {
|
||
|
errMsgs[0].value =
|
||
|
translate(await bind.mainTestIfValidServer(server: config.idServer));
|
||
|
if (errMsgs[0].isNotEmpty) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
// relay
|
||
|
if (config.relayServer.isNotEmpty) {
|
||
|
errMsgs[1].value =
|
||
|
translate(await bind.mainTestIfValidServer(server: config.relayServer));
|
||
|
if (errMsgs[1].isNotEmpty) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
// api
|
||
|
if (config.apiServer.isNotEmpty) {
|
||
|
if (!config.apiServer.startsWith('http://') &&
|
||
|
!config.apiServer.startsWith('https://')) {
|
||
|
errMsgs[2].value =
|
||
|
'${translate("API Server")}: ${translate("invalid_http")}';
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
final oldApiServer = await bind.mainGetApiServer();
|
||
|
|
||
|
// should set one by one
|
||
|
await bind.mainSetOption(
|
||
|
key: 'custom-rendezvous-server', value: config.idServer);
|
||
|
await bind.mainSetOption(key: 'relay-server', value: config.relayServer);
|
||
|
await bind.mainSetOption(key: 'api-server', value: config.apiServer);
|
||
|
await bind.mainSetOption(key: 'key', value: config.key);
|
||
|
|
||
|
final newApiServer = await bind.mainGetApiServer();
|
||
|
if (oldApiServer.isNotEmpty &&
|
||
|
oldApiServer != newApiServer &&
|
||
|
gFFI.userModel.isLogin) {
|
||
|
gFFI.userModel.logOut(apiServer: oldApiServer);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
List<Widget> ServerConfigImportExportWidgets(
|
||
|
List<TextEditingController> controllers,
|
||
|
List<RxString> errMsgs,
|
||
|
) {
|
||
|
import() {
|
||
|
Clipboard.getData(Clipboard.kTextPlain).then((value) {
|
||
|
final text = value?.text;
|
||
|
if (text != null && text.isNotEmpty) {
|
||
|
try {
|
||
|
final sc = ServerConfig.decode(text);
|
||
|
if (sc.idServer.isNotEmpty) {
|
||
|
controllers[0].text = sc.idServer;
|
||
|
controllers[1].text = sc.relayServer;
|
||
|
controllers[2].text = sc.apiServer;
|
||
|
controllers[3].text = sc.key;
|
||
|
Future<bool> success = setServerConfig(controllers, errMsgs, sc);
|
||
|
success.then((value) {
|
||
|
if (value) {
|
||
|
showToast(
|
||
|
translate('Import server configuration successfully'));
|
||
|
} else {
|
||
|
showToast(translate('Invalid server configuration'));
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
showToast(translate('Invalid server configuration'));
|
||
|
}
|
||
|
} catch (e) {
|
||
|
showToast(translate('Invalid server configuration'));
|
||
|
}
|
||
|
} else {
|
||
|
showToast(translate('Clipboard is empty'));
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
export() {
|
||
|
final text = ServerConfig(
|
||
|
idServer: controllers[0].text.trim(),
|
||
|
relayServer: controllers[1].text.trim(),
|
||
|
apiServer: controllers[2].text.trim(),
|
||
|
key: controllers[3].text.trim())
|
||
|
.encode();
|
||
|
debugPrint("ServerConfig export: $text");
|
||
|
Clipboard.setData(ClipboardData(text: text));
|
||
|
showToast(translate('Export server configuration successfully'));
|
||
|
}
|
||
|
|
||
|
return [
|
||
|
Tooltip(
|
||
|
message: translate('Import Server Config'),
|
||
|
child: IconButton(
|
||
|
icon: Icon(Icons.paste, color: Colors.grey), onPressed: import),
|
||
|
),
|
||
|
Tooltip(
|
||
|
message: translate('Export Server Config'),
|
||
|
child: IconButton(
|
||
|
icon: Icon(Icons.copy, color: Colors.grey), onPressed: export))
|
||
|
];
|
||
|
}
|