2023-08-31 20:30:20 +08:00
|
|
|
import 'package:debounce_throttle/debounce_throttle.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
import 'package:flutter_hbb/common.dart';
|
2023-11-13 19:29:16 +08:00
|
|
|
import 'package:flutter_hbb/consts.dart';
|
2023-12-11 15:32:13 +08:00
|
|
|
import 'package:flutter_hbb/models/desktop_render_texture.dart';
|
2023-08-31 20:30:20 +08:00
|
|
|
import 'package:flutter_hbb/models/platform_model.dart';
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
|
|
|
customImageQualityWidget(
|
|
|
|
{required double initQuality,
|
2023-11-09 15:24:57 +08:00
|
|
|
required double initFps,
|
2023-08-31 20:30:20 +08:00
|
|
|
required Function(double) setQuality,
|
2023-11-09 15:24:57 +08:00
|
|
|
required Function(double) setFps,
|
|
|
|
required bool showFps,
|
2023-11-02 20:39:56 +08:00
|
|
|
required bool showMoreQuality}) {
|
2023-11-13 19:29:16 +08:00
|
|
|
if (initQuality < kMinQuality ||
|
|
|
|
initQuality > (showMoreQuality ? kMaxMoreQuality : kMaxQuality)) {
|
|
|
|
initQuality = kDefaultQuality;
|
|
|
|
}
|
|
|
|
if (initFps < kMinFps || initFps > kMaxFps) {
|
|
|
|
initFps = kDefaultFps;
|
2023-11-02 20:39:56 +08:00
|
|
|
}
|
2023-08-31 20:30:20 +08:00
|
|
|
final qualityValue = initQuality.obs;
|
2023-11-09 15:24:57 +08:00
|
|
|
final fpsValue = initFps.obs;
|
2023-08-31 20:30:20 +08:00
|
|
|
|
2023-11-13 19:29:16 +08:00
|
|
|
final RxBool moreQualityChecked = RxBool(qualityValue.value > kMaxQuality);
|
2023-08-31 20:30:20 +08:00
|
|
|
final debouncerQuality = Debouncer<double>(
|
|
|
|
Duration(milliseconds: 1000),
|
|
|
|
onChanged: (double v) {
|
|
|
|
setQuality(v);
|
|
|
|
},
|
|
|
|
initialValue: qualityValue.value,
|
|
|
|
);
|
2023-11-09 15:24:57 +08:00
|
|
|
final debouncerFps = Debouncer<double>(
|
|
|
|
Duration(milliseconds: 1000),
|
|
|
|
onChanged: (double v) {
|
|
|
|
setFps(v);
|
|
|
|
},
|
|
|
|
initialValue: fpsValue.value,
|
|
|
|
);
|
2023-08-31 20:30:20 +08:00
|
|
|
|
|
|
|
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,
|
2023-11-13 19:29:16 +08:00
|
|
|
min: kMinQuality,
|
|
|
|
max: moreQualityChecked.value ? kMaxMoreQuality : kMaxQuality,
|
|
|
|
divisions: moreQualityChecked.value
|
|
|
|
? ((kMaxMoreQuality - kMinQuality) / 10).round()
|
|
|
|
: ((kMaxQuality - kMinQuality) / 5).round(),
|
2023-08-31 20:30:20 +08:00
|
|
|
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
|
2023-11-02 20:39:56 +08:00
|
|
|
if (showMoreQuality && !isMobile)
|
2023-08-31 20:30:20 +08:00
|
|
|
Expanded(
|
|
|
|
flex: 1,
|
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
Checkbox(
|
|
|
|
value: moreQualityChecked.value,
|
|
|
|
onChanged: onMoreChanged,
|
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: Text(translate('More')),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
))
|
|
|
|
],
|
|
|
|
)),
|
2023-11-02 20:39:56 +08:00
|
|
|
if (showMoreQuality && isMobile)
|
2023-08-31 20:30:20 +08:00
|
|
|
Obx(() => Row(
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
child: Align(
|
|
|
|
alignment: Alignment.centerRight,
|
|
|
|
child: Checkbox(
|
|
|
|
value: moreQualityChecked.value,
|
|
|
|
onChanged: onMoreChanged,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: Text(translate('More')),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
)),
|
2023-11-09 15:24:57 +08:00
|
|
|
if (showFps)
|
|
|
|
Obx(() => Row(
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
flex: 3,
|
|
|
|
child: Slider(
|
|
|
|
value: fpsValue.value,
|
2023-11-13 19:29:16 +08:00
|
|
|
min: kMinFps,
|
|
|
|
max: kMaxFps,
|
|
|
|
divisions: ((kMaxFps - kMinFps) / 5).round(),
|
2023-11-09 15:24:57 +08:00
|
|
|
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),
|
|
|
|
))
|
|
|
|
],
|
|
|
|
)),
|
2023-08-31 20:30:20 +08:00
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
customImageQualitySetting() {
|
|
|
|
final qualityKey = 'custom_image_quality';
|
2023-11-09 15:24:57 +08:00
|
|
|
final fpsKey = 'custom-fps';
|
2023-08-31 20:30:20 +08:00
|
|
|
|
|
|
|
var initQuality =
|
2023-11-13 19:29:16 +08:00
|
|
|
(double.tryParse(bind.mainGetUserDefaultOption(key: qualityKey)) ??
|
|
|
|
kDefaultQuality);
|
|
|
|
var initFps = (double.tryParse(bind.mainGetUserDefaultOption(key: fpsKey)) ??
|
|
|
|
kDefaultFps);
|
2023-08-31 20:30:20 +08:00
|
|
|
|
|
|
|
return customImageQualityWidget(
|
|
|
|
initQuality: initQuality,
|
2023-11-09 15:24:57 +08:00
|
|
|
initFps: initFps,
|
2023-08-31 20:30:20 +08:00
|
|
|
setQuality: (v) {
|
|
|
|
bind.mainSetUserDefaultOption(key: qualityKey, value: v.toString());
|
|
|
|
},
|
2023-11-09 15:24:57 +08:00
|
|
|
setFps: (v) {
|
|
|
|
bind.mainSetUserDefaultOption(key: fpsKey, value: v.toString());
|
|
|
|
},
|
|
|
|
showFps: true,
|
2023-11-02 20:39:56 +08:00
|
|
|
showMoreQuality: true);
|
2023-08-31 20:30:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
List<Widget> ServerConfigImportExportWidgets(
|
|
|
|
List<TextEditingController> controllers,
|
|
|
|
List<RxString> errMsgs,
|
|
|
|
) {
|
|
|
|
import() {
|
|
|
|
Clipboard.getData(Clipboard.kTextPlain).then((value) {
|
2023-12-03 20:31:48 +08:00
|
|
|
importConfig(controllers, errMsgs, value?.text);
|
2023-08-31 20:30:20 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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(
|
2023-11-06 20:12:01 +08:00
|
|
|
message: translate('Import server config'),
|
2023-08-31 20:30:20 +08:00
|
|
|
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))
|
|
|
|
];
|
|
|
|
}
|
2023-12-11 15:32:13 +08:00
|
|
|
|
|
|
|
List<(String, String)> otherDefaultSettings() {
|
|
|
|
List<(String, String)> v = [
|
|
|
|
('View Mode', 'view_only'),
|
|
|
|
if (isDesktop) ('show_monitors_tip', kKeyShowMonitorsToolbar),
|
|
|
|
if (isDesktop) ('Collapse toolbar', 'collapse_toolbar'),
|
|
|
|
('Show remote cursor', 'show_remote_cursor'),
|
|
|
|
if (isDesktop) ('Zoom cursor', 'zoom-cursor'),
|
|
|
|
('Show quality monitor', 'show_quality_monitor'),
|
|
|
|
('Mute', 'disable_audio'),
|
|
|
|
if (isDesktop) ('Enable file copy and paste', 'enable_file_transfer'),
|
|
|
|
('Disable clipboard', 'disable_clipboard'),
|
|
|
|
('Lock after session end', 'lock_after_session_end'),
|
|
|
|
('Privacy mode', 'privacy_mode'),
|
|
|
|
if (isMobile) ('Touch mode', 'touch-mode'),
|
|
|
|
('True color (4:4:4)', 'i444'),
|
2024-02-23 22:49:53 +08:00
|
|
|
('Reverse mouse wheel', kKeyReverseMouseWheel),
|
2023-12-11 15:32:13 +08:00
|
|
|
('swap-left-right-mouse', 'swap-left-right-mouse'),
|
|
|
|
if (isDesktop && useTextureRender)
|
|
|
|
(
|
|
|
|
'Show displays as individual windows',
|
|
|
|
kKeyShowDisplaysAsIndividualWindows
|
|
|
|
),
|
|
|
|
if (isDesktop && useTextureRender)
|
|
|
|
(
|
|
|
|
'Use all my displays for the remote session',
|
|
|
|
kKeyUseAllMyDisplaysForTheRemoteSession
|
|
|
|
)
|
|
|
|
];
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|