feat: make daemon optional (#1450)

Drew Smirnoff created

## What?

Makes Background daemon optional in the settings

## Why?

Temporary fix for #1448, also a good option to have for users to turn
off, if they do not want the daemon on.

---------

Signed-off-by: drew <me@andrinoff.com>

Change summary

config/config.go        |  5 +++++
daemonclient/service.go |  7 ++++++-
i18n/locales/ar.json    |  1 +
i18n/locales/de.json    |  1 +
i18n/locales/en.json    |  1 +
i18n/locales/es.json    |  1 +
i18n/locales/fr.json    |  1 +
i18n/locales/ja.json    |  1 +
i18n/locales/pl.json    |  1 +
i18n/locales/pt.json    |  1 +
i18n/locales/ru.json    |  1 +
i18n/locales/uk.json    |  1 +
i18n/locales/zh.json    |  1 +
tui/settings_general.go | 21 +++++++++++++--------
14 files changed, 35 insertions(+), 9 deletions(-)

Detailed changes

config/config.go 🔗

@@ -119,6 +119,7 @@ type Config struct {
 	DisableImages           bool          `json:"disable_images,omitempty"`
 	HideTips                bool          `json:"hide_tips,omitempty"`
 	DisableNotifications    bool          `json:"disable_notifications,omitempty"`
+	DisableDaemon           bool          `json:"disable_daemon,omitempty"`
 	EnableSplitPane         bool          `json:"enable_split_pane,omitempty"`
 	EnableThreaded          bool          `json:"enable_threaded,omitempty"`
 	EnableDetailedDates     bool          `json:"enable_detailed_dates,omitempty"`
@@ -452,6 +453,7 @@ type secureDiskConfig struct {
 	DisableImages           bool                              `json:"disable_images,omitempty"`
 	HideTips                bool                              `json:"hide_tips,omitempty"`
 	DisableNotifications    bool                              `json:"disable_notifications,omitempty"`
+	DisableDaemon           bool                              `json:"disable_daemon,omitempty"`
 	EnableSplitPane         bool                              `json:"enable_split_pane,omitempty"`
 	EnableThreaded          bool                              `json:"enable_threaded,omitempty"`
 	EnableDetailedDates     bool                              `json:"enable_detailed_dates,omitempty"`
@@ -502,6 +504,7 @@ func SaveConfig(config *Config) error {
 			DisableImages:           config.DisableImages,
 			HideTips:                config.HideTips,
 			DisableNotifications:    config.DisableNotifications,
+			DisableDaemon:           config.DisableDaemon,
 			EnableSplitPane:         config.EnableSplitPane,
 			EnableThreaded:          config.EnableThreaded,
 			EnableDetailedDates:     config.EnableDetailedDates,
@@ -610,6 +613,7 @@ func LoadConfig() (*Config, error) {
 		DisableImages           bool                              `json:"disable_images,omitempty"`
 		HideTips                bool                              `json:"hide_tips,omitempty"`
 		DisableNotifications    bool                              `json:"disable_notifications,omitempty"`
+		DisableDaemon           bool                              `json:"disable_daemon,omitempty"`
 		EnableSplitPane         bool                              `json:"enable_split_pane,omitempty"`
 		EnableThreaded          bool                              `json:"enable_threaded,omitempty"`
 		EnableDetailedDates     bool                              `json:"enable_detailed_dates,omitempty"`
@@ -653,6 +657,7 @@ func LoadConfig() (*Config, error) {
 	config.DisableImages = raw.DisableImages
 	config.HideTips = raw.HideTips
 	config.DisableNotifications = raw.DisableNotifications
+	config.DisableDaemon = raw.DisableDaemon
 	config.EnableSplitPane = raw.EnableSplitPane
 	config.EnableThreaded = raw.EnableThreaded
 	config.EnableDetailedDates = raw.EnableDetailedDates

daemonclient/service.go 🔗

@@ -42,8 +42,13 @@ type Service interface {
 }
 
 // NewService connects to the daemon, auto-starting it if needed.
-// Falls back to direct mode only if daemon cannot be started.
+// Falls back to direct mode only if daemon cannot be started, or if DisableDaemon is set.
 func NewService(cfg *config.Config) Service {
+	if cfg.DisableDaemon {
+		log.Println("service: daemon disabled by config, using direct mode")
+		return newDirectService(cfg)
+	}
+
 	// Try connecting to existing daemon.
 	if svc := tryConnect(); svc != nil {
 		return svc

i18n/locales/ar.json 🔗

@@ -154,6 +154,7 @@
       "disable_images": "تعطيل عرض الصور",
       "hide_tips": "إخفاء النصائح السياقية",
       "disable_notifications": "تعطيل الإشعارات",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "عرض مقسم",
       "enable_threaded": "عرض المحادثات",
       "enable_detailed_dates": "تواريخ مفصلة",

i18n/locales/de.json 🔗

@@ -150,6 +150,7 @@
       "disable_images": "Bildanzeige Deaktivieren",
       "hide_tips": "Kontextuelle Tipps Ausblenden",
       "disable_notifications": "Benachrichtigungen Deaktivieren",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Geteilte Ansicht",
       "enable_threaded": "Konversations-Threads",
       "enable_detailed_dates": "Detaillierte Datumsangaben",

i18n/locales/en.json 🔗

@@ -152,6 +152,7 @@
       "disable_images": "Disable Image Display",
       "hide_tips": "Hide Contextual Tips",
       "disable_notifications": "Disable Notifications",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Split Pane View",
       "enable_threaded": "Threaded Conversation View",
       "enable_detailed_dates": "Detailed Dates",

i18n/locales/es.json 🔗

@@ -150,6 +150,7 @@
       "disable_images": "Deshabilitar Visualización de Imágenes",
       "hide_tips": "Ocultar Consejos Contextuales",
       "disable_notifications": "Deshabilitar Notificaciones",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Vista dividida",
       "enable_threaded": "Vista de conversación",
       "enable_detailed_dates": "Fechas detalladas",

i18n/locales/fr.json 🔗

@@ -150,6 +150,7 @@
       "disable_images": "Désactiver l'Affichage des Images",
       "hide_tips": "Masquer les Conseils Contextuels",
       "disable_notifications": "Désactiver les Notifications",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Vue divisée",
       "enable_threaded": "Vue par conversation",
       "enable_detailed_dates": "Dates détaillées",

i18n/locales/ja.json 🔗

@@ -148,6 +148,7 @@
       "disable_images": "画像表示を無効化",
       "hide_tips": "コンテキストヒントを非表示",
       "disable_notifications": "通知を無効化",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "分割ビュー",
       "enable_threaded": "スレッド表示",
       "enable_detailed_dates": "詳細な日付",

i18n/locales/pl.json 🔗

@@ -154,6 +154,7 @@
       "disable_images": "Wyłącz Wyświetlanie Obrazów",
       "hide_tips": "Ukryj Wskazówki Kontekstowe",
       "disable_notifications": "Wyłącz Powiadomienia",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Widok podzielony",
       "enable_threaded": "Widok wątków",
       "enable_detailed_dates": "Szczegółowe daty",

i18n/locales/pt.json 🔗

@@ -150,6 +150,7 @@
       "disable_images": "Desativar Exibição de Imagens",
       "hide_tips": "Ocultar Dicas Contextuais",
       "disable_notifications": "Desativar Notificações",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Vista dividida",
       "enable_threaded": "Vista de conversação",
       "enable_detailed_dates": "Datas detalhadas",

i18n/locales/ru.json 🔗

@@ -154,6 +154,7 @@
       "disable_images": "Отключить Отображение Изображений",
       "hide_tips": "Скрыть Контекстные Подсказки",
       "disable_notifications": "Отключить Уведомления",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Разделённый вид",
       "enable_threaded": "Просмотр беседами",
       "enable_detailed_dates": "Подробные даты",

i18n/locales/uk.json 🔗

@@ -152,6 +152,7 @@
       "disable_images": "Вимкнути показ зображень",
       "hide_tips": "Приховати контекстні підказки",
       "disable_notifications": "Вимкнути сповіщення",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "Розділений вигляд",
       "enable_threaded": "Перегляд розмов",
       "enable_detailed_dates": "Детальні дати",

i18n/locales/zh.json 🔗

@@ -148,6 +148,7 @@
       "disable_images": "禁用图片显示",
       "hide_tips": "隐藏上下文提示",
       "disable_notifications": "禁用通知",
+      "disable_daemon": "Background Daemon",
       "enable_split_pane": "分屏视图",
       "enable_threaded": "会话视图",
       "enable_detailed_dates": "详细日期",

tui/settings_general.go 🔗

@@ -20,6 +20,7 @@ func (m *Settings) buildGeneralOptions() []generalOption {
 		{"settings_general.disable_images", onOff(m.cfg.DisableImages), "Prevent images from loading automatically in emails."},
 		{"settings_general.hide_tips", onOff(m.cfg.HideTips), "Hide helpful hints displayed at the bottom of the screen."},
 		{"settings_general.disable_notifications", onOff(m.cfg.DisableNotifications), "Turn off desktop notifications for new mail."},
+		{"settings_general.disable_daemon", onOff(!m.cfg.DisableDaemon), "Run a background daemon for push notifications and sync. Takes effect on restart."},
 		{"settings_general.enable_split_pane", onOff(m.cfg.EnableSplitPane), "View inbox and email side-by-side."},
 		{"settings_general.enable_threaded", onOff(m.cfg.EnableThreaded), "Group emails into conversations by reply chain. Per-folder overrides are kept."},
 		{"settings_general.enable_detailed_dates", onOff(m.cfg.EnableDetailedDates), "Show detailed inbox dates."},
@@ -57,27 +58,31 @@ func (m *Settings) updateGeneral(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
 				m.cfg.DisableNotifications = !m.cfg.DisableNotifications
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 3: // Split Pane View
+			case 3: // Background Daemon
+				m.cfg.DisableDaemon = !m.cfg.DisableDaemon
+				_ = config.SaveConfig(m.cfg)
+				saved = true
+			case 4: // Split Pane View
 				m.cfg.EnableSplitPane = !m.cfg.EnableSplitPane
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 4: // Threaded Conversation View
+			case 5: // Threaded Conversation View
 				m.cfg.EnableThreaded = !m.cfg.EnableThreaded
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 5: // Detailed Dates
+			case 6: // Detailed Dates
 				m.cfg.EnableDetailedDates = !m.cfg.EnableDetailedDates
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 6: // Spellcheck
+			case 7: // Spellcheck
 				m.cfg.DisableSpellcheck = !m.cfg.DisableSpellcheck
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 7: // Spell Suggestions
+			case 8: // Spell Suggestions
 				m.cfg.DisableSpellSuggestions = !m.cfg.DisableSpellSuggestions
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 8: // Date Format
+			case 9: // Date Format
 				switch m.cfg.DateFormat {
 				case config.DateFormatEU:
 					m.cfg.DateFormat = config.DateFormatUS
@@ -88,7 +93,7 @@ func (m *Settings) updateGeneral(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
 				}
 				_ = config.SaveConfig(m.cfg)
 				saved = true
-			case 9: // Language
+			case 10: // Language
 				// Cycle through available languages
 				langs := i18n.LanguageCodes()
 				currentLang := m.cfg.GetLanguage()
@@ -109,7 +114,7 @@ func (m *Settings) updateGeneral(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
 					func() tea.Msg { return ConfigSavedMsg{} },
 					func() tea.Msg { return LanguageChangedMsg{} },
 				)
-			case 10: // Edit Signature
+			case 11: // Edit Signature
 				if msg.String() == keyEnter || msg.String() == keyRight || msg.String() == "l" {
 					return m, func() tea.Msg { return GoToSignatureEditorMsg{} }
 				}