From 1f0ac68fcd3f382eedf69d1f5fdcffdc16c3885e Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 11 Mar 2021 16:55:14 +0200
Subject: [PATCH] implement ChoiceSetting for settings modal similar to
 BooleanSetting

---
 .../settings_modal/helpers/choice_setting.js  | 34 ++++++++++++++
 .../settings_modal/helpers/choice_setting.vue | 29 ++++++++++++
 .../settings_modal/tabs/filtering_tab.js      | 11 +++--
 .../settings_modal/tabs/filtering_tab.vue     | 17 ++-----
 .../settings_modal/tabs/general_tab.js        | 18 ++++++--
 .../settings_modal/tabs/general_tab.vue       | 46 +++++--------------
 6 files changed, 103 insertions(+), 52 deletions(-)
 create mode 100644 src/components/settings_modal/helpers/choice_setting.js
 create mode 100644 src/components/settings_modal/helpers/choice_setting.vue

diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js
new file mode 100644
index 00000000..042e8106
--- /dev/null
+++ b/src/components/settings_modal/helpers/choice_setting.js
@@ -0,0 +1,34 @@
+import { get, set } from 'lodash'
+import Select from 'src/components/select/select.vue'
+import ModifiedIndicator from './modified_indicator.vue'
+export default {
+  components: {
+    Select,
+    ModifiedIndicator
+  },
+  props: [
+    'path',
+    'disabled',
+    'options'
+  ],
+  computed: {
+    pathDefault () {
+      const [firstSegment, ...rest] = this.path.split('.')
+      return [firstSegment + 'DefaultValue', ...rest].join('.')
+    },
+    state () {
+      return get(this.$parent, this.path)
+    },
+    defaultState () {
+      return get(this.$parent, this.pathDefault)
+    },
+    isChanged () {
+      return get(this.$parent, this.path) !== get(this.$parent, this.pathDefault)
+    }
+  },
+  methods: {
+    update (e) {
+      set(this.$parent, this.path, e)
+    }
+  }
+}
diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue
new file mode 100644
index 00000000..1a8275b4
--- /dev/null
+++ b/src/components/settings_modal/helpers/choice_setting.vue
@@ -0,0 +1,29 @@
+<template>
+  <label
+    class="ChoiceSetting"
+  >
+    <slot />
+    <Select
+      :value="state"
+      :disabled="disabled"
+      @change="update"
+    >
+      <option
+        v-for="option in options"
+        :key="option.key"
+        :value="option.value"
+      >
+        {{ option.label }}
+        {{ option.value === defaultValue ? $t('settings.instance_default_simple') : '' }}
+      </option>
+    </Select>
+    <ModifiedIndicator :changed="isChanged" />
+  </label>
+</template>
+
+<script src="./choice_setting.js"></script>
+
+<style lang="scss">
+.ChoiceSetting {
+}
+</style>
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index 89199d85..4eaf4217 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -1,18 +1,23 @@
 import { filter, trim } from 'lodash'
 import BooleanSetting from '../helpers/boolean_setting.vue'
