Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edge #2

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions app/src/main/assets/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ let renderPending = false;
let renderPendingLazy = false;
const canvas = document.getElementById('content');
let orientationDegrees = 0;
let zoomLevel = 100;
let zoomRatio = 1;
let textLayerDiv = document.getElementById("text");
const zoomLevels = [50, 75, 100, 125, 150];
let task = null;

let newPageNumber = 0;
let newZoomLevel = 0;
let newZoomRatio = 1;
let useRender;

const cache = [];
Expand Down Expand Up @@ -65,13 +64,13 @@ function renderPage(pageNumber, lazy, prerender, prerenderTrigger=0) {
useRender = !prerender;

newPageNumber = pageNumber;
newZoomLevel = zoomLevels[channel.getZoomLevel()];
newZoomRatio = channel.getZoomRatio();
orientationDegrees = channel.getDocumentOrientationDegrees();
console.log("page: " + pageNumber + ", zoom: " + newZoomLevel +
console.log("page: " + pageNumber + ", zoom: " + newZoomRatio +
", orientationDegrees: " + orientationDegrees + ", prerender: " + prerender);
for (let i = 0; i < cache.length; i++) {
const cached = cache[i];
if (cached.pageNumber === pageNumber && cached.zoomLevel === newZoomLevel &&
if (cached.pageNumber === pageNumber && cached.zoomRatio === newZoomRatio &&
cache.orientationDegrees === orientationDegrees) {
if (useRender) {
cache.splice(i, 1);
Expand All @@ -95,7 +94,7 @@ function renderPage(pageNumber, lazy, prerender, prerenderTrigger=0) {
}

const newCanvas = document.createElement("canvas");
const viewport = page.getViewport({scale: newZoomLevel / 100, rotation: orientationDegrees})
const viewport = page.getViewport({scale: newZoomRatio, rotation: orientationDegrees})
const ratio = window.devicePixelRatio;
newCanvas.height = viewport.height * ratio;
newCanvas.width = viewport.width * ratio;
Expand All @@ -105,11 +104,11 @@ function renderPage(pageNumber, lazy, prerender, prerenderTrigger=0) {
newContext.scale(ratio, ratio);

if (useRender) {
if (newZoomLevel !== zoomLevel) {
if (newZoomRatio !== zoomRatio) {
canvas.style.height = viewport.height + "px";
canvas.style.width = viewport.width + "px";
}
zoomLevel = newZoomLevel;
zoomRatio = newZoomRatio;
}

task = page.render({
Expand Down Expand Up @@ -155,7 +154,7 @@ function renderPage(pageNumber, lazy, prerender, prerenderTrigger=0) {
}
cache.push({
pageNumber: pageNumber,
zoomLevel: newZoomLevel,
zoomRatio: newZoomRatio,
orientationDegrees: orientationDegrees,
canvas: newCanvas,
textLayerDiv: newTextLayerDiv
Expand All @@ -170,7 +169,7 @@ function renderPage(pageNumber, lazy, prerender, prerenderTrigger=0) {

function onRenderPage(lazy) {
if (pageRendering) {
if (newPageNumber === channel.getPage() && newZoomLevel === zoomLevels[channel.getZoomLevel()] &&
if (newPageNumber === channel.getPage() && getZoomRatio === channel.getZoomRatio() &&
orientationDegrees === channel.getDocumentOrientationDegrees()) {
useRender = true;
return;
Expand Down
90 changes: 90 additions & 0 deletions app/src/main/java/org/grapheneos/pdfviewer/GestureHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.grapheneos.pdfviewer;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

/*
The GestureHelper present a simple gesture api for the PdfViewer
*/

class GestureHelper {
public interface GestureListener {
boolean onTapUp();
// Can be replaced with ratio when supported
void onZoomIn(int steps);
void onZoomOut(int steps);
void onSwipeEdgeLeft();
void onSwipeEdgeRight();
}

private static final int SPAN_STEP = 150;

@SuppressLint("ClickableViewAccessibility")
static void attach(Activity context, View gestureView, GestureListener listener) {
DisplayMetrics displayMetrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

final GestureDetector detector = new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return listener.onTapUp();
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float diffX = e2.getX() - e1.getX();
if (diffX > 0 && e1.getX() < 10.0) {
listener.onSwipeEdgeRight();
} else if (diffX < 0 && e1.getX() > displayMetrics.widthPixels - 10.0) {
listener.onSwipeEdgeLeft();
} else {
return false;
}
return true;
}
});

final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
// As the zoom value is discrete we listen to scaling step and not scaling ratio
float initialSpan;
int prevNbStep;

@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
initialSpan = detector.getCurrentSpan();
prevNbStep = 0;
return super.onScaleBegin(detector);
}

@Override
public boolean onScale(ScaleGestureDetector detector) {
float spanDiff = initialSpan - detector.getCurrentSpan();
int curNbStep = (int) (spanDiff/SPAN_STEP);
if (curNbStep != prevNbStep) {
int stepDiff = curNbStep - prevNbStep;
if (stepDiff > 0) {
listener.onZoomOut(stepDiff);
} else {
listener.onZoomIn(Math.abs(stepDiff));
}
prevNbStep = curNbStep;
}
return true;
}
});

gestureView.setOnTouchListener((view, motionEvent) -> {
detector.onTouchEvent(motionEvent);
scaleDetector.onTouchEvent(motionEvent);
return false;
});
}

}
104 changes: 64 additions & 40 deletions app/src/main/java/org/grapheneos/pdfviewer/PdfViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.JavascriptInterface;
Expand Down Expand Up @@ -43,7 +41,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader

private static final String STATE_URI = "uri";
private static final String STATE_PAGE = "page";
private static final String STATE_ZOOM_LEVEL = "zoomLevel";
private static final String STATE_ZOOM_RATIO = "zoomRatio";
private static final String STATE_DOCUMENT_ORIENTATION_DEGREES = "documentOrientationDegrees";
private static final String KEY_PROPERTIES = "properties";

Expand Down Expand Up @@ -76,8 +74,8 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
"usb 'none'; " +
"vr 'none'";

private static final int MIN_ZOOM_LEVEL = 0;
private static final int MAX_ZOOM_LEVEL = 4;
private static final float MIN_ZOOM_RATIO = 0.5f;
private static final float MAX_ZOOM_RATIO = 1.5f;
private static final int ALPHA_LOW = 130;
private static final int ALPHA_HIGH = 255;
private static final int ACTION_OPEN_DOCUMENT_REQUEST_CODE = 1;
Expand All @@ -88,7 +86,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
private Uri mUri;
public int mPage;
public int mNumPages;
private int mZoomLevel = 2;
private float mZoomRatio = 1f;
private int mDocumentOrientationDegrees;
private int mDocumentState;
private int windowInsetTop;
Expand All @@ -111,8 +109,8 @@ public int getPage() {
}

@JavascriptInterface
public int getZoomLevel() {
return mZoomLevel;
public float getZoomRatio() {
return mZoomRatio;
}

@JavascriptInterface
Expand Down Expand Up @@ -234,10 +232,10 @@ public void onPageFinished(WebView view, String url) {

showSystemUi();

final GestureDetector detector = new GestureDetector(PdfViewer.this,
new GestureDetector.SimpleOnGestureListener() {
GestureHelper.attach(PdfViewer.this, mWebView,
new GestureHelper.GestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
public boolean onTapUp() {
if (mUri != null) {
mWebView.evaluateJavascript("isTextSelected()", selection -> {
if (!Boolean.valueOf(selection)) {
Expand All @@ -253,11 +251,37 @@ public boolean onSingleTapUp(MotionEvent motionEvent) {
}
return false;
}

@Override
public void onZoomIn(int steps) {
for (int i = 0; i < steps; i++) {
zoomIn();
}
}

@Override
public void onZoomOut(int steps) {
for (int i = 0; i < steps; i++) {
zoomOut();
}
}


@Override
public void onSwipeEdgeRight() {
if (mPage > 0) {
onJumpToPageInDocument(mPage - 1);
}
}


@Override
public void onSwipeEdgeLeft() {
if (mPage < mNumPages) {
onJumpToPageInDocument(mPage + 1);
}
}
});
mWebView.setOnTouchListener((view, motionEvent) -> {
detector.onTouchEvent(motionEvent);
return false;
});

mTextView = new TextView(this);
mTextView.setBackgroundColor(Color.DKGRAY);
Expand All @@ -284,7 +308,7 @@ public boolean onSingleTapUp(MotionEvent motionEvent) {
if (savedInstanceState != null) {
mUri = savedInstanceState.getParcelable(STATE_URI);
mPage = savedInstanceState.getInt(STATE_PAGE);
mZoomLevel = savedInstanceState.getInt(STATE_ZOOM_LEVEL);
mZoomRatio = savedInstanceState.getFloat(STATE_ZOOM_RATIO);
mDocumentOrientationDegrees = savedInstanceState.getInt(STATE_DOCUMENT_ORIENTATION_DEGREES);
}

Expand Down Expand Up @@ -340,6 +364,22 @@ private void openDocument() {
startActivityForResult(intent, ACTION_OPEN_DOCUMENT_REQUEST_CODE);
}

private void zoomIn() {
if (mZoomRatio < MAX_ZOOM_RATIO) {
mZoomRatio += 0.25f;
renderPage(true);
invalidateOptionsMenu();
}
}

private void zoomOut() {
if (mZoomRatio > MIN_ZOOM_RATIO) {
mZoomRatio -= 0.25f;
renderPage(true);
invalidateOptionsMenu();
}
}

private static void enableDisableMenuItem(MenuItem item, boolean enable) {
if (enable) {
if (!item.isEnabled()) {
Expand Down Expand Up @@ -382,7 +422,7 @@ public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putParcelable(STATE_URI, mUri);
savedInstanceState.putInt(STATE_PAGE, mPage);
savedInstanceState.putInt(STATE_ZOOM_LEVEL, mZoomLevel);
savedInstanceState.putFloat(STATE_ZOOM_RATIO, mZoomRatio);
savedInstanceState.putInt(STATE_DOCUMENT_ORIENTATION_DEGREES, mDocumentOrientationDegrees);
}

Expand Down Expand Up @@ -444,18 +484,10 @@ public boolean onPrepareOptionsMenu(Menu menu) {
mDocumentState = STATE_END;
}

switch (mZoomLevel) {
case MAX_ZOOM_LEVEL:
enableDisableMenuItem(menu.findItem(R.id.action_zoom_in), false);
return true;
case MIN_ZOOM_LEVEL:
enableDisableMenuItem(menu.findItem(R.id.action_zoom_out), false);
return true;
default:
enableDisableMenuItem(menu.findItem(R.id.action_zoom_in), true);
enableDisableMenuItem(menu.findItem(R.id.action_zoom_out), true);
return true;
}
enableDisableMenuItem(menu.findItem(R.id.action_zoom_in), mZoomRatio != MAX_ZOOM_RATIO);
enableDisableMenuItem(menu.findItem(R.id.action_zoom_out), mZoomRatio != MIN_ZOOM_RATIO);

return true;
}

@Override
Expand All @@ -482,19 +514,11 @@ public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);

case R.id.action_zoom_out:
if (mZoomLevel > 0) {
mZoomLevel--;
renderPage(true);
invalidateOptionsMenu();
}
zoomOut();
return true;

case R.id.action_zoom_in:
if (mZoomLevel < MAX_ZOOM_LEVEL) {
mZoomLevel++;
renderPage(true);
invalidateOptionsMenu();
}
zoomIn();
return true;

case R.id.action_rotate_clockwise:
Expand All @@ -513,7 +537,7 @@ public boolean onOptionsItemSelected(MenuItem item) {

case R.id.action_jump_to_page:
new JumpToPageFragment()
.show(getSupportFragmentManager(), JumpToPageFragment.TAG);
.show(getSupportFragmentManager(), JumpToPageFragment.TAG);
return true;

default:
Expand Down