Просмотр исходного кода

Глобальный рефакторинг SettingsPage (в процессе)

Book Pauk 2 лет назад
Родитель
Сommit
419b203fcf

+ 6 - 150
client/components/Reader/SettingsPage/SettingsPage.vue

@@ -5,8 +5,6 @@
         </template>
 
         <div class="col row">
-            <a ref="download" style="display: none;" target="_blank"></a>
-
             <div class="full-height">
                 <q-tabs
                     ref="tabs"
@@ -62,16 +60,13 @@
 <script>
 //-----------------------------------------------------------------------------
 import vueComponent from '../../vueComponent.js';
+import { reactive } from 'vue';
 
 import _ from 'lodash';
 
 //stuff
-import * as utils from '../../../share/utils';
-import * as cryptoUtils from '../../../share/cryptoUtils';
 import Window from '../../share/Window.vue';
-import wallpaperStorage from '../share/wallpaperStorage';
 
-import readerApi from '../../../api/reader';
 import rstore from '../../../store/modules/reader';
 
 //pages
@@ -107,7 +102,7 @@ const componentOptions = {
         },
         form: {
             handler() {
-                if (this.inited && !this.setsChanged) {
+                if (this.inited && !this.isSetsChanged) {
                     this.debouncedCommitSettings();
                 }
             },
@@ -134,31 +129,9 @@ const componentOptions = {
             const font = (newValue ? newValue : this.fontName);
             this.vertShift = this.fontShifts[font] || 0;
         },
-        wallpaper: function(newValue) {
-            if (newValue != '' && this.pageChangeAnimation == 'flip')
-                this.pageChangeAnimation = '';
-        },
-        /*this.$watch('form.dualPageMode', (newValue) => {
-            console.log(newValue);
-        })*/        
-        dualPageMode(newValue) {
-            if (newValue && this.pageChangeAnimation == 'flip' || this.pageChangeAnimation == 'rightShift')
-                this.pageChangeAnimation = '';
-        },
         textColor: function(newValue) {
             this.textColorFiltered = newValue;
         },
-        textColorFiltered: function(newValue) {
-            if (hex.test(newValue))
-                this.textColor = newValue;
-        },
-        backgroundColor: function(newValue) {
-            this.bgColorFiltered = newValue;
-        },
-        bgColorFiltered: function(newValue) {
-            if (hex.test(newValue))
-                this.backgroundColor = newValue;
-        },
         statusBarColor(newValue) {
             this.statusBarColorFiltered = newValue;
         },
@@ -175,13 +148,11 @@ class SettingsPage {
 
     selectedTab = 'profiles';
 
-    setsChanged = false;
+    isSetsChanged = false;
 
     fontBold = false;
     fontItalic = false;
     vertShift = 0;
-    textColorFiltered = '';
-    bgColorFiltered = '';
     statusBarColorFiltered = '';
     webFonts = [];
     fonts = [];    
@@ -205,9 +176,9 @@ class SettingsPage {
     }
 
     async settingsChanged() {
-        this.setsChanged = true;
+        this.isSetsChanged = true;
         try {
-            this.form = _.cloneDeep(this.settings);
+            this.form = reactive(_.cloneDeep(this.settings));
             const form = this.form;
 
             this.fontBold = (form.fontWeight == 'bold');
@@ -217,13 +188,11 @@ class SettingsPage {
             this.webFonts = rstore.webFonts;
             const font = (form.webFontName ? form.webFontName : form.fontName);
             this.vertShift = form.fontShifts[font] || 0;
-            this.textColorFiltered = form.textColor;
-            this.bgColorFiltered = form.backgroundColor;
             this.dualDivColorFiltered = form.dualDivColor;
             this.statusBarColorFiltered = form.statusBarColor;
         } finally {
             await this.$nextTick();
-            this.setsChanged = false;
+            this.isSetsChanged = false;
         }
     }
 
@@ -231,24 +200,6 @@ class SettingsPage {
         return this.$store.state.reader.settings;
     }
 
-    get wallpaperOptions() {
-        let result = [{label: 'Нет', value: ''}];
-
-        const userWallpapers = _.cloneDeep(this.userWallpapers);
-        userWallpapers.sort((a, b) => a.label.localeCompare(b.label));
-
-        for (const wp of userWallpapers) {
-            if (wallpaperStorage.keyExists(wp.cssClass))
-                result.push({label: wp.label, value: wp.cssClass});
-        }
-
-        for (let i = 1; i <= 17; i++) {
-            result.push({label: i, value: `paper${i}`});
-        }
-
-        return result;
-    }
-
     get fontsOptions() {
         let result = [];
         this.fonts.forEach(font => {
@@ -296,101 +247,6 @@ class SettingsPage {
         }
     }
 
-    loadWallpaperFileClick() {
-        this.$refs.file.click();
-    }
-
-    loadWallpaperFile() {
-        const file = this.$refs.file.files[0];        
-        if (file.size > 10*1024*1024) {
-            this.$root.stdDialog.alert('Файл обоев не должен превышать в размере 10Mb', 'Ошибка');
-            return;
-        }
-
-        if (file.type != 'image/png' && file.type != 'image/jpeg') {
-            this.$root.stdDialog.alert('Файл обоев должен иметь тип PNG или JPEG', 'Ошибка');
-            return;
-        }
-
-        if (this.userWallpapers.length >= 100) {
-            this.$root.stdDialog.alert('Превышено максимальное количество пользовательских обоев.', 'Ошибка');
-            return;
-        }
-
-        this.$refs.file.value = '';
-        if (file) {
-            const reader = new FileReader();
-
-            reader.onload = (e) => {
-                (async() => {
-                    const data = e.target.result;
-                    const key = utils.toHex(cryptoUtils.sha256(data));
-                    const label = `#${key.substring(0, 4)}`;
-                    const cssClass = `user-paper${key}`;
-
-                    const newUserWallpapers = _.cloneDeep(this.userWallpapers);
-                    const index = _.findIndex(newUserWallpapers, (item) => (item.cssClass == cssClass));
-
-                    if (index < 0)
-                        newUserWallpapers.push({label, cssClass});
-                    if (!wallpaperStorage.keyExists(cssClass)) {
-                        await wallpaperStorage.setData(cssClass, data);
-                        //отправим data на сервер в файл `/upload/${key}`
-                        try {
-                            //const res = 
-                            await readerApi.uploadFileBuf(data);
-                            //console.log(res);
-                        } catch (e) {
-                            console.error(e);
-                        }
-                    }
-
-                    this.userWallpapers = newUserWallpapers;
-                    this.wallpaper = cssClass;
-                })();
-            }
-
-            reader.readAsDataURL(file);
-        }
-    }
-
-    async delWallpaper() {
-        if (this.wallpaper.indexOf('user-paper') == 0) {
-            const newUserWallpapers = [];
-            for (const wp of this.userWallpapers) {
-                if (wp.cssClass != this.wallpaper) {
-                    newUserWallpapers.push(wp);
-                }
-            }
-
-            await wallpaperStorage.removeData(this.wallpaper);
-
-            this.userWallpapers = newUserWallpapers;
-            this.wallpaper = '';
-        }
-    }
-
-    async downloadWallpaper() {
-        if (this.wallpaper.indexOf('user-paper') != 0)
-            return;
-
-        try {
-            const d = this.$refs.download;
-
-            const dataUrl = await wallpaperStorage.getData(this.wallpaper);
-
-            if (!dataUrl)
-                throw new Error('Файл обоев не найден');
-
-            d.href = dataUrl;
-            d.download = `wallpaper-#${this.wallpaper.replace('user-paper', '').substring(0, 4)}`;
-
-            d.click();
-        } catch (e) {
-            this.$root.stdDialog.alert(e.message, 'Ошибка', {color: 'negative'});
-        }
-    }
-
     keyHook(event) {
         if (!this.$root.stdDialog.active && event.type == 'keydown' && event.key == 'Escape') {
             this.close();

+ 326 - 0
client/components/Reader/SettingsPage/ViewTab/Color/Color.vue

@@ -0,0 +1,326 @@
+<template>
+    <div class="fit sets-tab-panel">
+        <!---------------------------------------------->
+        <div class="hidden sets-part-header">
+            Цвет
+        </div>
+
+        <div class="sets-item row">
+            <div class="sets-label label">
+                Текст
+            </div>
+            <div class="col row">
+                <q-input
+                    v-model="textColorFiltered"
+                    class="col-left no-mp"
+                    outlined dense
+                    
+                    :rules="['hexColor']"
+                    style="max-width: 150px"
+                >
+                    <template #prepend>
+                        <q-icon name="la la-angle-down la-xs" class="cursor-pointer text-white" :style="helper.colorPanStyle(form.textColor)">
+                            <q-popup-proxy anchor="bottom middle" self="top middle">
+                                <div>
+                                    <q-color
+                                        v-model="form.textColor"
+                                        no-header default-view="palette" :palette="defPalette.predefineTextColors"
+                                    />
+                                </div>
+                            </q-popup-proxy>
+                        </q-icon>
+                    </template>
+                </q-input>
+            </div>
+        </div>
+
+        <div class="q-mt-md" />
+        <div class="sets-item row">
+            <div class="sets-label label">
+                Фон
+            </div>
+            <div class="col row">
+                <q-input 
+                    v-model="bgColorFiltered"
+                    class="col-left no-mp"
+                    outlined dense
+                    
+                    :rules="['hexColor']"
+                    style="max-width: 150px"
+                >
+                    <template #prepend>
+                        <q-icon name="la la-angle-down la-xs" class="cursor-pointer text-white" :style="helper.colorPanStyle(form.backgroundColor)">
+                            <q-popup-proxy anchor="bottom middle" self="top middle">
+                                <div>
+                                    <q-color v-model="form.backgroundColor" no-header default-view="palette" :palette="defPalette.predefineBackgroundColors" />
+                                </div>
+                            </q-popup-proxy>
+                        </q-icon>
+                    </template>
+                </q-input>
+            </div>
+        </div>
+
+        <div class="q-mt-md" />
+        <div class="sets-item row">
+            <div class="sets-label label">
+                Обои
+            </div>
+            <div class="col row items-center">
+                <q-select 
+                    v-model="form.wallpaper"
+                    class="col-left no-mp"
+                    :options="wallpaperOptions"
+                    dropdown-icon="la la-angle-down la-sm"
+                    outlined dense emit-value map-options
+                >
+                    <template #selected-item="scope">
+                        <div>
+                            {{ scope.opt.label }}
+                        </div>
+                        <div v-show="scope.opt.value" class="q-ml-sm" :class="scope.opt.value" style="width: 40px; height: 28px;"></div>
+                    </template>
+
+                    <template #option="scope">
+                        <q-item
+                            v-bind="scope.itemProps"
+                        >
+                            <q-item-section style="min-width: 50px;">
+                                <q-item-label>
+                                    {{ scope.opt.label }}
+                                </q-item-label>
+                            </q-item-section>
+                            <q-item-section v-show="scope.opt.value" :class="scope.opt.value" style="min-width: 70px; min-height: 50px;" />
+                        </q-item>
+                    </template>
+                </q-select>
+
+                <div class="q-px-xs" />
+                <q-btn class="q-ml-sm" round dense color="blue" icon="la la-plus" @click.stop="loadWallpaperFileClick">
+                    <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
+                        Добавить файл обоев
+                    </q-tooltip>
+                </q-btn>
+                <q-btn v-show="form.wallpaper.indexOf('user-paper') === 0" class="q-ml-sm" round dense color="blue" icon="la la-minus" @click.stop="delWallpaper">
+                    <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
+                        Удалить выбранные обои
+                    </q-tooltip>
+                </q-btn>
+                <q-btn v-show="form.wallpaper.indexOf('user-paper') === 0" class="q-ml-sm" round dense color="blue" icon="la la-file-download" @click.stop="downloadWallpaper">
+                    <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
+                        Скачать выбранные обои
+                    </q-tooltip>
+                </q-btn>
+            </div>
+        </div>
+
+        <div class="q-mt-sm" />
+        <div class="sets-item row">
+            <div class="sets-label label"></div>
+            <div class="col row items-center">
+                <q-checkbox v-model="form.wallpaperIgnoreStatusBar" size="xs" label="Не включать строку статуса в обои" />
+            </div>
+        </div>
+
+        <input ref="file" type="file" style="display: none;" @change="loadWallpaperFile" />
+        <a ref="download" style="display: none;" target="_blank"></a>
+    </div>
+</template>
+
+<script>
+//-----------------------------------------------------------------------------
+import vueComponent from '../../../../vueComponent.js';
+
+import _ from 'lodash';
+
+import * as helper from '../helper';
+import defPalette from '../defPalette';
+
+import * as utils from '../../../../../share/utils';
+import * as cryptoUtils from '../../../../../share/cryptoUtils';
+import wallpaperStorage from '../../../share/wallpaperStorage';
+import readerApi from '../../../../../api/reader';
+
+const componentOptions = {
+    components: {
+    },
+    watch: {
+        form() {
+            this.formChanged();//no await
+        },
+        textColorFiltered(newValue) {
+            if (!this.isFormChanged && this.helper.isHexColor(newValue))
+                this.form.textColor = newValue;
+        },
+        bgColorFiltered(newValue) {
+            if (!this.isFormChanged && this.helper.isHexColor(newValue))
+                this.form.backgroundColor = newValue;
+        },
+    },
+};
+class Color {
+    _options = componentOptions;
+    _props = {
+        form: Object,
+    };
+
+    helper = helper;
+    defPalette = defPalette;
+
+    isFormChanged = false;
+    textColorFiltered = '';
+    bgColorFiltered = '';
+
+    created() {
+        this.formChanged();//no await
+    }
+
+    mounted() {
+    }
+
+    async formChanged() {
+        this.isFormChanged = true;
+        try {
+            this.textColorFiltered = this.form.textColor;
+            this.bgColorFiltered = this.form.backgroundColor;
+
+            if (this.form.wallpaper != '' && this.form.pageChangeAnimation == 'flip')
+                this.form.pageChangeAnimation = '';
+        } finally {
+            await this.$nextTick();
+            this.isFormChanged = false;
+        }
+    }
+
+    get wallpaperOptions() {
+        let result = [{label: 'Нет', value: ''}];
+
+        const userWallpapers = _.cloneDeep(this.form.userWallpapers);
+        userWallpapers.sort((a, b) => a.label.localeCompare(b.label));
+
+        for (const wp of userWallpapers) {
+            if (wallpaperStorage.keyExists(wp.cssClass))
+                result.push({label: wp.label, value: wp.cssClass});
+        }
+
+        for (let i = 1; i <= 17; i++) {
+            result.push({label: i, value: `paper${i}`});
+        }
+
+        return result;
+    }
+
+    loadWallpaperFileClick() {
+        this.$refs.file.click();
+    }
+
+    loadWallpaperFile() {
+        const file = this.$refs.file.files[0];        
+        if (file.size > 10*1024*1024) {
+            this.$root.stdDialog.alert('Файл обоев не должен превышать в размере 10Mb', 'Ошибка');
+            return;
+        }
+
+        if (file.type != 'image/png' && file.type != 'image/jpeg') {
+            this.$root.stdDialog.alert('Файл обоев должен иметь тип PNG или JPEG', 'Ошибка');
+            return;
+        }
+
+        if (this.form.userWallpapers.length >= 100) {
+            this.$root.stdDialog.alert('Превышено максимальное количество пользовательских обоев.', 'Ошибка');
+            return;
+        }
+
+        this.$refs.file.value = '';
+        if (file) {
+            const reader = new FileReader();
+
+            reader.onload = (e) => {
+                (async() => {
+                    const data = e.target.result;
+                    const key = utils.toHex(cryptoUtils.sha256(data));
+                    const label = `#${key.substring(0, 4)}`;
+                    const cssClass = `user-paper${key}`;
+
+                    const newUserWallpapers = _.cloneDeep(this.form.userWallpapers);
+                    const index = _.findIndex(newUserWallpapers, (item) => (item.cssClass == cssClass));
+
+                    if (index < 0)
+                        newUserWallpapers.push({label, cssClass});
+                    if (!wallpaperStorage.keyExists(cssClass)) {
+                        await wallpaperStorage.setData(cssClass, data);
+                        //отправим data на сервер в файл `/upload/${key}`
+                        try {
+                            //const res = 
+                            await readerApi.uploadFileBuf(data);
+                            //console.log(res);
+                        } catch (e) {
+                            console.error(e);
+                        }
+                    }
+
+                    this.form.userWallpapers = newUserWallpapers;
+                    this.form.wallpaper = cssClass;
+                })();
+            }
+
+            reader.readAsDataURL(file);
+        }
+    }
+
+    async delWallpaper() {
+        if (this.form.wallpaper.indexOf('user-paper') == 0) {
+            const newUserWallpapers = [];
+            for (const wp of this.form.userWallpapers) {
+                if (wp.cssClass != this.form.wallpaper) {
+                    newUserWallpapers.push(wp);
+                }
+            }
+
+            await wallpaperStorage.removeData(this.form.wallpaper);
+
+            this.form.userWallpapers = newUserWallpapers;
+            this.form.wallpaper = '';
+        }
+    }
+
+    async downloadWallpaper() {
+        if (this.form.wallpaper.indexOf('user-paper') != 0)
+            return;
+
+        try {
+            const d = this.$refs.download;
+
+            const dataUrl = await wallpaperStorage.getData(this.form.wallpaper);
+
+            if (!dataUrl)
+                throw new Error('Файл обоев не найден');
+
+            d.href = dataUrl;
+            d.download = `wallpaper-#${this.form.wallpaper.replace('user-paper', '').substring(0, 4)}`;
+
+            d.click();
+        } catch (e) {
+            this.$root.stdDialog.alert(e.message, 'Ошибка', {color: 'negative'});
+        }
+    }
+}
+
+export default vueComponent(Color);
+//-----------------------------------------------------------------------------
+</script>
+
+<style scoped>
+.label {
+    width: 110px;
+}
+
+.col-left {
+    width: 150px;
+}
+
+.no-mp {
+    margin: 0;
+    padding: 0;
+}
+</style>

+ 17 - 5
client/components/Reader/SettingsPage/ViewTab/Mode/Mode.vue

@@ -163,10 +163,10 @@ const componentOptions = {
     },
     watch: {
         form() {
-            this.formChanged();
+            this.formChanged();//no await
         },
         dualDivColorFiltered(newValue) {
-            if (this.helper.isHexColor(newValue))
+            if (!this.isFormChanged && this.helper.isHexColor(newValue))
                 this.form.dualDivColor = newValue;
         },
     }
@@ -180,17 +180,29 @@ class Mode {
     helper = helper;
     defPalette = defPalette;
 
+    isFormChanged = false;
     dualDivColorFiltered = '';
 
     created() {
-        this.formChanged();
+        this.formChanged();//no await
     }
 
     mounted() {
     }
 
-    formChanged() {
-        this.dualDivColorFiltered = this.form.dualDivColor;
+    async formChanged() {
+        this.isFormChanged = true;
+        try {
+            this.dualDivColorFiltered = this.form.dualDivColor;
+
+            if (this.form.dualPageMode 
+                && (this.form.pageChangeAnimation == 'flip' || this.form.pageChangeAnimation == 'rightShift')
+                )
+                this.form.pageChangeAnimation = '';
+        } finally {
+            await this.$nextTick();
+            this.isFormChanged = false;
+        }
     }
 }
 

+ 3 - 0
client/components/Reader/SettingsPage/ViewTab/ViewTab.vue

@@ -20,6 +20,7 @@
 
         <div class="col sets-tab-panel">
             <Mode v-if="selectedTab == 'mode'" :form="form" />
+            <Color v-if="selectedTab == 'color'" :form="form" />
 
             <!--div v-if="selectedViewTab == 'color'">
                 @@include('./ViewTab/Color.inc');
@@ -45,10 +46,12 @@
 import vueComponent from '../../../vueComponent.js';
 
 import Mode from './Mode/Mode.vue';
+import Color from './Color/Color.vue';
 
 const componentOptions = {
     components: {
         Mode,
+        Color,
     },
 };
 class ViewTab {