Перенес управление и хранение recentBooks из vuex в bookManager

This commit is contained in:
Book Pauk
2019-02-03 15:21:11 +07:00
parent 614a2b9409
commit 1ea6fc6926
4 changed files with 129 additions and 84 deletions

View File

@@ -99,26 +99,34 @@ import _ from 'lodash';
import {formatDate} from '../../../share/utils'; import {formatDate} from '../../../share/utils';
import Window from '../../share/Window.vue'; import Window from '../../share/Window.vue';
import bookManager from '../share/bookManager';
export default @Component({ export default @Component({
components: { components: {
Window, Window,
}, },
watch: {
search: function() {
this.updateTableData();
}
},
}) })
class HistoryPage extends Vue { class HistoryPage extends Vue {
search = null; search = null;
tableData = null;
created() { created() {
this.commit = this.$store.commit;
this.reader = this.$store.state.reader;
} }
get tableData() { mounted() {
const state = this.reader; this.updateTableData();
}
updateTableData() {
let result = []; let result = [];
for (let bookKey in state.openedBook) { for (let bookKey in bookManager.recent) {
const book = state.openedBook[bookKey]; const book = bookManager.recent[bookKey];
let d = new Date(); let d = new Date();
d.setTime(book.touchTime); d.setTime(book.touchTime);
const t = formatDate(d).split(' '); const t = formatDate(d).split(' ');
@@ -151,7 +159,7 @@ class HistoryPage extends Vue {
} }
const search = this.search; const search = this.search;
return result.filter(item => { this.tableData = result.filter(item => {
return !search || return !search ||
item.touchTime.includes(search) || item.touchTime.includes(search) ||
item.touchDate.includes(search) || item.touchDate.includes(search) ||
@@ -184,8 +192,9 @@ class HistoryPage extends Vue {
window.open(path, '_blank'); window.open(path, '_blank');
} }
handleDel(key) { async handleDel(key) {
this.commit('reader/delOpenedBook', {key}); await bookManager.delRecentBook({key});
this.updateTableData();
} }
loadBook(url) { loadBook(url) {

View File

@@ -107,7 +107,7 @@ export default @Component({
if (textPage.bookPos != newValue) { if (textPage.bookPos != newValue) {
textPage.bookPos = newValue; textPage.bookPos = newValue;
} }
this.debouncedCommitOpenedBook(newValue); this.debouncedSetRecentBook(newValue);
} }
}, },
routeParamPos: function(newValue) { routeParamPos: function(newValue) {
@@ -116,7 +116,7 @@ export default @Component({
} }
}, },
routeParamUrl: function(newValue) { routeParamUrl: function(newValue) {
if (newValue !== '' && newValue !== this.lastOpenedBook.url) { if (newValue !== '' && newValue !== this.mostRecentBook().url) {
this.loadBook({url: newValue, bookPos: this.routeParamPos}); this.loadBook({url: newValue, bookPos: this.routeParamPos});
} }
}, },
@@ -155,9 +155,10 @@ class Reader extends Vue {
this.updateRoute(); this.updateRoute();
}, 1000); }, 1000);
this.debouncedCommitOpenedBook = _.debounce((newValue) => { this.debouncedSetRecentBook = _.debounce(async(newValue) => {
if (this.lastOpenedBook && this.lastOpenedBook.bookPos != newValue) { const recent = this.mostRecentBook();
this.commit('reader/setOpenedBook', Object.assign({}, this.lastOpenedBook, {bookPos: newValue, bookPosSeen: this.bookPosSeen})); if (recent && recent.bookPos != newValue) {
await bookManager.setRecentBook(Object.assign({}, recent, {bookPos: newValue, bookPosSeen: this.bookPosSeen}));
} }
}, 500); }, 500);
@@ -169,14 +170,11 @@ class Reader extends Vue {
} }
mounted() { mounted() {
/*while (this.lastOpenedBook) {
this.commit('reader/delOpenedBook', this.lastOpenedBook);
}*/
if (this.$root.rootRoute == '/reader') { if (this.$root.rootRoute == '/reader') {
if (this.routeParamUrl) { if (this.routeParamUrl) {
this.loadBook({url: this.routeParamUrl, bookPos: this.routeParamPos}); this.loadBook({url: this.routeParamUrl, bookPos: this.routeParamPos});
} else if (this.lastOpenedBook) { } else if (this.mostRecentBook()) {
this.loadBook({url: this.lastOpenedBook.url}); this.loadBook({url: this.this.mostRecentBook().url});
} else { } else {
this.loaderActive = true; this.loaderActive = true;
} }
@@ -197,10 +195,11 @@ class Reader extends Vue {
updateRoute(isNewRoute) { updateRoute(isNewRoute) {
const pos = (this.bookPos != undefined && this.allowUrlParamBookPos ? `__p=${this.bookPos}&` : ''); const pos = (this.bookPos != undefined && this.allowUrlParamBookPos ? `__p=${this.bookPos}&` : '');
const url = (this.mostRecentBook() ? `url=${this.mostRecentBook().url}` : '');
if (isNewRoute) if (isNewRoute)
this.$router.push(`/reader?${pos}url=${this.lastOpenedBook.url}`); this.$router.push(`/reader?${pos}${url}`);
else else
this.$router.replace(`/reader?${pos}url=${this.lastOpenedBook.url}`); this.$router.replace(`/reader?${pos}${url}`);
} }
@@ -226,8 +225,8 @@ class Reader extends Vue {
return this.reader.toolBarActive; return this.reader.toolBarActive;
} }
get lastOpenedBook() { mostRecentBook() {
const result = this.$store.getters['reader/lastOpenedBook']; const result = bookManager.mostRecentBook();
if (!result) if (!result)
this.closeAllTextPages(); this.closeAllTextPages();
return result; return result;
@@ -281,13 +280,13 @@ class Reader extends Vue {
setPositionToggle() { setPositionToggle() {
this.setPositionActive = !this.setPositionActive; this.setPositionActive = !this.setPositionActive;
if (this.setPositionActive && this.activePage == 'TextPage' && this.lastOpenedBook) { if (this.setPositionActive && this.activePage == 'TextPage' && this.mostRecentBook()) {
this.closeAllTextPages(); this.closeAllTextPages();
this.setPositionActive = true; this.setPositionActive = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.setPositionPage.sliderMax = this.lastOpenedBook.textLength - 1; this.$refs.setPositionPage.sliderMax = this.mostRecentBook().textLength - 1;
this.$refs.setPositionPage.sliderValue = this.lastOpenedBook.bookPos; this.$refs.setPositionPage.sliderValue = this.mostRecentBook().bookPos;
}); });
} else { } else {
this.setPositionActive = false; this.setPositionActive = false;
@@ -329,7 +328,7 @@ class Reader extends Vue {
searchToggle() { searchToggle() {
this.searchActive = !this.searchActive; this.searchActive = !this.searchActive;
const page = this.$refs.page; const page = this.$refs.page;
if (this.searchActive && this.activePage == 'TextPage' && page.parsed && this.lastOpenedBook) { if (this.searchActive && this.activePage == 'TextPage' && page.parsed && this.mostRecentBook()) {
this.closeAllTextPages(); this.closeAllTextPages();
this.searchActive = true; this.searchActive = true;
@@ -383,8 +382,8 @@ class Reader extends Vue {
this.historyToggle(); this.historyToggle();
break; break;
case 'refresh': case 'refresh':
if (this.lastOpenedBook) { if (this.mostRecentBook()) {
this.loadBook({url: this.lastOpenedBook.url, force: true}); this.loadBook({url: this.mostRecentBook().url, force: true});
} }
break; break;
case 'settings': case 'settings':
@@ -413,7 +412,7 @@ class Reader extends Vue {
break; break;
} }
if (this.activePage == 'LoaderPage' || !this.lastOpenedBook) { if (this.activePage == 'LoaderPage' || !this.mostRecentBook()) {
switch (button) { switch (button) {
case 'undoAction': case 'undoAction':
case 'redoAction': case 'redoAction':
@@ -425,7 +424,7 @@ class Reader extends Vue {
break; break;
case 'history': case 'history':
case 'refresh': case 'refresh':
if (!this.lastOpenedBook) if (!this.mostRecentBook())
classResult = classDisabled; classResult = classDisabled;
break; break;
} }
@@ -441,7 +440,7 @@ class Reader extends Vue {
result = 'ProgressPage'; result = 'ProgressPage';
else if (this.loaderActive) else if (this.loaderActive)
result = 'LoaderPage'; result = 'LoaderPage';
else if (this.lastOpenedBook) else if (this.mostRecentBook())
result = 'TextPage'; result = 'TextPage';
if (!result) { if (!result) {
@@ -456,7 +455,7 @@ class Reader extends Vue {
if (this.lastActivePage != result && result == 'TextPage') { if (this.lastActivePage != result && result == 'TextPage') {
//акивируем страницу с текстом //акивируем страницу с текстом
this.$nextTick(async() => { this.$nextTick(async() => {
const last = this.lastOpenedBook; const last = this.mostRecentBook();
const isParsed = await bookManager.hasBookParsed(last); const isParsed = await bookManager.hasBookParsed(last);
if (!isParsed) { if (!isParsed) {
@@ -489,9 +488,9 @@ class Reader extends Vue {
progress.show(); progress.show();
progress.setState({state: 'parse'}); progress.setState({state: 'parse'});
// есть ли среди истории OpenedBook // есть ли среди недавних
const key = bookManager.keyFromUrl(opts.url); const key = bookManager.keyFromUrl(opts.url);
let wasOpened = this.reader.openedBook[key]; let wasOpened = bookManager.getRecentBook({key});
wasOpened = (wasOpened ? wasOpened : {}); wasOpened = (wasOpened ? wasOpened : {});
const bookPos = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPos); const bookPos = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPos);
const bookPosSeen = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPosSeen); const bookPosSeen = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPosSeen);
@@ -506,7 +505,7 @@ class Reader extends Vue {
// если есть в локальном кеше // если есть в локальном кеше
if (bookParsed) { if (bookParsed) {
this.commit('reader/setOpenedBook', Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(bookParsed))); await bookManager.setRecentBook(Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(bookParsed)));
this.loaderActive = false; this.loaderActive = false;
progress.hide(); this.progressActive = false; progress.hide(); this.progressActive = false;
this.blinkCachedLoadMessage(); this.blinkCachedLoadMessage();
@@ -545,7 +544,7 @@ class Reader extends Vue {
}); });
// добавляем в историю // добавляем в историю
this.commit('reader/setOpenedBook', Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(addedBook))); await bookManager.setRecentBook(Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(addedBook)));
this.updateRoute(true); this.updateRoute(true);
this.loaderActive = false; this.loaderActive = false;

View File

@@ -13,12 +13,17 @@ const bmDataStore = localForage.createInstance({
name: 'bmDataStore' name: 'bmDataStore'
}); });
const bmRecentStore = localForage.createInstance({
name: 'bmRecentStore'
});
class BookManager { class BookManager {
async init() { async init() {
this.books = {}; this.books = {};
this.recent = {};
this.recentChanged = true;
const len = await bmMetaStore.length(); let len = await bmMetaStore.length();
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
const key = await bmMetaStore.key(i); const key = await bmMetaStore.key(i);
const keySplit = key.split('-'); const keySplit = key.split('-');
@@ -30,6 +35,13 @@ class BookManager {
} }
} }
len = await bmRecentStore.length();
for (let i = 0; i < len; i++) {
const key = await bmRecentStore.key(i);
let r = await bmRecentStore.getItem(key);
this.recent[r.key] = r;
}
await this.cleanBooks(); await this.cleanBooks();
} }
@@ -142,6 +154,75 @@ class BookManager {
return utils.stringToHex(url); return utils.stringToHex(url);
} }
async setRecentBook(value) {
if (!this.recent)
await this.init();
const result = Object.assign({}, value, {touchTime: Date.now()});
this.recent[result.key] = result;
await bmRecentStore.setItem(result.key, result);
await this.cleanRecentBooks();
this.recentChanged = true;
return result;
}
async getRecentBook(value) {
if (!this.recent)
await this.init();
return this.recent[value.key];
}
async delRecentBook(value) {
if (!this.recent)
await this.init();
await bmRecentStore.removeItem(value.key);
delete this.recent[value.key];
this.recentChanged = true;
}
async cleanRecentBooks() {
if (!this.recent)
await this.init();
if (Object.keys(this.recent).length > 3) {
let min = Date.now();
let found = null;
for (let key in this.recent) {
const book = this.recent[key];
if (book.touchTime < min) {
min = book.touchTime;
found = book;
}
}
if (found) {
await this.delRecentBook(found);
await this.cleanRecentBooks();
}
}
}
mostRecentBook() {
if (!this.recentChanged && this.mostRecentCached) {
return this.mostRecentCached;
}
let max = 0;
let result = null;
for (let key in this.recent) {
const book = this.recent[key];
if (book.touchTime > max) {
max = book.touchTime;
result = book;
}
}
this.mostRecentCached = result;
this.recentChanged = false;
return result;
}
} }
export default new BookManager(); export default new BookManager();

View File

@@ -168,64 +168,20 @@ for (const font of webFonts)
// initial state // initial state
const state = { const state = {
toolBarActive: true, toolBarActive: true,
openedBook: {},
settings: Object.assign({}, settingDefaults), settings: Object.assign({}, settingDefaults),
}; };
// getters // getters
const getters = { const getters = {};
lastOpenedBook: (state) => {
let max = 0;
let result = null;
for (let bookKey in state.openedBook) {
const book = state.openedBook[bookKey];
if (book.touchTime > max) {
max = book.touchTime;
result = book;
}
}
return result;
},
};
// actions // actions
const actions = {}; const actions = {};
function delBook(state, value) {
Vue.delete(state.openedBook, value.key);
}
function cleanBooks(state) {
if (Object.keys(state.openedBook).length > 100) {
let min = Date.now();
let found = null;
for (let bookKey in state.openedBook) {
const book = state.openedBook[bookKey];
if (book.touchTime < min) {
min = book.touchTime;
found = book;
}
}
if (found) {
delBook(state, found);
cleanBooks(state);
}
}
}
// mutations // mutations
const mutations = { const mutations = {
setToolBarActive(state, value) { setToolBarActive(state, value) {
state.toolBarActive = value; state.toolBarActive = value;
}, },
setOpenedBook(state, value) {
Vue.set(state.openedBook, value.key, Object.assign({}, value, {touchTime: Date.now()}));
cleanBooks(state);
},
delOpenedBook(state, value) {
delBook(state, value);
},
setSettings(state, value) { setSettings(state, value) {
state.settings = Object.assign({}, state.settings, value); state.settings = Object.assign({}, state.settings, value);
} }