libpdfviewer: update to PdfViewer 12

This commit is contained in:
Matéo Duparc 2022-03-06 21:39:38 +01:00
commit 0f312347dd
Signed by: hardcoresushi
GPG Key ID: AFE384344A45E13A
60 changed files with 295 additions and 123 deletions

View File

@ -22,6 +22,13 @@ android {
keyAlias = keystoreProperties["keyAlias"] as String keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String keyPassword = keystoreProperties["keyPassword"] as String
} }
create("play") {
storeFile = rootProject.file(keystoreProperties["storeFile"]!!)
storePassword = keystoreProperties["storePassword"] as String
keyAlias = keystoreProperties["uploadKeyAlias"] as String
keyPassword = keystoreProperties["uploadKeyPassword"] as String
}
} }
} }
@ -43,6 +50,13 @@ android {
} }
} }
create("play") {
initWith(getByName("release"))
if (useKeystoreProperties) {
signingConfig = signingConfigs.getByName("play")
}
}
buildFeatures { buildFeatures {
viewBinding = true viewBinding = true
} }

View File

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.grapheneos.pdfviewer" package="org.grapheneos.pdfviewer"
android:targetSandboxVersion="2"> android:targetSandboxVersion="2">
<original-package android:name="org.grapheneos.pdfviewer" />
<application> <application>
<meta-data android:name="android.webkit.WebView.MetricsOptOut" <meta-data android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" /> android:value="true" />

View File

