add option to hide stop-service when service is running (#14563)

* add option to hide stop-service when service is running

Signed-off-by: 21pages <sunboeasy@gmail.com>

* update hbb_common to upstream

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages
2026-03-19 20:04:10 +08:00
committed by GitHub
parent c0da4a6645
commit c457b0e7d3
9 changed files with 87 additions and 36 deletions

View File

@@ -311,7 +311,10 @@ class FloatingWindowService : Service(), View.OnTouchListener {
popupMenu.menu.add(0, idSyncClipboard, 0, translate("Update client clipboard")) popupMenu.menu.add(0, idSyncClipboard, 0, translate("Update client clipboard"))
} }
val idStopService = 2 val idStopService = 2
val hideStopService = FFI.getBuildinOption("hide-stop-service") == "Y"
if (!hideStopService) {
popupMenu.menu.add(0, idStopService, 0, translate("Stop service")) popupMenu.menu.add(0, idStopService, 0, translate("Stop service"))
}
popupMenu.setOnMenuItemClickListener { menuItem -> popupMenu.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) { when (menuItem.itemId) {
idShowRustDesk -> { idShowRustDesk -> {
@@ -389,4 +392,3 @@ class FloatingWindowService : Service(), View.OnTouchListener {
return false return false
} }
} }

View File

@@ -24,6 +24,7 @@ object FFI {
external fun setFrameRawEnable(name: String, value: Boolean) external fun setFrameRawEnable(name: String, value: Boolean)
external fun setCodecInfo(info: String) external fun setCodecInfo(info: String)
external fun getLocalOption(key: String): String external fun getLocalOption(key: String): String
external fun getBuildinOption(key: String): String
external fun onClipboardUpdate(clips: ByteBuffer) external fun onClipboardUpdate(clips: ByteBuffer)
external fun isServiceClipboardEnabled(): Boolean external fun isServiceClipboardEnabled(): Boolean
} }

View File

@@ -175,6 +175,7 @@ const String kOptionEnableFlutterHttpOnRust = "enable-flutter-http-on-rust";
const String kOptionHideServerSetting = "hide-server-settings"; const String kOptionHideServerSetting = "hide-server-settings";
const String kOptionHideProxySetting = "hide-proxy-settings"; const String kOptionHideProxySetting = "hide-proxy-settings";
const String kOptionHideWebSocketSetting = "hide-websocket-settings"; const String kOptionHideWebSocketSetting = "hide-websocket-settings";
const String kOptionHideStopService = "hide-stop-service";
const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings"; const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings";
const String kOptionHideSecuritySetting = "hide-security-settings"; const String kOptionHideSecuritySetting = "hide-security-settings";
const String kOptionHideNetworkSetting = "hide-network-settings"; const String kOptionHideNetworkSetting = "hide-network-settings";

View File

