Persistent storage controller (#1478)
* Add PersistentStorageController * Update DictionaryController * Update DictionaryImportController * Update when storage stats are updated
This commit is contained in:
parent
571b865ae5
commit
4208595293
@ -190,10 +190,9 @@ class DictionaryEntry {
|
||||
}
|
||||
|
||||
class DictionaryController {
|
||||
constructor(settingsController, modalController, storageController, statusFooter) {
|
||||
constructor(settingsController, modalController, statusFooter) {
|
||||
this._settingsController = settingsController;
|
||||
this._modalController = modalController;
|
||||
this._storageController = storageController;
|
||||
this._statusFooter = statusFooter;
|
||||
this._dictionaries = null;
|
||||
this._dictionaryEntries = [];
|
||||
@ -436,7 +435,6 @@ class DictionaryController {
|
||||
const index = this._dictionaryEntries.findIndex((entry) => entry.dictionaryTitle === dictionaryTitle);
|
||||
if (index < 0) { return; }
|
||||
|
||||
const storageController = this._storageController;
|
||||
const statusFooter = this._statusFooter;
|
||||
const {node} = this._dictionaryEntries[index];
|
||||
const progressSelector = '.dictionary-delete-progress';
|
||||
@ -483,7 +481,7 @@ class DictionaryController {
|
||||
if (statusFooter !== null) { statusFooter.setTaskActive(progressSelector, false); }
|
||||
this._setButtonsEnabled(true);
|
||||
this._isDeleting = false;
|
||||
if (storageController !== null) { storageController.updateStats(); }
|
||||
this._triggerStorageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,6 +545,10 @@ class DictionaryController {
|
||||
}
|
||||
}
|
||||
|
||||
_triggerStorageChanged() {
|
||||
yomichan.trigger('storageChanged');
|
||||
}
|
||||
|
||||
static createDefaultDictionarySettings() {
|
||||
return {
|
||||
enabled: false,
|
||||
|
@ -22,10 +22,9 @@
|
||||
*/
|
||||
|
||||
class DictionaryImportController {
|
||||
constructor(settingsController, modalController, storageController, statusFooter) {
|
||||
constructor(settingsController, modalController, statusFooter) {
|
||||
this._settingsController = settingsController;
|
||||
this._modalController = modalController;
|
||||
this._storageController = storageController;
|
||||
this._statusFooter = statusFooter;
|
||||
this._modifying = false;
|
||||
this._purgeButton = null;
|
||||
@ -92,7 +91,6 @@ class DictionaryImportController {
|
||||
if (this._modifying) { return; }
|
||||
|
||||
const purgeNotification = this._purgeNotification;
|
||||
const storageController = this._storageController;
|
||||
const prevention = this._preventPageExit();
|
||||
|
||||
try {
|
||||
@ -114,7 +112,7 @@ class DictionaryImportController {
|
||||
if (purgeNotification !== null) { purgeNotification.hidden = true; }
|
||||
this._setSpinnerVisible(false);
|
||||
this._setModifying(false);
|
||||
if (storageController !== null) { storageController.updateStats(); }
|
||||
this._triggerStorageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +120,6 @@ class DictionaryImportController {
|
||||
if (this._modifying) { return; }
|
||||
|
||||
const statusFooter = this._statusFooter;
|
||||
const storageController = this._storageController;
|
||||
const importInfo = document.querySelector('#dictionary-import-info');
|
||||
const progressSelector = '.dictionary-import-progress';
|
||||
const progressContainers = [
|
||||
@ -156,7 +153,7 @@ class DictionaryImportController {
|
||||
const statusString = `${percent.toFixed(0)}%`;
|
||||
for (const progressBar of progressBars) { progressBar.style.width = cssString; }
|
||||
for (const label of statusLabels) { label.textContent = statusString; }
|
||||
if (storageController !== null) { storageController.updateStats(); }
|
||||
this._triggerStorageChanged();
|
||||
};
|
||||
|
||||
const fileCount = files.length;
|
||||
@ -186,7 +183,7 @@ class DictionaryImportController {
|
||||
}
|
||||
this._setSpinnerVisible(false);
|
||||
this._setModifying(false);
|
||||
if (storageController !== null) { storageController.updateStats(); }
|
||||
this._triggerStorageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,4 +339,8 @@ class DictionaryImportController {
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
_triggerStorageChanged() {
|
||||
yomichan.trigger('storageChanged');
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
* GenericSettingController
|
||||
* ModalController
|
||||
* PermissionsToggleController
|
||||
* PersistentStorageController
|
||||
* PopupPreviewController
|
||||
* ProfileController
|
||||
* ScanInputsController
|
||||
@ -63,7 +64,10 @@ async function setupEnvironmentInfo() {
|
||||
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
||||
settingsController.prepare();
|
||||
|
||||
const storageController = new StorageController();
|
||||
const persistentStorageController = new PersistentStorageController();
|
||||
persistentStorageController.prepare();
|
||||
|
||||
const storageController = new StorageController(persistentStorageController);
|
||||
storageController.prepare();
|
||||
|
||||
const genericSettingController = new GenericSettingController(settingsController);
|
||||
@ -81,10 +85,10 @@ async function setupEnvironmentInfo() {
|
||||
const profileController = new ProfileController(settingsController, modalController);
|
||||
profileController.prepare();
|
||||
|
||||
const dictionaryController = new DictionaryController(settingsController, modalController, storageController, null);
|
||||
const dictionaryController = new DictionaryController(settingsController, modalController, null);
|
||||
dictionaryController.prepare();
|
||||
|
||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, storageController, null);
|
||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, null);
|
||||
dictionaryImportController.prepare();
|
||||
|
||||
const ankiController = new AnkiController(settingsController);
|
||||
|
94
ext/js/pages/settings/persistent-storage-controller.js
Normal file
94
ext/js/pages/settings/persistent-storage-controller.js
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class PersistentStorageController {
|
||||
constructor() {
|
||||
this._persistentStorageCheckbox = false;
|
||||
}
|
||||
|
||||
async prepare() {
|
||||
this._persistentStorageCheckbox = document.querySelector('#storage-persistent-checkbox');
|
||||
this._persistentStorageCheckbox.addEventListener('change', this._onPersistentStorageCheckboxChange.bind(this), false);
|
||||
|
||||
const button = document.querySelector('#storage-persistent-button');
|
||||
if (button !== null) {
|
||||
button.hidden = false;
|
||||
button.addEventListener('click', this._onPersistStorageButtonClick.bind(this), false);
|
||||
}
|
||||
|
||||
if (!this._isPersistentStorageSupported()) { return; }
|
||||
|
||||
const info = document.querySelector('#storage-persistent-info');
|
||||
if (info !== null) { info.hidden = false; }
|
||||
|
||||
const isStoragePeristent = await this.isStoragePeristent();
|
||||
this._updateCheckbox(isStoragePeristent);
|
||||
}
|
||||
|
||||
async isStoragePeristent() {
|
||||
try {
|
||||
return await navigator.storage.persisted();
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_onPersistentStorageCheckboxChange(e) {
|
||||
const node = e.currentTarget;
|
||||
if (node.checked) {
|
||||
node.checked = false;
|
||||
this._attemptPersistStorage();
|
||||
} else {
|
||||
node.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
_onPersistStorageButtonClick() {
|
||||
const {checked} = this._persistentStorageCheckbox;
|
||||
if (checked) { return; }
|
||||
this._persistentStorageCheckbox.checked = !checked;
|
||||
this._persistentStorageCheckbox.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
async _attemptPersistStorage() {
|
||||
let isStoragePeristent = false;
|
||||
try {
|
||||
isStoragePeristent = await navigator.storage.persist();
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
this._updateCheckbox(isStoragePeristent);
|
||||
|
||||
const node = document.querySelector('#storage-persistent-fail-warning');
|
||||
if (node !== null) { node.hidden = isStoragePeristent; }
|
||||
|
||||
yomichan.trigger('storageChanged');
|
||||
}
|
||||
|
||||
_isPersistentStorageSupported() {
|
||||
return isObject(navigator.storage) && typeof navigator.storage.persist === 'function';
|
||||
}
|
||||
|
||||
_updateCheckbox(isStoragePeristent) {
|
||||
this._persistentStorageCheckbox.checked = isStoragePeristent;
|
||||
this._persistentStorageCheckbox.readOnly = isStoragePeristent;
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@
|
||||
* ModalController
|
||||
* NestedPopupsController
|
||||
* PermissionsToggleController
|
||||
* PersistentStorageController
|
||||
* PopupPreviewController
|
||||
* PopupWindowController
|
||||
* ProfileController
|
||||
@ -79,13 +80,16 @@ async function setupGenericSettingsController(genericSettingController) {
|
||||
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
||||
settingsController.prepare();
|
||||
|
||||
const storageController = new StorageController();
|
||||
const persistentStorageController = new PersistentStorageController();
|
||||
persistentStorageController.prepare();
|
||||
|
||||
const storageController = new StorageController(persistentStorageController);
|
||||
storageController.prepare();
|
||||
|
||||
const dictionaryController = new DictionaryController(settingsController, modalController, storageController, statusFooter);
|
||||
const dictionaryController = new DictionaryController(settingsController, modalController, statusFooter);
|
||||
dictionaryController.prepare();
|
||||
|
||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, storageController, statusFooter);
|
||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, statusFooter);
|
||||
dictionaryImportController.prepare();
|
||||
|
||||
const genericSettingController = new GenericSettingController(settingsController);
|
||||
|
@ -16,11 +16,11 @@
|
||||
*/
|
||||
|
||||
class StorageController {
|
||||
constructor() {
|
||||
constructor(persistentStorageController) {
|
||||
this._persistentStorageController = persistentStorageController;
|
||||
this._mostRecentStorageEstimate = null;
|
||||
this._storageEstimateFailed = false;
|
||||
this._isUpdating = false;
|
||||
this._persistentStorageCheckbox = false;
|
||||
this._storageUsageNode = null;
|
||||
this._storageQuotaNode = null;
|
||||
this._storageUseFiniteNodes = null;
|
||||
@ -30,7 +30,6 @@ class StorageController {
|
||||
}
|
||||
|
||||
prepare() {
|
||||
this._persistentStorageCheckbox = document.querySelector('#storage-persistent-checkbox');
|
||||
this._storageUsageNodes = document.querySelectorAll('.storage-usage');
|
||||
this._storageQuotaNodes = document.querySelectorAll('.storage-quota');
|
||||
this._storageUseFiniteNodes = document.querySelectorAll('.storage-use-finite');
|
||||
@ -38,13 +37,23 @@ class StorageController {
|
||||
this._storageUseValidNodes = document.querySelectorAll('.storage-use-valid');
|
||||
this._storageUseInvalidNodes = document.querySelectorAll('.storage-use-invalid');
|
||||
|
||||
this._preparePersistentStorage();
|
||||
this.updateStats();
|
||||
this._persistentStorageCheckbox.addEventListener('change', this._onPersistentStorageCheckboxChange.bind(this), false);
|
||||
document.querySelector('#storage-refresh').addEventListener('click', this.updateStats.bind(this), false);
|
||||
document.querySelector('#storage-refresh').addEventListener('click', this._onStorageRefreshButtonClick.bind(this), false);
|
||||
yomichan.on('storageChanged', this._onStorageChanged.bind(this));
|
||||
|
||||
this._updateStats();
|
||||
}
|
||||
|
||||
async updateStats() {
|
||||
// Private
|
||||
|
||||
_onStorageRefreshButtonClick() {
|
||||
this._updateStats();
|
||||
}
|
||||
|
||||
_onStorageChanged() {
|
||||
this._updateStats();
|
||||
}
|
||||
|
||||
async _updateStats() {
|
||||
if (this._isUpdating) { return; }
|
||||
|
||||
try {
|
||||
@ -54,7 +63,7 @@ class StorageController {
|
||||
const valid = (estimate !== null);
|
||||
|
||||
// Firefox reports usage as 0 when persistent storage is enabled.
|
||||
const finite = valid && (estimate.usage > 0 || !(await this._isStoragePeristent()));
|
||||
const finite = valid && (estimate.usage > 0 || !(await this._persistentStorageController.isStoragePeristent()));
|
||||
if (finite) {
|
||||
for (const node of this._storageUsageNodes) {
|
||||
node.textContent = this._bytesToLabeledString(estimate.usage);
|
||||
@ -77,61 +86,6 @@ class StorageController {
|
||||
|
||||
// Private
|
||||
|
||||
async _preparePersistentStorage() {
|
||||
if (!(navigator.storage && navigator.storage.persist)) {
|
||||
// Not supported
|
||||
return;
|
||||
}
|
||||
|
||||
const info = document.querySelector('#storage-persistent-info');
|
||||
if (info !== null) { info.hidden = false; }
|
||||
|
||||
const isStoragePeristent = await this._isStoragePeristent();
|
||||
this._updateCheckbox(isStoragePeristent);
|
||||
|
||||
const button = document.querySelector('#storage-persistent-button');
|
||||
if (button !== null) {
|
||||
button.hidden = false;
|
||||
button.addEventListener('click', this._onPersistStorageButtonClick.bind(this), false);
|
||||
}
|
||||
}
|
||||
|
||||
_onPersistentStorageCheckboxChange(e) {
|
||||
const node = e.currentTarget;
|
||||
if (!node.checked) {
|
||||
node.checked = true;
|
||||
return;
|
||||
}
|
||||
this._attemptPersistStorage();
|
||||
}
|
||||
|
||||
_onPersistStorageButtonClick() {
|
||||
const {checked} = this._persistentStorageCheckbox;
|
||||
if (checked) { return; }
|
||||
this._persistentStorageCheckbox.checked = !checked;
|
||||
this._persistentStorageCheckbox.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
async _attemptPersistStorage() {
|
||||
if (await this._isStoragePeristent()) { return; }
|
||||
|
||||
let isStoragePeristent = false;
|
||||
try {
|
||||
isStoragePeristent = await navigator.storage.persist();
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
this._updateCheckbox(isStoragePeristent);
|
||||
|
||||
if (isStoragePeristent) {
|
||||
this.updateStats();
|
||||
} else {
|
||||
const node = document.querySelector('#storage-persistent-fail-warning');
|
||||
if (node !== null) { node.hidden = false; }
|
||||
}
|
||||
}
|
||||
|
||||
async _storageEstimate() {
|
||||
if (this._storageEstimateFailed && this._mostRecentStorageEstimate === null) {
|
||||
return null;
|
||||
@ -159,21 +113,6 @@ class StorageController {
|
||||
return `${label}${labels[labelIndex]}`;
|
||||
}
|
||||
|
||||
async _isStoragePeristent() {
|
||||
try {
|
||||
return await navigator.storage.persisted();
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_updateCheckbox(isStoragePeristent) {
|
||||
const checkbox = this._persistentStorageCheckbox;
|
||||
checkbox.checked = isStoragePeristent;
|
||||
checkbox.readOnly = isStoragePeristent;
|
||||
}
|
||||
|
||||
_setElementsVisible(elements, visible) {
|
||||
visible = !visible;
|
||||
for (const element of elements) {
|
||||
|
@ -62,10 +62,10 @@ async function setupGenericSettingsController(genericSettingController) {
|
||||
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
||||
settingsController.prepare();
|
||||
|
||||
const dictionaryController = new DictionaryController(settingsController, modalController, null, statusFooter);
|
||||
const dictionaryController = new DictionaryController(settingsController, modalController, statusFooter);
|
||||
dictionaryController.prepare();
|
||||
|
||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, null, statusFooter);
|
||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, statusFooter);
|
||||
dictionaryImportController.prepare();
|
||||
|
||||
const genericSettingController = new GenericSettingController(settingsController);
|
||||
|
@ -1319,6 +1319,7 @@
|
||||
<script src="/js/pages/settings/modal-controller.js"></script>
|
||||
<script src="/js/pages/settings/modal-jquery.js"></script>
|
||||
<script src="/js/pages/settings/permissions-toggle-controller.js"></script>
|
||||
<script src="/js/pages/settings/persistent-storage-controller.js"></script>
|
||||
<script src="/js/pages/settings/popup-preview-controller.js"></script>
|
||||
<script src="/js/pages/settings/profile-conditions-ui.js"></script>
|
||||
<script src="/js/pages/settings/profile-controller.js"></script>
|
||||
|
@ -3270,6 +3270,7 @@
|
||||
<script src="/js/pages/settings/modal-controller.js"></script>
|
||||
<script src="/js/pages/settings/nested-popups-controller.js"></script>
|
||||
<script src="/js/pages/settings/permissions-toggle-controller.js"></script>
|
||||
<script src="/js/pages/settings/persistent-storage-controller.js"></script>
|
||||
<script src="/js/pages/settings/popup-preview-controller.js"></script>
|
||||
<script src="/js/pages/settings/popup-window-controller.js"></script>
|
||||
<script src="/js/pages/settings/profile-conditions-ui.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user