-import Select from '../../select/select.vue'
+import ChoiceSetting from '../helpers/choice_setting.vue'
 
 import SharedComputedObject from '../helpers/shared_computed_object.js'
 
 const FilteringTab = {
   data () {
     return {
-      muteWordsStringLocal: this.$store.getters.mergedConfig.muteWords.join('\n')
+      muteWordsStringLocal: this.$store.getters.mergedConfig.muteWords.join('\n'),
+      replyVisibilityOptions: ['all', 'following', 'self'].map(mode => ({
+        key: mode,
+        value: mode,
+        label: this.$t(`settings.reply_visibility_${mode}`)
+      }))
     }
   },
   components: {
     BooleanSetting,
-    Select
+    ChoiceSetting
   },
   computed: {
     ...SharedComputedObject(),
diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue
index 4023fbe2..fb5fc375 100644
--- a/src/components/settings_modal/tabs/filtering_tab.vue
+++ b/src/components/settings_modal/tabs/filtering_tab.vue
@@ -36,20 +36,13 @@
           </li>
         </ul>
       </div>
-      <div>
-        {{ $t('settings.replies_in_timeline') }}
-        <Select
+      <ChoiceSetting
           id="replyVisibility"
-          v-model="replyVisibility"
+          path="replyVisibility"
+          :options="replyVisibilityOptions"
         >
-          <option
-            value="all"
-            selected
-          >{{ $t('settings.reply_visibility_all') }}</option>
-          <option value="following">{{ $t('settings.reply_visibility_following') }}</option>
-          <option value="self">{{ $t('settings.reply_visibility_self') }}</option>
-        </Select>
-      </div>
+        {{ $t('settings.replies_in_timeline') }}
+      </ChoiceSetting>
       <div>
         <BooleanSetting path="hidePostStats">
           {{ $t('settings.hide_post_stats') }}
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index 03648d0b..07fccf57 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -1,5 +1,5 @@
 import BooleanSetting from '../helpers/boolean_setting.vue'
-import Select from '../../select/select.vue'
+import ChoiceSetting from '../helpers/choice_setting.vue'
 import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
 
 import SharedComputedObject from '../helpers/shared_computed_object.js'
@@ -15,6 +15,11 @@ library.add(
 const GeneralTab = {
   data () {
     return {
+      subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({
+        key: mode,
+        value: mode,
+        label: this.$t(`settings.subject_line_${mode === 'masto' ? 'mastodon' : mode}`)
+      })),
       loopSilentAvailable:
       // Firefox
       Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
@@ -26,13 +31,20 @@ const GeneralTab = {
   },
   components: {
     BooleanSetting,
-    InterfaceLanguageSwitcher,
-    Select
+    ChoiceSetting,
+    InterfaceLanguageSwitcher
   },
   computed: {
     postFormats () {
       return this.$store.state.instance.postFormats || []
     },
+    postContentOptions () {
+      return this.postFormats.map(format => ({
+        key: format,
+        value: format,
+        label: this.$t(`post_status.content_type["${format}"]`)
+      }))
+    },
     instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel },
     instanceWallpaperUsed () {
       return this.$store.state.instance.background &&
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index a0413cfa..7fb82c06 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -85,44 +85,22 @@
           </BooleanSetting>
         </li>
         <li>
-          <div>
+          <ChoiceSetting
+            id="subjectLineBehavior"
+            path="subjectLineBehavior"
+            :options="subjectLineOptions"
+          >
             {{ $t('settings.subject_line_behavior') }}
-            <Select
-              id="subjectLineBehavior"
-              v-model="subjectLineBehavior"
-            >
-              <option value="email">
-                {{ $t('settings.subject_line_email') }}
-                {{ subjectLineBehaviorDefaultValue == 'email' ? $t('settings.instance_default_simple') : '' }}
-              </option>
-              <option value="masto">
-                {{ $t('settings.subject_line_mastodon') }}
-                {{ subjectLineBehaviorDefaultValue == 'mastodon' ? $t('settings.instance_default_simple') : '' }}
-              </option>
-              <option value="noop">
-                {{ $t('settings.subject_line_noop') }}
-                {{ subjectLineBehaviorDefaultValue == 'noop' ? $t('settings.instance_default_simple') : '' }}
-              </option>
-            </Select>
-          </div>
+          </ChoiceSetting>
         </li>
         <li v-if="postFormats.length > 0">
-          <div>
+          <ChoiceSetting
+            id="postContentType"
+            path="postContentType"
+            :options="postContentOptions"
+          >
             {{ $t('settings.post_status_content_type') }}
-            <Select
-              id="postContentType"
-              v-model="postContentType"
-            >
-              <option
-                v-for="postFormat in postFormats"
-                :key="postFormat"
-                :value="postFormat"
-              >
-                {{ $t(`post_status.content_type["${postFormat}"]`) }}
-                {{ postContentTypeDefaultValue === postFormat ? $t('settings.instance_default_simple') : '' }}
-              </option>
-            </Select>
-          </div>
+          </ChoiceSetting>
         </li>
         <li>
           <BooleanSetting path="minimalScopesMode">