@@ -458,8 +458,16 @@ class _GeneralState extends State<_General> {
return const Offstage(); return const Offstage();
} }
final hideStopService =
bind.mainGetBuildinOption(key: kOptionHideStopService) == 'Y';
return Obx(() {
if (hideStopService && !serviceStop.value) {
return const Offstage();
}
return _Card(title: 'Service', children: [ return _Card(title: 'Service', children: [
Obx(() => _Button(serviceStop.value ? 'Start' : 'Stop', () { _Button(serviceStop.value ? 'Start' : 'Stop', () {
() async { () async {
serviceBtnEnabled.value = false; serviceBtnEnabled.value = false;
await start_service(serviceStop.value); await start_service(serviceStop.value);
@@ -468,8 +476,9 @@ class _GeneralState extends State<_General> {
serviceBtnEnabled.value = true; serviceBtnEnabled.value = true;
}); });
}(); }();
}, enabled: serviceBtnEnabled.value)) }, enabled: serviceBtnEnabled.value)
]); ]);
});
} }
Widget other() { Widget other() {

View File

@@ -582,10 +582,13 @@ class _PermissionCheckerState extends State<PermissionChecker> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serverModel = Provider.of<ServerModel>(context); final serverModel = Provider.of<ServerModel>(context);
final hasAudioPermission = androidVersion >= 30; final hasAudioPermission = androidVersion >= 30;
final hideStopService =
isAndroid &&
bind.mainGetBuildinOption(key: kOptionHideStopService) == 'Y';
return PaddingCard( return PaddingCard(
title: translate("Permissions"), title: translate("Permissions"),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
serverModel.mediaOk serverModel.mediaOk && !hideStopService
? ElevatedButton.icon( ? ElevatedButton.icon(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: backgroundColor:
@@ -595,6 +598,7 @@ class _PermissionCheckerState extends State<PermissionChecker> {
label: Text(translate("Stop service"))) label: Text(translate("Stop service")))
.marginOnly(bottom: 8) .marginOnly(bottom: 8)
: SizedBox.shrink(), : SizedBox.shrink(),
if (!hideStopService || !serverModel.mediaOk)
PermissionRow( PermissionRow(
translate("Screen Capture"), translate("Screen Capture"),
serverModel.mediaOk, serverModel.mediaOk,

View File

@@ -3049,6 +3049,22 @@ pub mod server_side {
return env.new_string(res).unwrap_or_default().into_raw(); return env.new_string(res).unwrap_or_default().into_raw();
} }
#[no_mangle]
pub unsafe extern "system" fn Java_ffi_FFI_getBuildinOption(
env: JNIEnv,
_class: JClass,
key: JString,
) -> jstring {
let mut env = env;
let res = if let Ok(key) = env.get_string(&key) {
let key: String = key.into();
super::get_builtin_option(&key)
} else {
"".into()
};
return env.new_string(res).unwrap_or_default().into_raw();
}
#[no_mangle] #[no_mangle]
pub unsafe extern "system" fn Java_ffi_FFI_isServiceClipboardEnabled( pub unsafe extern "system" fn Java_ffi_FFI_isServiceClipboardEnabled(
env: JNIEnv, env: JNIEnv,

View File

@@ -54,9 +54,22 @@ fn make_tray() -> hbb_common::ResultType<()> {
let mut event_loop = EventLoopBuilder::new().build(); let mut event_loop = EventLoopBuilder::new().build();
let tray_menu = Menu::new(); let tray_menu = Menu::new();
let quit_i = MenuItem::new(translate("Stop service".to_owned()), true, None); let hide_stop_service = crate::ui_interface::get_builtin_option(
hbb_common::config::keys::OPTION_HIDE_STOP_SERVICE,
) == "Y";
// The tray icon is only shown when the service is running, so we don't need to check
// the `stop-service` option here.
let quit_i = if !hide_stop_service {
Some(MenuItem::new(translate("Stop service".to_owned()), true, None))
} else {
None
};
let open_i = MenuItem::new(translate("Open".to_owned()), true, None); let open_i = MenuItem::new(translate("Open".to_owned()), true, None);
tray_menu.append_items(&[&open_i, &quit_i]).ok(); if let Some(quit_i) = &quit_i {
tray_menu.append_items(&[&open_i, quit_i]).ok();
} else {
tray_menu.append_items(&[&open_i]).ok();
}
let tooltip = |count: usize| { let tooltip = |count: usize| {
if count == 0 { if count == 0 {
format!( format!(
@@ -155,6 +168,7 @@ fn make_tray() -> hbb_common::ResultType<()> {
} }
if let Ok(event) = menu_channel.try_recv() { if let Ok(event) = menu_channel.try_recv() {
if let Some(quit_i) = &quit_i {
if event.id == quit_i.id() { if event.id == quit_i.id() {
/* failed in windows, seems no permission to check system process /* failed in windows, seems no permission to check system process
if !crate::check_process("--server", false) { if !crate::check_process("--server", false) {
@@ -168,6 +182,9 @@ fn make_tray() -> hbb_common::ResultType<()> {
} else if event.id == open_i.id() { } else if event.id == open_i.id() {
open_func(); open_func();
} }
} else if event.id == open_i.id() {
open_func();
}
} }
if let Ok(_event) = tray_channel.try_recv() { if let Ok(_event) = tray_channel.try_recv() {

View File

@@ -16,6 +16,7 @@ const disable_ab = handler.is_disable_ab();
const hide_server_settings = handler.get_builtin_option("hide-server-settings") == "Y"; const hide_server_settings = handler.get_builtin_option("hide-server-settings") == "Y";
const hide_proxy_settings = handler.get_builtin_option("hide-proxy-settings") == "Y"; const hide_proxy_settings = handler.get_builtin_option("hide-proxy-settings") == "Y";
const hide_websocket_settings = handler.get_builtin_option("hide-websocket-settings") == "Y"; const hide_websocket_settings = handler.get_builtin_option("hide-websocket-settings") == "Y";
const hide_stop_service = handler.get_builtin_option("hide-stop-service") == "Y";
const disable_change_permanent_password = handler.get_builtin_option("disable-change-permanent-password") == "Y"; const disable_change_permanent_password = handler.get_builtin_option("disable-change-permanent-password") == "Y";
const disable_change_id = handler.get_builtin_option("disable-change-id") == "Y"; const disable_change_id = handler.get_builtin_option("disable-change-id") == "Y";
@@ -532,7 +533,7 @@ class MyIdMenu: Reactor.Component {
{!disable_settings && !using_public_server && !outgoing_only && <li #disable-udp class={disable_udp ? "selected" : "line-through"}><span>{svg_checkmark}</span>{translate('Disable UDP')}</li>} {!disable_settings && !using_public_server && !outgoing_only && <li #disable-udp class={disable_udp ? "selected" : "line-through"}><span>{svg_checkmark}</span>{translate('Disable UDP')}</li>}
{!disable_settings && !using_public_server && <li #allow-insecure-tls-fallback><span>{svg_checkmark}</span>{translate('Allow insecure TLS fallback')}</li>} {!disable_settings && !using_public_server && <li #allow-insecure-tls-fallback><span>{svg_checkmark}</span>{translate('Allow insecure TLS fallback')}</li>}
<div .separator /> <div .separator />
<li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable service")}</li> {(!hide_stop_service || service_stopped) && <li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable service")}</li>}
{!disable_settings && is_win && handler.is_installed() ? <ShareRdp /> : ""} {!disable_settings && is_win && handler.is_installed() ? <ShareRdp /> : ""}
{!disable_settings && <DirectServer />} {!disable_settings && <DirectServer />}
{!disable_settings && false && handler.using_public_server() && <li #allow-always-relay><span>{svg_checkmark}</span>{translate('Always connect via relay')}</li>} {!disable_settings && false && handler.using_public_server() && <li #allow-always-relay><span>{svg_checkmark}</span>{translate('Always connect via relay')}</li>}