From 0d3f872c5c6ec8e5d8b0b1d716ba6afee98ea0ae Mon Sep 17 00:00:00 2001
From: Alex Jbanca <47811206+alexjba@users.noreply.github.com>
Date: Mon, 7 Nov 2022 15:43:38 +0200
Subject: [PATCH] Display message preview settings - fix model -> view
 relationship

There are two main changes in the model -> view relationship:
1. The model coming from the store becomes the only source of truth and the UI will only change when the model changes. This means that when another UI component from settings menu wants to change some setting it needs to update the model, not UI components directly.
2. When the store will provide a new model we will update only rows that are different in the current model.
---
 .../Profile/views/MessagingView.qml           | 74 ++++++++++++-------
 1 file changed, 48 insertions(+), 26 deletions(-)

diff --git a/ui/app/AppLayouts/Profile/views/MessagingView.qml b/ui/app/AppLayouts/Profile/views/MessagingView.qml
index b0a0150f9a..572573c5b4 100644
--- a/ui/app/AppLayouts/Profile/views/MessagingView.qml
+++ b/ui/app/AppLayouts/Profile/views/MessagingView.qml
@@ -136,15 +136,18 @@ SettingsContentBase {
             components: [
                 StatusSwitch {
                     id: showMessageLinksSwitch
+                    function switchOffPreviewableSites() {
+                        //update all models
+                        localAccountSensitiveSettings.displayChatImages = false
+                        for (let i = 0; i < previewableSites.count; i++) {
+                            let item = previewableSites.get(i)
+                            RootStore.updateWhitelistedUnfurlingSites(item.address, false)
+                        }
+                    }
                     checked: false
                     onCheckedChanged: {
                         if (checked === false) {
-                            // Switch all the whitelists to false
-                            imageSwitch.checked = false
-                            for (let i = 0; i < sitesListView.count; i++) {
-                                let item = sitesListView.itemAt(i)
-                                item.whitelistSwitch.checked = false
-                            }
+                            switchOffPreviewableSites()
                         }
                     }
                 }
@@ -154,26 +157,28 @@ SettingsContentBase {
             }
         }
 
-        function populatePreviewableSites() {
+        function buildPreviewablesSitesJSON() {
             let whitelistAsString = root.messagingStore.getLinkPreviewWhitelist()
             if(whitelistAsString == "")
                 return
-            let whitelist = JSON.parse(whitelistAsString)
+
             if (!localAccountSensitiveSettings.whitelistedUnfurlingSites) {
                 localAccountSensitiveSettings.whitelistedUnfurlingSites = {}
             }
-            previewableSites.clear()
-            var oneEntryIsActive = false
+
+            let anyWhitelisted = false
+            let whitelist = JSON.parse(whitelistAsString)
             whitelist.forEach(entry => {
                                   entry.isWhitelisted = !!localAccountSensitiveSettings.whitelistedUnfurlingSites[entry.address]
-                                  if (entry.isWhitelisted) {
-                                      oneEntryIsActive = true
-                                  }
-                                  previewableSites.append(entry)
-                              })
-            if (oneEntryIsActive) {
-                showMessageLinksSwitch.checked = true
-            }
+                                  if(entry.isWhitelisted) anyWhitelisted = true
+                })
+            return [anyWhitelisted, whitelist]
+        }
+
+        function populatePreviewableSites() {
+            const [anyWhitelisted, whitelist] = buildPreviewablesSitesJSON()
+            showMessageLinksSwitch.checked = anyWhitelisted
+            previewableSites.populateModel(whitelist)
         }
 
         Component.onCompleted: {
@@ -196,6 +201,24 @@ SettingsContentBase {
 
             ListModel {
                 id: previewableSites
+                function populateModel(jsonModel) {
+                    // add/update rows
+                    Object.entries(jsonModel)
+                        .forEach(([index, newRow]) => {
+                            var existingRow = previewableSites.get(index)
+                            let isRowIdentical = existingRow != undefined && Object.entries(newRow)
+                                        .every(([key, value]) => value == existingRow[key])
+                            if(!isRowIdentical) {
+                                previewableSites.set(index, newRow)
+                            }
+                    })
+
+                    // remove rows that are not in the new model
+                    if(previewableSites.count > jsonModel.length) {
+                        let rowsToDelete = previewableSites.count - jsonModel.length
+                        previewableSites.remove(jsonModel.length - 1, rowsToDelete)
+                    }
+                }
             }
 
             Connections {
@@ -229,15 +252,13 @@ SettingsContentBase {
                     StatusSwitch {
                         id: imageSwitch
                         checked: localAccountSensitiveSettings.displayChatImages
-                        onCheckedChanged: {
-                            if (localAccountSensitiveSettings.displayChatImages !== checked) {
-                                localAccountSensitiveSettings.displayChatImages = checked
-                            }
+                        onToggled: {
+                                localAccountSensitiveSettings.displayChatImages = !localAccountSensitiveSettings.displayChatImages
                         }
                     }
                 ]
                 onClicked: {
-                    imageSwitch.checked = !imageSwitch.checked
+                    localAccountSensitiveSettings.displayChatImages = !localAccountSensitiveSettings.displayChatImages
                 }
             }
 
@@ -248,7 +269,6 @@ SettingsContentBase {
                 delegate: Component {
                     StatusListItem {
                         objectName: "MessagingView_sitesListView_StatusListItem_" + model.title.replace(/ /g, "_").toLowerCase()
-                        property alias whitelistSwitch: siteSwitch
                         width: parent.width
                         implicitHeight: 64
                         title: model.title
@@ -283,11 +303,13 @@ SettingsContentBase {
                             StatusSwitch {
                                 id: siteSwitch
                                 checked: !!model.isWhitelisted
-                                onCheckedChanged: RootStore.updateWhitelistedUnfurlingSites(model.address, checked)
+                                onToggled: {
+                                    RootStore.updateWhitelistedUnfurlingSites(model.address, checked)
+                                }
                             }
                         ]
                         onClicked: {
-                            siteSwitch.checked = !siteSwitch.checked
+                            RootStore.updateWhitelistedUnfurlingSites(model.address, !model.isWhitelisted)
                         }
                     }
                 }