mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-25 21:27:55 +08:00
bc875a35b0
* refact: multi_window_soft_rendering Signed-off-by: fufesou <linlong1266@gmail.com> * fix: window pos, potential wait for image Signed-off-by: fufesou <linlong1266@gmail.com> * comments Signed-off-by: fufesou <linlong1266@gmail.com> * remove debug print Signed-off-by: fufesou <linlong1266@gmail.com> * explicitly set rgba_data.size_got to false after init Signed-off-by: fufesou <linlong1266@gmail.com> * refact: multi window, merge images, render with texture Signed-off-by: fufesou <linlong1266@gmail.com> * revert, flutter.rs, rgba valid Signed-off-by: fufesou <linlong1266@gmail.com> * Add displays index before sending capture msg Signed-off-by: fufesou <linlong1266@gmail.com> * refact: multi window, soft rendering Signed-off-by: fufesou <linlong1266@gmail.com> * fix: build Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
251 lines
8.1 KiB
Dart
251 lines
8.1 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/consts.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,
|
|
required bool showMoreQuality}) {
|
|
if (initQuality < kMinQuality ||
|
|
initQuality > (showMoreQuality ? kMaxMoreQuality : kMaxQuality)) {
|
|
initQuality = kDefaultQuality;
|
|
}
|
|
if (initFps < kMinFps || initFps > kMaxFps) {
|
|
initFps = kDefaultFps;
|
|
}
|
|
final qualityValue = initQuality.obs;
|
|
final fpsValue = initFps.obs;
|
|
|
|
final RxBool moreQualityChecked = RxBool(qualityValue.value > kMaxQuality);
|
|
final debouncerQuality = Debouncer<double>(
|
|
Duration(milliseconds: 1000),
|
|
onChanged: setQuality,
|
|
initialValue: qualityValue.value,
|
|
);
|
|
final debouncerFps = Debouncer<double>(
|
|
Duration(milliseconds: 1000),
|
|
onChanged: setFps,
|
|
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: kMinQuality,
|
|
max: moreQualityChecked.value ? kMaxMoreQuality : kMaxQuality,
|
|
divisions: moreQualityChecked.value
|
|
? ((kMaxMoreQuality - kMinQuality) / 10).round()
|
|
: ((kMaxQuality - kMinQuality) / 5).round(),
|
|
onChanged: setQuality == null
|
|
? null
|
|
: (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 (showMoreQuality && !isMobile)
|
|
Expanded(
|
|
flex: 1,
|
|
child: Row(
|
|
children: [
|
|
Checkbox(
|
|
value: moreQualityChecked.value,
|
|
onChanged: onMoreChanged,
|
|
),
|
|
Expanded(
|
|
child: Text(translate('More')),
|
|
)
|
|
],
|
|
))
|
|
],
|
|
)),
|
|
if (showMoreQuality && 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: kMinFps,
|
|
max: kMaxFps,
|
|
divisions: ((kMaxFps - kMinFps) / 5).round(),
|
|
onChanged: setFps == null
|
|
? null
|
|
: (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';
|
|
|
|
final initQuality =
|
|
(double.tryParse(bind.mainGetUserDefaultOption(key: qualityKey)) ??
|
|
kDefaultQuality);
|
|
final isQuanlityFixed = isOptionFixed(qualityKey);
|
|
final initFps =
|
|
(double.tryParse(bind.mainGetUserDefaultOption(key: fpsKey)) ??
|
|
kDefaultFps);
|
|
final isFpsFixed = isOptionFixed(fpsKey);
|
|
|
|
return customImageQualityWidget(
|
|
initQuality: initQuality,
|
|
initFps: initFps,
|
|
setQuality: isQuanlityFixed
|
|
? null
|
|
: (v) {
|
|
bind.mainSetUserDefaultOption(
|
|
key: qualityKey, value: v.toString());
|
|
},
|
|
setFps: isFpsFixed
|
|
? null
|
|
: (v) {
|
|
bind.mainSetUserDefaultOption(key: fpsKey, value: v.toString());
|
|
},
|
|
showFps: true,
|
|
showMoreQuality: true);
|
|
}
|
|
|
|
List<Widget> ServerConfigImportExportWidgets(
|
|
List<TextEditingController> controllers,
|
|
List<RxString> errMsgs,
|
|
) {
|
|
import() {
|
|
Clipboard.getData(Clipboard.kTextPlain).then((value) {
|
|
importConfig(controllers, errMsgs, value?.text);
|
|
});
|
|
}
|
|
|
|
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))
|
|
];
|
|
}
|
|
|
|
List<(String, String)> otherDefaultSettings() {
|
|
List<(String, String)> v = [
|
|
('View Mode', kOptionViewOnly),
|
|
if ((isDesktop || isWebDesktop))
|
|
('show_monitors_tip', kKeyShowMonitorsToolbar),
|
|
if ((isDesktop || isWebDesktop))
|
|
('Collapse toolbar', kOptionCollapseToolbar),
|
|
('Show remote cursor', kOptionShowRemoteCursor),
|
|
('Follow remote cursor', kOptionFollowRemoteCursor),
|
|
('Follow remote window focus', kOptionFollowRemoteWindow),
|
|
if ((isDesktop || isWebDesktop)) ('Zoom cursor', kOptionZoomCursor),
|
|
('Show quality monitor', kOptionShowQualityMonitor),
|
|
('Mute', kOptionDisableAudio),
|
|
if (isDesktop) ('Enable file copy and paste', kOptionEnableFileCopyPaste),
|
|
('Disable clipboard', kOptionDisableClipboard),
|
|
('Lock after session end', kOptionLockAfterSessionEnd),
|
|
('Privacy mode', kOptionPrivacyMode),
|
|
if (isMobile) ('Touch mode', kOptionTouchMode),
|
|
('True color (4:4:4)', kOptionI444),
|
|
('Reverse mouse wheel', kKeyReverseMouseWheel),
|
|
('swap-left-right-mouse', kOptionSwapLeftRightMouse),
|
|
if (isDesktop)
|
|
(
|
|
'Show displays as individual windows',
|
|
kKeyShowDisplaysAsIndividualWindows
|
|
),
|
|
if (isDesktop)
|
|
(
|
|
'Use all my displays for the remote session',
|
|
kKeyUseAllMyDisplaysForTheRemoteSession
|
|
)
|
|
];
|
|
|
|
return v;
|
|
}
|