@ -1,11 +1,11 @@
body, canvas, #padding { body, canvas {
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
#padding { canvas {
min-width: 100%; margin: auto;
background: black; display: block;
} }
.textLayer { .textLayer {

View File

@ -7,7 +7,6 @@
<script src="pdf.js"></script> <script src="pdf.js"></script>
</head> </head>
<body> <body>
<div id="padding"></div>
<canvas id="content"></canvas> <canvas id="content"></canvas>
<div id="text" class="textLayer"></div> <div id="text" class="textLayer"></div>
<script src="viewer.js"></script> <script src="viewer.js"></script>

View File

@ -2,7 +2,6 @@
pdfjsLib.GlobalWorkerOptions.workerSrc = "/pdf.worker.js"; pdfjsLib.GlobalWorkerOptions.workerSrc = "/pdf.worker.js";
const padding = document.getElementById("padding");
let pdfDoc = null; let pdfDoc = null;
let pageRendering = false; let pageRendering = false;
let renderPending = false; let renderPending = false;
@ -56,7 +55,6 @@ function display(newCanvas, zoom) {
canvas.width = newCanvas.width; canvas.width = newCanvas.width;
canvas.style.height = newCanvas.style.height; canvas.style.height = newCanvas.style.height;
canvas.style.width = newCanvas.style.width; canvas.style.width = newCanvas.style.width;
padding.style.width = canvas.style.width;
canvas.getContext("2d", { alpha: false }).drawImage(newCanvas, 0, 0); canvas.getContext("2d", { alpha: false }).drawImage(newCanvas, 0, 0);
if (!zoom) { if (!zoom) {
scrollTo(0, 0); scrollTo(0, 0);
@ -200,14 +198,6 @@ function isTextSelected() {
return window.getSelection().toString() !== ""; return window.getSelection().toString() !== "";
} }
function updateInset() {
const windowInsetTop = channel.getWindowInsetTop() / window.devicePixelRatio + "px";
padding.style.paddingTop = windowInsetTop;
textLayerDiv.style.top = windowInsetTop;
}
updateInset();
pdfjsLib.getDocument("https://localhost/placeholder.pdf").promise.then(function(newDoc) { pdfjsLib.getDocument("https://localhost/placeholder.pdf").promise.then(function(newDoc) {
pdfDoc = newDoc; pdfDoc = newDoc;
channel.setNumPages(pdfDoc.numPages); channel.setNumPages(pdfDoc.numPages);

View File

@ -1,16 +1,18 @@
package org.grapheneos.pdfviewer; package org.grapheneos.pdfviewer;
import android.content.Context; import android.content.pm.PackageInfo;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.webkit.CookieManager; import android.webkit.CookieManager;
import android.webkit.JavascriptInterface; import android.webkit.JavascriptInterface;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
@ -22,11 +24,12 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
import org.grapheneos.pdfviewer.databinding.PdfviewerBinding;
import org.grapheneos.pdfviewer.fragment.DocumentPropertiesFragment; import org.grapheneos.pdfviewer.fragment.DocumentPropertiesFragment;
import org.grapheneos.pdfviewer.fragment.JumpToPageFragment; import org.grapheneos.pdfviewer.fragment.JumpToPageFragment;
import org.grapheneos.pdfviewer.loader.DocumentPropertiesLoader; import org.grapheneos.pdfviewer.loader.DocumentPropertiesLoader;
@ -36,10 +39,11 @@ import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<List<CharSequence>> { public class PdfViewer implements LoaderManager.LoaderCallbacks<List<CharSequence>> {
public static final String TAG = "PdfViewer"; public static final String TAG = "PdfViewer";
private static final String KEY_PROPERTIES = "properties"; private static final String KEY_PROPERTIES = "properties";
private static final int MIN_WEBVIEW_RELEASE = 89;
private static final String CONTENT_SECURITY_POLICY = private static final String CONTENT_SECURITY_POLICY =
"default-src 'none'; " + "default-src 'none'; " +
@ -93,31 +97,64 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
private float mZoomRatio = 1f; private float mZoomRatio = 1f;
private int mDocumentOrientationDegrees; private int mDocumentOrientationDegrees;
private int mDocumentState; private int mDocumentState;
private int windowInsetTop;
private List<CharSequence> mDocumentProperties; private List<CharSequence> mDocumentProperties;
private InputStream mInputStream; private InputStream mInputStream;
private PdfviewerBinding binding;
private TextView mTextView; private TextView mTextView;
private Toast mToast; private Toast mToast;
public AppCompatActivity activity; AppCompatActivity activity;
String fileName; String fileName;
Long fileSize; Long fileSize;
void init(Context context) { private class Channel {
setBackgroundColor(Color.TRANSPARENT); @JavascriptInterface
public int getPage() {
return mPage;
}
@JavascriptInterface
public float getZoomRatio() {
return mZoomRatio;
}
@JavascriptInterface
public int getDocumentOrientationDegrees() {
return mDocumentOrientationDegrees;
}
@JavascriptInterface
public void setNumPages(int numPages) {
mNumPages = numPages;
activity.runOnUiThread(activity::invalidateOptionsMenu);
}
@JavascriptInterface
public void setDocumentProperties(final String properties) {
if (mDocumentProperties != null) {
throw new SecurityException("mDocumentProperties not null");
}
final Bundle args = new Bundle();
args.putString(KEY_PROPERTIES, properties);
activity.runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this.activity).restartLoader(DocumentPropertiesLoader.ID, args, PdfViewer.this));
}
}
public PdfViewer(@NonNull AppCompatActivity activity) {
this.activity = activity;
LayoutInflater inflater = activity.getLayoutInflater();
binding = PdfviewerBinding.inflate(inflater);
activity.setContentView(binding.getRoot());
binding.webview.setBackgroundColor(Color.TRANSPARENT);
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true); WebView.setWebContentsDebuggingEnabled(true);
} }
setOnApplyWindowInsetsListener((view, insets) -> { final WebSettings settings = binding.webview.getSettings();
windowInsetTop = insets.getSystemWindowInsetTop();
evaluateJavascript("updateInset()", null);
return insets;
});
final WebSettings settings = getSettings();
settings.setAllowContentAccess(false); settings.setAllowContentAccess(false);
settings.setAllowFileAccess(false); settings.setAllowFileAccess(false);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE); settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
@ -125,12 +162,12 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
CookieManager.getInstance().setAcceptCookie(false); CookieManager.getInstance().setAcceptCookie(false);
addJavascriptInterface(new Channel(), "channel"); binding.webview.addJavascriptInterface(new Channel(), "channel");
setWebViewClient(new WebViewClient() { binding.webview.setWebViewClient(new WebViewClient() {
private WebResourceResponse fromAsset(final String mime, final String path) { private WebResourceResponse fromAsset(final String mime, final String path) {
try { try {
InputStream inputStream = context.getAssets().open(path.substring(1)); InputStream inputStream = activity.getAssets().open(path.substring(1));
return new WebResourceResponse(mime, null, inputStream); return new WebResourceResponse(mime, null, inputStream);
} catch (IOException e) { } catch (IOException e) {
return null; return null;
@ -188,7 +225,7 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
} }
}); });
GestureHelper.attach(context, this, GestureHelper.attach(activity, binding.webview,
new GestureHelper.GestureListener() { new GestureHelper.GestureListener() {
@Override @Override
public void onZoomIn(float value) { public void onZoomIn(float value) {
@ -206,72 +243,40 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
} }
}); });
mTextView = new TextView(context); mTextView = new TextView(activity);
mTextView.setBackgroundColor(Color.DKGRAY); mTextView.setBackgroundColor(Color.DKGRAY);
mTextView.setTextColor(ColorStateList.valueOf(Color.WHITE)); mTextView.setTextColor(ColorStateList.valueOf(Color.WHITE));
mTextView.setTextSize(18); mTextView.setTextSize(18);
mTextView.setPadding(PADDING, 0, PADDING, 0); mTextView.setPadding(PADDING, 0, PADDING, 0);
} }
public PdfViewer(@NonNull Context context) {
super(context);
init(context);
}
public PdfViewer(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PdfViewer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void onCreateOptionMenu(Menu menu) { public void onCreateOptionMenu(Menu menu) {
MenuInflater inflater = activity.getMenuInflater(); MenuInflater inflater = activity.getMenuInflater();
inflater.inflate(R.menu.pdf_viewer, menu); inflater.inflate(R.menu.pdf_viewer, menu);
} }
private class Channel { public void onResume() {
@JavascriptInterface if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
public int getWindowInsetTop() { // The user could have left the activity to update the WebView
return windowInsetTop; activity.invalidateOptionsMenu();
} if (getWebViewRelease() >= MIN_WEBVIEW_RELEASE) {
binding.webviewOutOfDateLayout.setVisibility(View.GONE);
@JavascriptInterface binding.webview.setVisibility(View.VISIBLE);
public int getPage() { } else {
return mPage; binding.webview.setVisibility(View.GONE);
} binding.webviewOutOfDateMessage.setText(activity.getString(R.string.webview_out_of_date_message, getWebViewRelease(), MIN_WEBVIEW_RELEASE));
binding.webviewOutOfDateLayout.setVisibility(View.VISIBLE);
@JavascriptInterface
public float getZoomRatio() {
return mZoomRatio;
}
@JavascriptInterface
public int getDocumentOrientationDegrees() {
return mDocumentOrientationDegrees;
}
@JavascriptInterface
public void setNumPages(int numPages) {
mNumPages = numPages;
activity.runOnUiThread(activity::invalidateOptionsMenu);
}
@JavascriptInterface
public void setDocumentProperties(final String properties) {
if (mDocumentProperties != null) {
throw new SecurityException("mDocumentProperties not null");
} }
final Bundle args = new Bundle();
args.putString(KEY_PROPERTIES, properties);
activity.runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this.activity).restartLoader(DocumentPropertiesLoader.ID, args, PdfViewer.this));
} }
} }
@RequiresApi(api = Build.VERSION_CODES.O)
private int getWebViewRelease() {
PackageInfo webViewPackage = WebView.getCurrentWebViewPackage();
String webViewVersionName = webViewPackage.versionName;
return Integer.parseInt(webViewVersionName.substring(0, webViewVersionName.indexOf(".")));
}
@NonNull @NonNull
@Override @Override
public Loader<List<CharSequence>> onCreateLoader(int id, Bundle args) { public Loader<List<CharSequence>> onCreateLoader(int id, Bundle args) {
@ -295,12 +300,12 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
mInputStream = inputStream; mInputStream = inputStream;
this.fileName = fileName; this.fileName = fileName;
this.fileSize = fileSize; this.fileSize = fileSize;
loadUrl("https://localhost/viewer.html"); binding.webview.loadUrl("https://localhost/viewer.html");
activity.invalidateOptionsMenu(); activity.invalidateOptionsMenu();
} }
private void renderPage(final int zoom) { private void renderPage(final int zoom) {
evaluateJavascript("onRenderPage(" + zoom + ")", null); binding.webview.evaluateJavascript("onRenderPage(" + zoom + ")", null);
} }
private void documentOrientationChanged(final int orientationDegreesOffset) { private void documentOrientationChanged(final int orientationDegreesOffset) {

View File

@ -6,14 +6,15 @@ import android.os.Bundle;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.grapheneos.pdfviewer.R;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.grapheneos.pdfviewer.R;
public class DocumentPropertiesFragment extends DialogFragment { public class DocumentPropertiesFragment extends DialogFragment {
public static final String TAG = "DocumentPropertiesFragment"; public static final String TAG = "DocumentPropertiesFragment";
@ -44,7 +45,7 @@ public class DocumentPropertiesFragment extends DialogFragment {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = requireActivity(); final Activity activity = requireActivity();
final AlertDialog.Builder dialog = new AlertDialog.Builder(activity) final MaterialAlertDialogBuilder dialog = new MaterialAlertDialogBuilder(activity)
.setPositiveButton(android.R.string.ok, null); .setPositiveButton(android.R.string.ok, null);
if (mDocumentProperties != null) { if (mDocumentProperties != null) {

View File

@ -7,9 +7,10 @@ import android.widget.FrameLayout;
import android.widget.NumberPicker; import android.widget.NumberPicker;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.grapheneos.pdfviewer.PdfViewer; import org.grapheneos.pdfviewer.PdfViewer;
public class JumpToPageFragment extends DialogFragment { public class JumpToPageFragment extends DialogFragment {
@ -42,7 +43,7 @@ public class JumpToPageFragment extends DialogFragment {
FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER)); Gravity.CENTER));
return new AlertDialog.Builder(requireActivity()) return new MaterialAlertDialogBuilder(requireActivity())
.setView(layout) .setView(layout)
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
mPicker.clearFocus(); mPicker.clearFocus();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 B

View File

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M18.41,16.59L13.82,12l4.59,-4.59L17,6l-6,6 6,6zM6,6h2v12H6z"/>
</vector>

View File

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M5.59,7.41L10.18,12l-4.59,4.59L7,18l6,-6 -6,-6zM16,6h2v12h-2z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M12,7c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM13,17h-2v-2h2v2z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M17.7,15.89L13.82,12l3.89,-3.89c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0l-4.59,4.59c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.38,-0.38 0.38,-1.02 -0.01,-1.4zM7,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.83,-4.83c-0.37,-0.38 -0.88,-0.59 -1.41,-0.59L6,2zM13,8L13,3.5L18.5,9L14,9c-0.55,0 -1,-0.45 -1,-1z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M6.29,8.11L10.18,12l-3.89,3.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L7.7,6.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.38,0.39 -0.38,1.03 0,1.41zM17,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V7c0,-0.55 0.45,-1 1,-1z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M14.91,6.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.91,11.3c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L11.03,12l3.88,-3.88c0.38,-0.39 0.38,-1.03 0,-1.41z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M9.31,6.71c-0.39,0.39 -0.39,1.02 0,1.41L13.19,12l-3.88,3.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L10.72,6.7c-0.38,-0.38 -1.02,-0.38 -1.41,0.01z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M11.5,9C10.12,9 9,10.12 9,11.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5S12.88,9 11.5,9zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM16.08,17.5l-2.2,-2.2c-0.9,0.58 -2.03,0.84 -3.22,0.62 -1.88,-0.35 -3.38,-1.93 -3.62,-3.83 -0.38,-3.01 2.18,-5.52 5.21,-5.04 1.88,0.3 3.39,1.84 3.7,3.71 0.19,1.16 -0.08,2.23 -0.64,3.12l2.2,2.19c0.39,0.39 0.39,1.03 0,1.42 -0.4,0.4 -1.04,0.4 -1.43,0.01z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M6.56,7.98C6.1,7.52 5.31,7.6 5,8.17c-0.28,0.51 -0.5,1.03 -0.67,1.58 -0.19,0.63 0.31,1.25 0.96,1.25h0.01c0.43,0 0.82,-0.28 0.94,-0.7 0.12,-0.4 0.28,-0.79 0.48,-1.17 0.22,-0.37 0.15,-0.84 -0.16,-1.15zM5.31,13h-0.02c-0.65,0 -1.15,0.62 -0.96,1.25 0.16,0.54 0.38,1.07 0.66,1.58 0.31,0.57 1.11,0.66 1.57,0.2 0.3,-0.31 0.38,-0.77 0.17,-1.15 -0.2,-0.37 -0.36,-0.76 -0.48,-1.16 -0.12,-0.44 -0.51,-0.72 -0.94,-0.72zM8.16,19.02c0.51,0.28 1.04,0.5 1.59,0.66 0.62,0.18 1.24,-0.32 1.24,-0.96v-0.03c0,-0.43 -0.28,-0.82 -0.7,-0.94 -0.4,-0.12 -0.78,-0.28 -1.15,-0.48 -0.38,-0.21 -0.86,-0.14 -1.16,0.17l-0.03,0.03c-0.45,0.45 -0.36,1.24 0.21,1.55zM13,4.07v-0.66c0,-0.89 -1.08,-1.34 -1.71,-0.71L9.17,4.83c-0.4,0.4 -0.4,1.04 0,1.43l2.13,2.08c0.63,0.62 1.7,0.17 1.7,-0.72L13,6.09c2.84,0.48 5,2.94 5,5.91 0,2.73 -1.82,5.02 -4.32,5.75 -0.41,0.12 -0.68,0.51 -0.68,0.94v0.02c0,0.65 0.61,1.14 1.23,0.96C17.57,18.71 20,15.64 20,12c0,-4.08 -3.05,-7.44 -7,-7.93z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M14.83,4.83L12.7,2.7c-0.62,-0.62 -1.7,-0.18 -1.7,0.71v0.66C7.06,4.56 4,7.92 4,12c0,3.64 2.43,6.71 5.77,7.68 0.62,0.18 1.23,-0.32 1.23,-0.96v-0.03c0,-0.43 -0.27,-0.82 -0.68,-0.94C7.82,17.03 6,14.73 6,12c0,-2.97 2.16,-5.43 5,-5.91v1.53c0,0.89 1.07,1.33 1.7,0.71l2.13,-2.08c0.4,-0.38 0.4,-1.02 0,-1.42zM19.67,9.76c-0.16,-0.55 -0.38,-1.08 -0.66,-1.59 -0.31,-0.57 -1.1,-0.66 -1.56,-0.2l-0.01,0.01c-0.31,0.31 -0.38,0.78 -0.17,1.16 0.2,0.37 0.36,0.76 0.48,1.16 0.12,0.42 0.51,0.7 0.94,0.7h0.02c0.65,0 1.15,-0.62 0.96,-1.24zM13,18.68v0.02c0,0.65 0.62,1.14 1.24,0.96 0.55,-0.16 1.08,-0.38 1.59,-0.66 0.57,-0.31 0.66,-1.1 0.2,-1.56l-0.02,-0.02c-0.31,-0.31 -0.78,-0.38 -1.16,-0.17 -0.37,0.21 -0.76,0.37 -1.16,0.49 -0.41,0.12 -0.69,0.51 -0.69,0.94zM17.44,16.03c0.46,0.46 1.25,0.37 1.56,-0.2 0.28,-0.51 0.5,-1.04 0.67,-1.59 0.18,-0.62 -0.31,-1.24 -0.96,-1.24h-0.02c-0.44,0 -0.82,0.28 -0.94,0.7 -0.12,0.4 -0.28,0.79 -0.48,1.17 -0.21,0.38 -0.13,0.86 0.17,1.16z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.78,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.26,4.25c0.41,0.41 1.07,0.41 1.48,0l0.01,-0.01c0.41,-0.41 0.41,-1.07 0,-1.48L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM9.5,7c-0.28,0 -0.5,0.22 -0.5,0.5L9,9L7.5,9c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5L9,10v1.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5L10,10h1.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5L10,9L10,7.5c0,-0.28 -0.22,-0.5 -0.5,-0.5z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.26,4.25c0.41,0.41 1.07,0.41 1.48,0l0.01,-0.01c0.41,-0.41 0.41,-1.07 0,-1.48L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM7.5,9h4c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5h-4c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5z" />
</vector>

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<ScrollView
android:id="@+id/webview_out_of_date_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:visibility="gone"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/error_image_view"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginTop="32dp"
android:importantForAccessibility="no"
android:src="@drawable/ic_error_outline_24dp"
app:layout_constraintBottom_toTopOf="@id/webview_out_of_date_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:tint="?attr/colorPrimary" />
<TextView
android:id="@+id/webview_out_of_date_title"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:elegantTextHeight="true"
android:gravity="center"
android:text="@string/webview_out_of_date_title"
app:layout_constraintBottom_toTopOf="@id/webview_out_of_date_message"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_image_view" />
<TextView
android:id="@+id/webview_out_of_date_message"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
android:elegantTextHeight="true"
android:gravity="center"
android:lineSpacingMultiplier="1.2"
android:text="@string/webview_out_of_date_message"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/webview_out_of_date_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -9,55 +9,55 @@
<item <item
android:id="@+id/action_previous" android:id="@+id/action_previous"
android:icon="@drawable/ic_navigate_before_white_24dp" android:icon="@drawable/ic_navigate_before_24dp"
android:title="@string/action_previous" android:title="@string/action_previous"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_next" android:id="@+id/action_next"
android:icon="@drawable/ic_navigate_next_white_24dp" android:icon="@drawable/ic_navigate_next_24dp"
android:title="@string/action_next" android:title="@string/action_next"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_zoom_out" android:id="@+id/action_zoom_out"
android:icon="@drawable/ic_zoom_out_white_24dp" android:icon="@drawable/ic_zoom_out_24dp"
android:title="@string/action_zoom_out" android:title="@string/action_zoom_out"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_zoom_in" android:id="@+id/action_zoom_in"
android:icon="@drawable/ic_zoom_in_white_24dp" android:icon="@drawable/ic_zoom_in_24dp"
android:title="@string/action_zoom_in" android:title="@string/action_zoom_in"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_first" android:id="@+id/action_first"
android:icon="@drawable/baseline_first_page_24" android:icon="@drawable/ic_first_page_24dp"
android:title="@string/action_first" android:title="@string/action_first"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_last" android:id="@+id/action_last"
android:icon="@drawable/baseline_last_page_24" android:icon="@drawable/ic_last_page_24dp"
android:title="@string/action_last" android:title="@string/action_last"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_jump_to_page" android:id="@+id/action_jump_to_page"
android:icon="@drawable/ic_pageview_white_24dp" android:icon="@drawable/ic_pageview_24dp"
android:title="@string/action_jump_to_page" android:title="@string/action_jump_to_page"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_rotate_clockwise" android:id="@+id/action_rotate_clockwise"
android:icon="@drawable/ic_rotate_right_white_24dp" android:icon="@drawable/ic_rotate_right_24dp"
android:title="@string/action_rotate_clockwise" android:title="@string/action_rotate_clockwise"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_rotate_counterclockwise" android:id="@+id/action_rotate_counterclockwise"
android:icon="@drawable/ic_rotate_left_white_24dp" android:icon="@drawable/ic_rotate_left_24dp"
android:title="@string/action_rotate_counterclockwise" android:title="@string/action_rotate_counterclockwise"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />

View File

@ -19,4 +19,7 @@
<string name="invalid_mime_type">Cannot open file with invalid MIME type</string> <string name="invalid_mime_type">Cannot open file with invalid MIME type</string>
<string name="legacy_file_uri">Cannot open legacy file paths from insecure apps</string> <string name="legacy_file_uri">Cannot open legacy file paths from insecure apps</string>
<string name="io_error">Received I/O error trying to open content</string> <string name="io_error">Received I/O error trying to open content</string>
<string name="webview_out_of_date_title">WebView out-of-date</string>
<string name="webview_out_of_date_message">Your current WebView version is %d. The WebView should be at least version %d for the PDF Viewer to work.</string>
</resources> </resources>

View File

@ -4,7 +4,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:7.1.1") classpath("com.android.tools.build:gradle:7.1.2")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
} }
} }