summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2019-03-13 15:53:55 +0300
committerAndrew Dolgov <[email protected]>2019-03-13 15:53:55 +0300
commit215ac541007eb25d3c7c1d193f0e9326cf5e56cf (patch)
treef8aa9d732a3a66bc3861289ccff6a2c809b8631f
parent7c6287dfd404e96f080c48681c349919868e6f42 (diff)
add more basic stuff
-rwxr-xr-xapp.js16
-rwxr-xr-xpackage-lock.json21
-rwxr-xr-xpackage.json1
-rwxr-xr-xreader.css14
-rwxr-xr-xreader.html57
-rwxr-xr-xreader.js152
6 files changed, 195 insertions, 66 deletions
diff --git a/app.js b/app.js
index ba5686a..71ee502 100755
--- a/app.js
+++ b/app.js
@@ -23,6 +23,7 @@ function openFileDialog() {
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
+ icon: 'img/favicon.png',
width: 1280,
height: 1024,
webPreferences: {
@@ -36,24 +37,27 @@ function createWindow() {
{
label: 'File',
submenu: [
- {label: 'Open...', click: () => {
- openFileDialog();
- }},
+ {label: 'Open...', accelerator: 'Ctrl+O', click: () => { openFileDialog(); }},
+ {label: 'Close', click: () => { mainWindow.webContents.send("close-file"); }},
+ {type: 'separator'},
{label: 'Exit', click: () => { app.quit(); }}
]
},
{
label: 'Location',
submenu: [
- {label: 'Go to...', click: () => { mainWindow.webContents.send("open-location"); }},
+ {label: 'Go to...', accelerator: 'Ctrl+G', click: () => { mainWindow.webContents.send("open-location"); }},
{label: 'Sync to last page read', click: () => { mainWindow.webContents.send("sync-to-last"); }},
+ {type: 'separator'},
+ {label: 'Clear last read', click: () => { mainWindow.webContents.send("clear-last-read"); }},
+ {label: 'Mark as read', accelerator: 'Ctrl+M', click: () => { mainWindow.webContents.send("mark-as-read"); }},
]
},
{
label: 'Tools',
submenu: [
- {label: 'Settings', click: () => { mainWindow.webContents.send("open-settings"); }},
- {label: 'Toggle fullscreen', click: () => { mainWindow.setFullScreen(!mainWindow.isFullScreen()); }},
+ {label: 'Options', click: () => { mainWindow.webContents.send("open-settings"); }},
+ {label: 'Toggle fullscreen', accelerator: 'F11', click: () => { mainWindow.setFullScreen(!mainWindow.isFullScreen()); }},
]
},
]);
diff --git a/package-lock.json b/package-lock.json
index 29f4a4b..a8bae51 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -219,6 +219,14 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
+ "doc-ready": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/doc-ready/-/doc-ready-1.0.4.tgz",
+ "integrity": "sha1-N/U5GWnP+ZQwP9/vLl1QNX+BZNM=",
+ "requires": {
+ "eventie": "^1"
+ }
+ },
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -257,6 +265,14 @@
"sumchecker": "^2.0.2"
}
},
+ "electron-prompt": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/electron-prompt/-/electron-prompt-1.3.0.tgz",
+ "integrity": "sha512-BsoPDQ84QEzQtqWjbbDlFqwKKAgC6F6RKbLVKSRC4AQLxOqfqKlSm56RLNk1hV00iG4IutJiALgGhKhmxysEIQ==",
+ "requires": {
+ "doc-ready": "^1.0.4"
+ }
+ },
"env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
@@ -272,6 +288,11 @@
"is-arrayish": "^0.2.1"
}
},
+ "eventie": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/eventie/-/eventie-1.0.6.tgz",
+ "integrity": "sha1-1P/IsMK15JPCqhsiy+kY067nRDc="
+ },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
diff --git a/package.json b/package.json
index 13c764b..aa45882 100755
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"author": "fox",
"dependencies": {
"adm-zip": "^0.4.7",
+ "electron-prompt": "^1.3.0",
"js-sha1": "^0.6.0"
},
"devDependencies": {
diff --git a/reader.css b/reader.css
index 574ee2c..e2412a3 100755
--- a/reader.css
+++ b/reader.css
@@ -10,6 +10,20 @@
}
}
+#splash {
+ z-index : 999;
+ position : absolute;
+ top : 0;
+ left : 0;
+ width : 100%;
+ height : 100%;
+ background : white;
+ font-size : 21px;
+ display : flex;
+ align-items : center;
+ justify-content : center;
+}
+
.footer {
bottom : 0;
left : 0;
diff --git a/reader.html b/reader.html
index 7ff1640..d2edd8c 100755
--- a/reader.html
+++ b/reader.html
@@ -24,7 +24,7 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
- <h4 class="modal-title">Settings</h4>
+ <h4 class="modal-title">Options</h4>
</div>
<div class="modal-body">
<form name="settings-form" onsubmit="return false" class="form-horizontal">
@@ -40,32 +40,21 @@
</div>
<div class="form-group">
- <label class="col-sm-3 control-label"></label>
+ <label class="col-sm-3 control-label">Reading:</label>
<div class="col-sm-9">
<div class="checkbox">
- <label><input class="fit-to-width-cb" type="checkbox"> Fit to width</label>
+ <label><input class="fit-to-width-cb" type="checkbox" data-bind="attr: { checked: fitToWidth }"> Fit to width</label>
</div>
<div class="checkbox">
- <label><input class="keep-ui-visible-cb" type="checkbox"> Keep UI when turning
- pages</label>
- </div>
- </div>
- </div>
-
- <div class="form-group">
- <label class="col-sm-3 control-label">Columns</label>
- <div class="col-sm-9">
- <div class="checkbox">
- <label title="Applies for active file"><input class="single-column-cb" type="checkbox">
+ <label title="Applies for active file"><input class="single-column-cb" type="checkbox" data-bind="attr: { checked: singleColumn }">
Force single column</label>
</div>
<div class="checkbox">
- <label title="Applies for active file"><input class="flip-columns-cb" type="checkbox">
+ <label title="Applies for active file"><input class="flip-columns-cb" type="checkbox" data-bind="attr: { checked: flipColumns }">
Mirror (manga mode)</label>
</div>
-
</div>
</div>
@@ -78,36 +67,6 @@
</div>
</div>
- <!-- <div class="form-group">
- <label class="col-sm-3 control-label"></label>
- <div class="col-sm-9">
- <div class="checkbox">
- <label><input class="sync-enabled" type="checkbox"> Sync enabled</label>
- </div>
- </div>
- </div> -->
-
- <div class="form-group">
- <label class="col-sm-3 control-label">Position:</label>
- <div class="col-sm-9">
- <div class="input-group">
- <input type="numeric" disabled="disabled" class="form-control last-read-position">
- <span class="input-group-btn">
- <button class="btn btn-danger last-read-clear-btn" type="button">Clear</button>
- </span>
- </div>
- </div>
- </div>
-
- <div class="form-group">
- <label class="col-sm-3 control-label"></label>
- <div class="col-sm-9">
- <button class="btn btn-default sync-to-last-read-btn" type="button">Sync to last page read
- </button>
- <button class="btn btn-primary mark-as-read-btn" type="button">Mark as read</button>
- </div>
- </div>
-
</form>
</div>
<div class="modal-footer">
@@ -118,10 +77,12 @@
</div>
<div class="container">
+ <div id="splash" class="text-muted" data-bind="visible: !fileName()">No active file (Ctrl+O).</div>
+
<div id="left"><span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span></div>
<div id="right"><span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span></div>
- <div id="reader" class="single-column fit-size">
+ <div id="reader" data-bind="css: { 'fit-width': fitToWidth, 'fit-size': fitSize, 'flip-columns': flipColumns, 'single-column': singleColumn }">
<img class="left-page" data-bind="attr: { src: getLeftPage }">
<img style="display : none" data-bind="attr: { src: getRightPage }" class="right-page hidden-xs hidden-sm hidden-md hidden-portrait">
</div>
@@ -130,7 +91,7 @@
<div class="spacer"></div>
<div class="location">
<span data-bind="html: currentPageDisp"></span> / <span data-bind="html: totalPages"></span>
- (<span data-bind="html: progressPct"></span>)
+ (<span data-bind="html: progressPct"></span>%)
</div>
</div>
</div>
diff --git a/reader.js b/reader.js
index 112d430..2640509 100755
--- a/reader.js
+++ b/reader.js
@@ -59,6 +59,13 @@ function Model() {
},
};
+ self.closeFile = function() {
+ self._zipEntries.removeAll();
+ self._zip = null;
+ self.fileName("");
+ self.currentPage(-2);
+ };
+
self.openFile = function (file) {
console.log('openFile', file);
@@ -84,6 +91,13 @@ function Model() {
self.fileName(file.split(/[\\/]/).pop());
+ localforage.getItem(model.cacheKey("SINGLE-COLUMN")).then((single) => {
+ model.singleColumn(single);
+ });
+
+ localforage.getItem(model.cacheKey("FLIP-COLUMNS")).then((flip) => {
+ model.flipColumns(flip);
+ });
localforage.getItem(self.cacheKey("POSITION")).then((page) => {
if (page)
@@ -96,7 +110,7 @@ function Model() {
self.documentTitle = ko.computed(function () {
if (self.fileName())
- return "Pow! Comics Reader: " + self.fileName();
+ return "Pow! Comics Reader:" + self.fileName();
else
return "Pow! Comics Reader";
});
@@ -114,9 +128,9 @@ function Model() {
write: function(page) {
self._currentPage(page);
- localforage.getItem(model.cacheKey("POSITION")).then((stored) => {
+ localforage.getItem(self.cacheKey("POSITION")).then((stored) => {
if (stored < page) {
- localforage.setItem(model.cacheKey("POSITION"), page).then(() => {
+ localforage.setItem(self.cacheKey("POSITION"), page).then(() => {
console.log('saved position', page);
if (page % 10 == 0) {
@@ -128,6 +142,49 @@ function Model() {
},
});
+ self._fitToWidth = ko.observable(false);
+
+ self.fitToWidth = ko.computed({
+ read: function() {
+ return self._fitToWidth();
+ },
+ write: function(ftw) {
+ localforage.setItem("FIT-TO-WIDTH", ftw).then(() => {
+ self._fitToWidth(ftw);
+ });
+ },
+ });
+
+ self._singleColumn = ko.observable(false);
+
+ self.singleColumn = ko.computed({
+ read: function() {
+ return self._singleColumn();
+ },
+ write: function(single) {
+ localforage.setItem(self.cacheKey("SINGLE-COLUMN"), single).then(() => {
+ self._singleColumn(single);
+ });
+ },
+ });
+
+ self._flipColumns = ko.observable(false);
+
+ self.flipColumns = ko.computed({
+ read: function() {
+ return self._flipColumns();
+ },
+ write: function (flip) {
+ localforage.setItem(self.cacheKey("FLIP-COLUMNS"), flip).then(() => {
+ self._flipColumns(flip);
+ });
+ },
+ });
+
+ self.fitSize = ko.computed(function() {
+ return !self.fitToWidth();
+ });
+
self.currentPageDisp = ko.computed(function () {
const page = self.currentPage();
@@ -139,12 +196,19 @@ function Model() {
self.progressPct = ko.computed(function () {
if (self.totalPages() > 0) {
- return parseInt(self.currentPage() / self.totalPages() * 100) + "%";
+ return parseInt(self.currentPage() / self.totalPages() * 100);
} else {
return "";
}
});
+ self._updateProgress = ko.computed(function() {
+ const progress = self.progressPct();
+ const { remote } = require('electron');
+
+ remote.getCurrentWindow().setProgressBar(progress/100);
+ });
+
self.getLeftPage = ko.computed(function () {
const page = self.currentPage();
@@ -173,14 +237,17 @@ function Model() {
const model = new Model();
$(document).ready(function () {
- const {remote, ipcRenderer} = require('electron');
- const {BrowserWindow} = remote;
+ const { ipcRenderer } = require('electron');
localforage.getItem("TTC:SYNC-ACCOUNT").then((acct) => {
if (acct)
model.syncAccount(acct);
});
+ localforage.getItem("FIT-TO-WIDTH").then((ftw) => {
+ model.fitToWidth(ftw);
+ });
+
ko.applyBindings(model, document.querySelector('html'));
ipcRenderer.on("open-settings", () => {
@@ -191,6 +258,28 @@ $(document).ready(function () {
model.openFile(args[0]);
});
+ ipcRenderer.on("mark-as-read", (event, args) => {
+ if (confirm("Mark as read?")) {
+ model.currentPage(model.totalPages()-1);
+ }
+ });
+
+ ipcRenderer.on("open-location", (event, args) => {
+ $(".location").click();
+ });
+
+ ipcRenderer.on("close-file", (event, args) => {
+ model.closeFile();
+ });
+
+ ipcRenderer.on("clear-last-read", (event, args) => {
+ if (confirm("Clear stored last read position?")) {
+ localforage.setItem(model.cacheKey("POSITION"), 0).then(() => {
+ model.currentPage(0);
+ });
+ }
+ });
+
ipcRenderer.on("sync-to-last", (event, args) => {
model.syncClient.get().then((page) => {
if (confirm("You are currently on page %p. Furthest read page stored on the server is %r. Open it instead?"
@@ -203,15 +292,42 @@ $(document).ready(function () {
});
});
+ $("#reader img").on("load", function(e) {
+ const img = $(this);
+ const is_right = img.hasClass('right-page');
+
+ if (!is_right) {
+ if (img.width() > img.height()) {
+ $(".right-page").hide();
+ } else {
+ $(".right-page").show();
+ }
+ }
+
+ });
+
$(".location").click(function() {
- const current = model.currentPageDisp();
const total = model.totalPages();
- const page = prompt("Jump to location [1-" + total + "]", parseInt(current));
+ if (total == 0)
+ return;
- if (page) {
- $("#reader img").attr("data-page", parseInt(page - 1));
- }
+ const prompt = require('electron-prompt');
+
+ prompt({
+ title: "Go to",
+ label: '<small>Jump to location [1-' + total + ']:</small>',
+ value: model.currentPageDisp(),
+ useHtmlLabel: true,
+ height: 160,
+ inputAttrs: {
+ type: 'numeric'
+ }
+ }).then((res) => {
+ if (res != null && res <= model.totalPages()) {
+ model.currentPage(res - 1);
+ }
+ });
});
$(".sync-account").on("change", function() {
@@ -224,6 +340,18 @@ $(document).ready(function () {
});
});
+ $(".fit-to-width-cb").on("click", (e) => {
+ model.fitToWidth(e.target.checked);
+ });
+
+ $(".single-column-cb").on("click", (e) => {
+ model.singleColumn(e.target.checked);
+ });
+
+ $(".flip-columns-cb").on("click", (e) => {
+ model.flipColumns(e.target.checked);
+ });
+
$("#left").on("click", (e) => {
e.stopPropagation();
@@ -242,7 +370,7 @@ $(document).ready(function () {
let page = model.currentPage();
- if ($(".right-page").is(":visible") && page < total_pages - 2)
+ if ($(".right-page").is(":visible") && page < model.totalPages() - 2)
page = page + 1;
if (page < model.totalPages()) {