diff --git a/android/app/src/main/assets/css/index.css b/android/app/src/main/assets/css/index.css
index a028dec9..9b27fffa 100644
--- a/android/app/src/main/assets/css/index.css
+++ b/android/app/src/main/assets/css/index.css
@@ -303,4 +303,27 @@ tts.highlight {
opacity: 1;
transform: translateX(0);
}
+}
+
+#Image-Modal {
+ position: fixed;
+ left: 0;
+ top: 0;
+ user-select: none;
+}
+
+#Image-Modal.show {
+ display: flex;
+ height: 100%;
+ width: 100%;
+ max-width: max-content;
+ max-height: max-content;
+ background-color: var(--theme-surface-0-9);
+ align-items: center;
+ overflow: scroll;
+}
+
+#Image img {
+ display: block;
+ width: 100%;
}
\ No newline at end of file
diff --git a/android/app/src/main/assets/js/index.js b/android/app/src/main/assets/js/index.js
index 7b21b329..3925eb0e 100644
--- a/android/app/src/main/assets/js/index.js
+++ b/android/app/src/main/assets/js/index.js
@@ -25,6 +25,7 @@ const selectVolumeIcon =
class Reader {
constructor() {
this.selection = window.getSelection();
+ this.viewport = document.querySelector('meta[name=viewport]');
this.footerWrapper = document.getElementById('reader-footer-wrapper');
this.percentage = document.getElementById('reader-percentage');
this.battery = document.getElementById('reader-battery');
@@ -510,6 +511,14 @@ class ContextMenu {
});
document.addEventListener('contextmenu', e => {
e.preventDefault();
+ if (e.target instanceof HTMLImageElement) {
+ if (imageModal.showing) {
+ imageModal.hide();
+ } else {
+ imageModal.show(e.target);
+ }
+ return;
+ }
this.isOpened = true;
if (this.reader.selection.type === 'Range') {
this.renderMenu([this.items.START_HERE, this.items.START_READING]);
@@ -517,7 +526,7 @@ class ContextMenu {
this.renderMenu([this.items.START_READING]);
}
const { clientX, clientY } = e;
- document.body.appendChild(this.contextMenu);
+ e.target.appendChild(this.contextMenu);
const positionY =
clientY + this.contextMenu.scrollHeight >= window.innerHeight
? window.innerHeight - this.contextMenu.scrollHeight - 20
@@ -537,6 +546,55 @@ class ContextMenu {
}
}
+/**
+ * @type {import("./type").ImageModal}
+ */
+class ImageModal {
+ /**
+ * @param {import('./type').Reader} reader
+ */
+ constructor(reader) {
+ this.reader = reader;
+ this.$ = document.getElementById('Image-Modal');
+ this.img = this.$.querySelector('img');
+ this.showing = false;
+ this.$.onclick = e => {
+ if (e.target.id !== 'Image-Modal-img') {
+ e.stopPropagation();
+ this.hide();
+ }
+ };
+ this.$.ontouchmove = e => {
+ e.stopImmediatePropagation();
+ };
+ }
+
+ /**
+ *
+ * @param {HTMLImageElement} image
+ */
+ show(image) {
+ this.img.src = image.src;
+ this.img.alt = `Can not render image from ${image.src}`;
+ this.reader.viewport.setAttribute(
+ 'content',
+ 'width=device-width, initial-scale=1.0, maximum-scale=10',
+ );
+ this.$.classList.add('show');
+ this.showing = true;
+ }
+ hide() {
+ this.$.classList.remove('show');
+ this.showing = false;
+ this.img.src = '';
+ this.img.alt = '';
+ this.reader.viewport.setAttribute(
+ 'content',
+ 'width=device-width, initial-scale=1.0, maximum-scale=1.0',
+ );
+ }
+}
+
try {
var swipeHandler = new SwipeHandler();
var toolWrapper = new ToolWrapper();
@@ -544,6 +602,7 @@ try {
var scrollHandler = new ScrollHandler(reader, toolWrapper);
var tts = new TextToSpeech(reader);
toolWrapper.tools = [scrollHandler, tts];
+ imageModal = new ImageModal(reader);
const contextMenu = new ContextMenu(reader);
contextMenu.init();
} catch (e) {
diff --git a/android/app/src/main/assets/js/type.d.ts b/android/app/src/main/assets/js/type.d.ts
index 436b15b9..76c788f7 100644
--- a/android/app/src/main/assets/js/type.d.ts
+++ b/android/app/src/main/assets/js/type.d.ts
@@ -7,6 +7,7 @@ import 'typescript/lib/lib.dom';
interface Reader {
selection: Selection;
+ viewport: HTMLMetaElement;
footerWrapper: HTMLDivElement;
percentage: HTMLDivElement;
battery: HTMLDivElement;
@@ -60,3 +61,10 @@ interface ContextMenu {
closeMenu: (menu: HTMLUListElement) => void;
init: () => void;
}
+
+interface ImageModal {
+ reader: Reader;
+ showing: boolean;
+ show: (image: HTMLImageElement) => void;
+ hide: () => void;
+}
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index a8a910f1..2f1bd928 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -11,6 +11,7 @@
- @color/colorPrimaryDark
- @color/colorPrimaryDark
- @color/colorPrimaryDark
+ - #2596be