libpdfviewer: update to PdfViewer 12
@ -22,6 +22,13 @@ android {
|
||||
keyAlias = keystoreProperties["keyAlias"] 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 {
|
||||
viewBinding = true
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.grapheneos.pdfviewer"
|
||||
android:targetSandboxVersion="2">
|
||||
<original-package android:name="org.grapheneos.pdfviewer" />
|
||||
|
||||
<application>
|
||||
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
|
||||
android:value="true" />
|
||||
|
@ -1,11 +1,11 @@
|
||||
body, canvas, #padding {
|
||||
body, canvas {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#padding {
|
||||
min-width: 100%;
|
||||
background: black;
|
||||
canvas {
|
||||
margin: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.textLayer {
|
||||
|
@ -7,7 +7,6 @@
|
||||
<script src="pdf.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="padding"></div>
|
||||
<canvas id="content"></canvas>
|
||||
<div id="text" class="textLayer"></div>
|
||||
<script src="viewer.js"></script>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "/pdf.worker.js";
|
||||
|
||||
const padding = document.getElementById("padding");
|
||||
let pdfDoc = null;
|
||||
let pageRendering = false;
|
||||
let renderPending = false;
|
||||
@ -56,7 +55,6 @@ function display(newCanvas, zoom) {
|
||||
canvas.width = newCanvas.width;
|
||||
canvas.style.height = newCanvas.style.height;
|
||||
canvas.style.width = newCanvas.style.width;
|
||||
padding.style.width = canvas.style.width;
|
||||
canvas.getContext("2d", { alpha: false }).drawImage(newCanvas, 0, 0);
|
||||
if (!zoom) {
|
||||
scrollTo(0, 0);
|
||||
@ -200,14 +198,6 @@ function isTextSelected() {
|
||||
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) {
|
||||
pdfDoc = newDoc;
|
||||
channel.setNumPages(pdfDoc.numPages);
|
||||
|
@ -1,16 +1,18 @@
|
||||
package org.grapheneos.pdfviewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebResourceRequest;
|
||||
@ -22,11 +24,12 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import org.grapheneos.pdfviewer.databinding.PdfviewerBinding;
|
||||
import org.grapheneos.pdfviewer.fragment.DocumentPropertiesFragment;
|
||||
import org.grapheneos.pdfviewer.fragment.JumpToPageFragment;
|
||||
import org.grapheneos.pdfviewer.loader.DocumentPropertiesLoader;
|
||||
@ -36,10 +39,11 @@ import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
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";
|
||||
|
||||
private static final String KEY_PROPERTIES = "properties";
|
||||
private static final int MIN_WEBVIEW_RELEASE = 89;
|
||||
|
||||
private static final String CONTENT_SECURITY_POLICY =
|
||||
"default-src 'none'; " +
|
||||
@ -93,31 +97,64 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
|
||||
private float mZoomRatio = 1f;
|
||||
private int mDocumentOrientationDegrees;
|
||||
private int mDocumentState;
|
||||
private int windowInsetTop;
|
||||
private List<CharSequence> mDocumentProperties;
|
||||
private InputStream mInputStream;
|
||||
|
||||
private PdfviewerBinding binding;
|
||||
private TextView mTextView;
|
||||
private Toast mToast;
|
||||
|
||||
public AppCompatActivity activity;
|
||||
AppCompatActivity activity;
|
||||
String fileName;
|
||||
Long fileSize;
|
||||
|
||||
void init(Context context) {
|
||||
setBackgroundColor(Color.TRANSPARENT);
|
||||
private class Channel {
|
||||
@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) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
}
|
||||
|
||||
setOnApplyWindowInsetsListener((view, insets) -> {
|
||||
windowInsetTop = insets.getSystemWindowInsetTop();
|
||||
evaluateJavascript("updateInset()", null);
|
||||
return insets;
|
||||
});
|
||||
|
||||
final WebSettings settings = getSettings();
|
||||
final WebSettings settings = binding.webview.getSettings();
|
||||
settings.setAllowContentAccess(false);
|
||||
settings.setAllowFileAccess(false);
|
||||
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
@ -125,12 +162,12 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
|
||||
|
||||
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) {
|
||||
try {
|
||||
InputStream inputStream = context.getAssets().open(path.substring(1));
|
||||
InputStream inputStream = activity.getAssets().open(path.substring(1));
|
||||
return new WebResourceResponse(mime, null, inputStream);
|
||||
} catch (IOException e) {
|
||||
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() {
|
||||
@Override
|
||||
public void onZoomIn(float value) {
|
||||
@ -206,70 +243,38 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
|
||||
}
|
||||
});
|
||||
|
||||
mTextView = new TextView(context);
|
||||
mTextView = new TextView(activity);
|
||||
mTextView.setBackgroundColor(Color.DKGRAY);
|
||||
mTextView.setTextColor(ColorStateList.valueOf(Color.WHITE));
|
||||
mTextView.setTextSize(18);
|
||||
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) {
|
||||
MenuInflater inflater = activity.getMenuInflater();
|
||||
inflater.inflate(R.menu.pdf_viewer, menu);
|
||||
}
|
||||
|
||||
private class Channel {
|
||||
@JavascriptInterface
|
||||
public int getWindowInsetTop() {
|
||||
return windowInsetTop;
|
||||
public void onResume() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// The user could have left the activity to update the WebView
|
||||
activity.invalidateOptionsMenu();
|
||||
if (getWebViewRelease() >= MIN_WEBVIEW_RELEASE) {
|
||||
binding.webviewOutOfDateLayout.setVisibility(View.GONE);
|
||||
binding.webview.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
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 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));
|
||||
}
|
||||
@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
|
||||
@ -295,12 +300,12 @@ public class PdfViewer extends WebView implements LoaderManager.LoaderCallbacks<
|
||||
mInputStream = inputStream;
|
||||
this.fileName = fileName;
|
||||
this.fileSize = fileSize;
|
||||
loadUrl("https://localhost/viewer.html");
|
||||
binding.webview.loadUrl("https://localhost/viewer.html");
|
||||
activity.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private void renderPage(final int zoom) {
|
||||
evaluateJavascript("onRenderPage(" + zoom + ")", null);
|
||||
binding.webview.evaluateJavascript("onRenderPage(" + zoom + ")", null);
|
||||
}
|
||||
|
||||
private void documentOrientationChanged(final int orientationDegreesOffset) {
|
||||
|
@ -6,14 +6,15 @@ import android.os.Bundle;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.grapheneos.pdfviewer.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.grapheneos.pdfviewer.R;
|
||||
|
||||
public class DocumentPropertiesFragment extends DialogFragment {
|
||||
public static final String TAG = "DocumentPropertiesFragment";
|
||||
|
||||
@ -44,7 +45,7 @@ public class DocumentPropertiesFragment extends DialogFragment {
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Activity activity = requireActivity();
|
||||
final AlertDialog.Builder dialog = new AlertDialog.Builder(activity)
|
||||
final MaterialAlertDialogBuilder dialog = new MaterialAlertDialogBuilder(activity)
|
||||
.setPositiveButton(android.R.string.ok, null);
|
||||
|
||||
if (mDocumentProperties != null) {
|
||||
|
@ -7,9 +7,10 @@ import android.widget.FrameLayout;
|
||||
import android.widget.NumberPicker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.grapheneos.pdfviewer.PdfViewer;
|
||||
|
||||
public class JumpToPageFragment extends DialogFragment {
|
||||
@ -42,7 +43,7 @@ public class JumpToPageFragment extends DialogFragment {
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
Gravity.CENTER));
|
||||
|
||||
return new AlertDialog.Builder(requireActivity())
|
||||
return new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setView(layout)
|
||||
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
|
||||
mPicker.clearFocus();
|
||||
|
Before Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 133 B |
Before Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 433 B |
Before Width: | Height: | Size: 427 B |
Before Width: | Height: | Size: 422 B |
Before Width: | Height: | Size: 412 B |
Before Width: | Height: | Size: 116 B |
Before Width: | Height: | Size: 113 B |
Before Width: | Height: | Size: 226 B |
Before Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 272 B |
Before Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 249 B |
Before Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 536 B |
Before Width: | Height: | Size: 535 B |
Before Width: | Height: | Size: 486 B |
Before Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 601 B |
Before Width: | Height: | Size: 798 B |
Before Width: | Height: | Size: 787 B |
Before Width: | Height: | Size: 737 B |
Before Width: | Height: | Size: 731 B |
Before Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 770 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 954 B |
Before Width: | Height: | Size: 925 B |
@ -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>
|
@ -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>
|
9
app/src/main/res/drawable/ic_error_outline_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_first_page_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_insert_drive_file_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_last_page_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_navigate_before_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_navigate_next_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_pageview_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_rotate_left_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_rotate_right_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_zoom_in_24dp.xml
Normal 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>
|
9
app/src/main/res/drawable/ic_zoom_out_24dp.xml
Normal 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>
|
78
app/src/main/res/layout/pdfviewer.xml
Normal 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>
|
@ -9,55 +9,55 @@
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_first"
|
||||
android:icon="@drawable/baseline_first_page_24"
|
||||
android:icon="@drawable/ic_first_page_24dp"
|
||||
android:title="@string/action_first"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_last"
|
||||
android:icon="@drawable/baseline_last_page_24"
|
||||
android:icon="@drawable/ic_last_page_24dp"
|
||||
android:title="@string/action_last"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
|
@ -19,4 +19,7 @@
|
||||
<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="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>
|
||||
|
@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
|