@@ -8,6 +8,7 @@ namespace Dc {
88 public bool markdown_rendering { get ; set ; default = false ; }
99 public bool shift_enter_sends { get ; set ; default = false ; }
1010 public bool notifications_enabled { get ; set ; default = true ; }
11+ public string rpc_server_path { get ; set ; default = " " ; }
1112
1213 public static string get_config_path () {
1314 return Path . build_filename (
@@ -24,6 +25,7 @@ namespace Dc {
2425 Markdown . enabled = markdown_rendering;
2526 shift_enter_sends = kf_bool (kf, " shift_enter_sends" , false );
2627 notifications_enabled = kf_bool (kf, " notifications_enabled" , true );
28+ rpc_server_path = kf_str (kf, " rpc_server_path" , " " );
2729 }
2830
2931 private static int kf_int (KeyFile kf , string k , int d ) {
@@ -34,6 +36,10 @@ namespace Dc {
3436 try { return kf. get_boolean (" General" , k); } catch { return d; }
3537 }
3638
39+ private static string kf_str (KeyFile kf , string k , string d ) {
40+ try { return kf. get_string (" General" , k); } catch { return d; }
41+ }
42+
3743 public void save_double_click_action (int v ) {
3844 double_click_action = v;
3945 save_to_file ((kf) = > { kf. set_integer (" General" , " double_click_action" , v); });
@@ -54,6 +60,11 @@ namespace Dc {
5460 save_to_file ((kf) = > { kf. set_boolean (" General" , " notifications_enabled" , v); });
5561 }
5662
63+ public void save_rpc_server_path (string v ) {
64+ rpc_server_path = v;
65+ save_to_file ((kf) = > { kf. set_string (" General" , " rpc_server_path" , v); });
66+ }
67+
5768 public void save_to_file (SettingWriter writer ) {
5869 var kf = new KeyFile ();
5970 try {
@@ -76,6 +87,8 @@ namespace Dc {
7687 private Gtk . ListBox accounts_list;
7788 private Gtk . Box content;
7889 private unowned Window app_window;
90+ private Adw . ActionRow rpc_row;
91+ private Gtk . Switch rpc_custom_switch;
7992
8093 public signal void account_changed ();
8194
@@ -196,6 +209,39 @@ namespace Dc {
196209 behavior_list. append (notif_row);
197210 content. append (behavior_list);
198211
212+ /* Advanced section */
213+ var advanced_label = new Gtk .Label (" Advanced" );
214+ advanced_label. add_css_class (" title-3" );
215+ advanced_label. halign = Gtk . Align . START ;
216+ content. append (advanced_label);
217+
218+ var advanced_list = new Gtk .ListBox ();
219+ advanced_list. selection_mode = Gtk . SelectionMode . NONE ;
220+ advanced_list. add_css_class (" boxed-list" );
221+
222+ rpc_row = new Adw .ActionRow ();
223+ rpc_row. title = " deltachat-rpc-server" ;
224+
225+ var rpc_choose_btn = new Gtk .Button .with_label (" Choose…" );
226+ rpc_choose_btn. valign = Gtk . Align . CENTER ;
227+ rpc_choose_btn. add_css_class (" flat" );
228+ rpc_choose_btn. tooltip_text = " Pick a deltachat-rpc-server binary" ;
229+ rpc_choose_btn. clicked. connect (() = > { on_browse_rpc_server. begin (); });
230+ rpc_row. add_suffix (rpc_choose_btn);
231+
232+ rpc_custom_switch = new Gtk .Switch ();
233+ rpc_custom_switch. valign = Gtk . Align . CENTER ;
234+ rpc_custom_switch. tooltip_text = " Use a custom deltachat-rpc-server binary" ;
235+ rpc_custom_switch. active = app_window. settings. rpc_server_path. length > 0 ;
236+ rpc_custom_switch. notify[" active" ]. connect (on_rpc_switch_toggled);
237+ rpc_custom_switch. bind_property (" active" , rpc_choose_btn, " sensitive" ,
238+ BindingFlags . SYNC_CREATE );
239+ rpc_row. add_suffix (rpc_custom_switch);
240+
241+ advanced_list. append (rpc_row);
242+ content. append (advanced_list);
243+ update_rpc_row ();
244+
199245 var scroll = new Gtk .ScrolledWindow ();
200246 scroll. vexpand = true ;
201247 scroll. hscrollbar_policy = Gtk . PolicyType . NEVER ;
@@ -373,6 +419,58 @@ namespace Dc {
373419 " remove" , " Remove" , () = > { do_remove_account. begin (acct_id); });
374420 }
375421
422+ private void update_rpc_row () {
423+ string custom = app_window. settings. rpc_server_path;
424+ if (custom. length > 0 ) {
425+ bool ok = FileUtils . test (custom, FileTest . IS_EXECUTABLE );
426+ rpc_row. subtitle = ok ? " Custom" : " ❌ Custom path is not executable" ;
427+ rpc_row. tooltip_text = custom;
428+ } else {
429+ string ? found = AccountFinder . find_rpc_server ();
430+ rpc_row. subtitle = found != null ? " Auto-detected" : " ❌ Not found" ;
431+ rpc_row. tooltip_text = found ?? " No deltachat-rpc-server binary in the default locations" ;
432+ }
433+ }
434+
435+ private void on_rpc_switch_toggled () {
436+ if (rpc_custom_switch. active) {
437+ on_browse_rpc_server. begin ();
438+ } else if (app_window. settings. rpc_server_path. length > 0 ) {
439+ app_window. settings. save_rpc_server_path (" " );
440+ app_window. show_toast (" Using auto-detected RPC server. Restart to apply." );
441+ update_rpc_row ();
442+ }
443+ }
444+
445+ private async void on_browse_rpc_server () {
446+ var dlg = new Gtk .FileDialog ();
447+ dlg. title = " Locate deltachat-rpc-server" ;
448+ dlg. modal = true ;
449+
450+ string start = app_window. settings. rpc_server_path;
451+ if (start. length == 0 ) start = AccountFinder . find_rpc_server () ?? " " ;
452+ if (start. length > 0 ) dlg. initial_file = File . new_for_path (start);
453+
454+ try {
455+ var file = yield dlg. open (app_window, null );
456+ if (file != null ) {
457+ string ? path = file. get_path ();
458+ if (path != null && FileUtils . test (path, FileTest . IS_EXECUTABLE )) {
459+ app_window. settings. save_rpc_server_path (path);
460+ app_window. show_toast (" RPC server path saved. Restart to apply." );
461+ } else {
462+ show_error (app_window, " Selected file is not an executable binary." );
463+ }
464+ }
465+ } catch (Error e) {
466+ if (! (e is Gtk . DialogError ) && ! (e is IOError . CANCELLED ))
467+ show_error (app_window, e. message);
468+ }
469+ /* Sync switch to actual state — reverts the toggle if nothing was saved. */
470+ rpc_custom_switch. active = app_window. settings. rpc_server_path. length > 0 ;
471+ update_rpc_row ();
472+ }
473+
376474 private async void do_remove_account (int acct_id ) {
377475 try {
378476 yield rpc. remove_account (acct_id);
0 commit comments