Глобальный рефакторинг SettingsPage (в процессе)
This commit is contained in:
@@ -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
client/components/Reader/SettingsPage/ViewTab/Color/Color.vue
Normal file
326
client/components/Reader/SettingsPage/ViewTab/Color/Color.vue
Normal file
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user