From c769bc6d5f395069f1be15c9091b300b26d17bd2 Mon Sep 17 00:00:00 2001
From: "rawaha.elhoussayni@savoirfairelinux.com"
 <rawaha.elhoussayni@savoirfairelinux.com>
Date: Wed, 14 May 2025 10:38:15 -0400
Subject: [PATCH] settings: typing indicator

Add settings toggle to enable or disable the typing
indicator feature.
Change-Id: I9b37bbf922242282eb85eba50267342c56f78b82
---
 Ring/Ring/Constants/Generated/Strings.swift   |  6 +++--
 .../Settings/Me/AccountSettings.swift         | 11 ++++++++
 .../Settings/Me/AccountSettingsViews.swift    | 25 +++++++++++++++++++
 .../Settings/Me/SettingsSummaryView.swift     |  3 +++
 Ring/Ring/Models/ConfigKeyModel.swift         |  1 +
 .../Resources/en.lproj/Localizable.strings    |  3 ++-
 6 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/Ring/Ring/Constants/Generated/Strings.swift b/Ring/Ring/Constants/Generated/Strings.swift
index cd29b0af8..4a25d3303 100644
--- a/Ring/Ring/Constants/Generated/Strings.swift
+++ b/Ring/Ring/Constants/Generated/Strings.swift
@@ -453,8 +453,10 @@ internal enum L10n {
     internal static let turnServer = L10n.tr("Localizable", "accountPage.turnServer", fallback: "TURN address")
     /// TURN username
     internal static let turnUsername = L10n.tr("Localizable", "accountPage.turnUsername", fallback: "TURN username")
-    /// Typing indicator
-    internal static let typingIndicator = L10n.tr("Localizable", "accountPage.typingIndicator", fallback: "Typing indicator")
+    /// Enable typing indicator
+    internal static let typingIndicator = L10n.tr("Localizable", "accountPage.typingIndicator", fallback: "Enable typing indicator")
+    /// Send and receive typing indicators showing that a message is being typed.
+    internal static let typingIndicatorExplanation = L10n.tr("Localizable", "accountPage.typingIndicatorExplanation", fallback: "Send and receive typing indicators showing that a message is being typed.")
     /// Unblock
     internal static let unblockContact = L10n.tr("Localizable", "accountPage.unblockContact", fallback: "Unblock")
     /// Unlink
diff --git a/Ring/Ring/Features/Settings/Me/AccountSettings.swift b/Ring/Ring/Features/Settings/Me/AccountSettings.swift
index 5234b16a7..a7bc27bb2 100644
--- a/Ring/Ring/Features/Settings/Me/AccountSettings.swift
+++ b/Ring/Ring/Features/Settings/Me/AccountSettings.swift
@@ -31,6 +31,7 @@ class AccountSettings: ObservableObject {
     @Published var showNotificationPermitionIssue: Bool = false
     @Published var upnpEnabled: Bool = false
     @Published var turnEnabled: Bool = false
+    @Published var typingIndicator: Bool = true
 
     @Published var autoRegistrationEnabled: Bool = false
     @Published var autoRegistrationExpirationTime = ""
@@ -120,6 +121,7 @@ extension AccountSettings {
         self.proxyAddress = self.account.proxy
         self.callsFromUnknownContacts = self.getBoolState(for: ConfigKey.dhtPublicIn)
         self.peerDiscovery = self.getBoolState(for: ConfigKey.dhtPeerDiscovery)
+        self.typingIndicator = self.getBoolState(for: ConfigKey.typingIndicator)
         self.verifyNotificationPermissionStatus()
         observeNotificationPermissionChanges()
     }
@@ -133,6 +135,15 @@ extension AccountSettings {
         self.callsFromUnknownContacts = enable
     }
 
+    func enableTypingIndicator(enable: Bool) {
+        if self.typingIndicator == enable {
+            return
+        }
+        let property = ConfigKeyModel(withKey: ConfigKey.typingIndicator)
+        self.accountService.switchAccountPropertyTo(state: enable, accountId: account.id, property: property)
+        self.typingIndicator = enable
+    }
+
     func enableProxyList(enable: Bool) {
         if self.proxyListEnabled == enable {
             return
diff --git a/Ring/Ring/Features/Settings/Me/AccountSettingsViews.swift b/Ring/Ring/Features/Settings/Me/AccountSettingsViews.swift
index ad7e246ba..0b4d8de34 100644
--- a/Ring/Ring/Features/Settings/Me/AccountSettingsViews.swift
+++ b/Ring/Ring/Features/Settings/Me/AccountSettingsViews.swift
@@ -42,6 +42,31 @@ struct CallSettingsView: View {
     }
 }
 
+struct ChatSettingsView: View {
+    @StateObject var model: AccountSettings
+
+    init(injectionBag: InjectionBag, account: AccountModel) {
+        _model = StateObject(wrappedValue: AccountSettings(account: account, injectionBag: injectionBag))
+    }
+
+    var body: some View {
+        List {
+            VStack(alignment: .leading) {
+                ToggleCell(
+                    toggleText: L10n.AccountPage.typingIndicator,
+                    getAction: { model.typingIndicator },
+                    setAction: { newValue in model.enableTypingIndicator(enable: newValue) }
+                )
+                Text(L10n.AccountPage.typingIndicatorExplanation)
+                    .font(.footnote)
+                    .foregroundColor(Color(UIColor.secondaryLabel))
+            }
+        }
+        .navigationBarTitleDisplayMode(.inline)
+        .navigationTitle(L10n.AccountPage.chats)
+    }
+}
+
 struct NotificationsSettingsView: View {
     @StateObject var model: AccountSettings
 
diff --git a/Ring/Ring/Features/Settings/Me/SettingsSummaryView.swift b/Ring/Ring/Features/Settings/Me/SettingsSummaryView.swift
index 64cf6320a..575e0f6c4 100644
--- a/Ring/Ring/Features/Settings/Me/SettingsSummaryView.swift
+++ b/Ring/Ring/Features/Settings/Me/SettingsSummaryView.swift
@@ -31,6 +31,9 @@ struct SettingsSummaryView: View {
                         SettingsRow(iconName: "shield", title: L10n.AccountPage.security)
                     }
                 } else {
+                    NavigationLink(destination: ChatSettingsView(injectionBag: model.injectionBag, account: model.account)) {
+                        SettingsRow(iconName: "message", title: L10n.AccountPage.chats)
+                    }
                     NavigationLink(destination: CallSettingsView(injectionBag: model.injectionBag, account: model.account)) {
                         SettingsRow(iconName: "phone", title: L10n.Global.call)
                     }
diff --git a/Ring/Ring/Models/ConfigKeyModel.swift b/Ring/Ring/Models/ConfigKeyModel.swift
index 3989539a8..d2918370c 100644
--- a/Ring/Ring/Models/ConfigKeyModel.swift
+++ b/Ring/Ring/Models/ConfigKeyModel.swift
@@ -111,6 +111,7 @@ enum ConfigKey: String {
     case accountPublish = "Account.accountPublish"
     case managerUri = "Account.managerUri"
     case managerUsername = "Account.managerUsername"
+    case typingIndicator = "Account.sendComposing"
 }
 
 /**
diff --git a/Ring/Ring/Resources/en.lproj/Localizable.strings b/Ring/Ring/Resources/en.lproj/Localizable.strings
index 6644c7df7..0d6c502d0 100644
--- a/Ring/Ring/Resources/en.lproj/Localizable.strings
+++ b/Ring/Ring/Resources/en.lproj/Localizable.strings
@@ -406,7 +406,8 @@
 "accountPage.dhtConfiguration" = "OpenDHT configuration";
 "accountPage.nameServer" = "Name server";
 "accountPage.chats" = "Chats";
-"accountPage.typingIndicator" = "Typing indicator";
+"accountPage.typingIndicator" = "Enable typing indicator";
+"accountPage.typingIndicatorExplanation" = "Send and receive typing indicators showing that a message is being typed.";
 
 // Backup Account
 "backupAccount.explanation" = "This Jami account exists only on this device. The account will be lost if this device is lost or if the application is uninstalled. It is recommended to make a backup of this account.";
-- 
GitLab