rewrite DocumentPropertiesLoader in kotlin
This commit is contained in:
parent
61607858ef
commit
17c7c84296
@ -45,7 +45,7 @@ import app.grapheneos.pdfviewer.fragment.DocumentPropertiesFragment;
|
||||
import app.grapheneos.pdfviewer.fragment.PasswordPromptFragment;
|
||||
import app.grapheneos.pdfviewer.fragment.JumpToPageFragment;
|
||||
import app.grapheneos.pdfviewer.ktx.ViewKt;
|
||||
import app.grapheneos.pdfviewer.loader.DocumentPropertiesLoader;
|
||||
import app.grapheneos.pdfviewer.loader.DocumentPropertiesAsyncTaskLoader;
|
||||
import app.grapheneos.pdfviewer.viewModel.PasswordStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -191,7 +191,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
||||
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(KEY_PROPERTIES, properties);
|
||||
runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this).restartLoader(DocumentPropertiesLoader.ID, args, PdfViewer.this));
|
||||
runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this).restartLoader(DocumentPropertiesAsyncTaskLoader.ID, args, PdfViewer.this));
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -476,14 +476,14 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
||||
@NonNull
|
||||
@Override
|
||||
public Loader<List<CharSequence>> onCreateLoader(int id, Bundle args) {
|
||||
return new DocumentPropertiesLoader(this, args.getString(KEY_PROPERTIES), mNumPages, mUri);
|
||||
return new DocumentPropertiesAsyncTaskLoader(this, args.getString(KEY_PROPERTIES), mNumPages, mUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull Loader<List<CharSequence>> loader, List<CharSequence> data) {
|
||||
mDocumentProperties = data;
|
||||
setToolbarTitleWithDocumentName();
|
||||
LoaderManager.getInstance(this).destroyLoader(DocumentPropertiesLoader.ID);
|
||||
LoaderManager.getInstance(this).destroyLoader(DocumentPropertiesAsyncTaskLoader.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,48 @@
|
||||
package app.grapheneos.pdfviewer.loader;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DocumentPropertiesAsyncTaskLoader extends AsyncTaskLoader<List<CharSequence>> {
|
||||
|
||||
public static final String TAG = "DocumentPropertiesLoader";
|
||||
|
||||
public static final int ID = 1;
|
||||
|
||||
private final String mProperties;
|
||||
private final int mNumPages;
|
||||
private final Uri mUri;
|
||||
|
||||
public DocumentPropertiesAsyncTaskLoader(Context context, String properties, int numPages, Uri uri) {
|
||||
super(context);
|
||||
|
||||
mProperties = properties;
|
||||
mNumPages = numPages;
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<CharSequence> loadInBackground() {
|
||||
|
||||
DocumentPropertiesLoader loader = new DocumentPropertiesLoader(
|
||||
getContext(),
|
||||
mProperties,
|
||||
mNumPages,
|
||||
mUri
|
||||
);
|
||||
|
||||
return loader.loadAsList();
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
package app.grapheneos.pdfviewer.loader;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import app.grapheneos.pdfviewer.R;
|
||||
import app.grapheneos.pdfviewer.Utils;
|
||||
|
||||
public class DocumentPropertiesLoader extends AsyncTaskLoader<List<CharSequence>> {
|
||||
public static final String TAG = "DocumentPropertiesLoader";
|
||||
|
||||
public static final int ID = 1;
|
||||
|
||||
private final String mProperties;
|
||||
private final int mNumPages;
|
||||
private final Uri mUri;
|
||||
|
||||
private Cursor mCursor;
|
||||
|
||||
public DocumentPropertiesLoader(Context context, String properties, int numPages, Uri uri) {
|
||||
super(context);
|
||||
|
||||
mProperties = properties;
|
||||
mNumPages = numPages;
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CharSequence> loadInBackground() {
|
||||
final Context context = getContext();
|
||||
|
||||
final String[] names = context.getResources().getStringArray(R.array.property_names);
|
||||
final List<CharSequence> properties = new ArrayList<>(names.length);
|
||||
|
||||
mCursor = context.getContentResolver().query(mUri, null, null, null, null);
|
||||
if (mCursor != null) {
|
||||
mCursor.moveToFirst();
|
||||
|
||||
final int indexName = mCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
if (indexName >= 0) {
|
||||
properties.add(getProperty(null, names[0], mCursor.getString(indexName)));
|
||||
}
|
||||
|
||||
final int indexSize = mCursor.getColumnIndex(OpenableColumns.SIZE);
|
||||
if (indexSize >= 0) {
|
||||
final long fileSize = Long.parseLong(mCursor.getString(indexSize));
|
||||
properties.add(getProperty(null, names[1], Utils.parseFileSize(fileSize)));
|
||||
}
|
||||
|
||||
mCursor.close();
|
||||
}
|
||||
|
||||
try {
|
||||
final JSONObject json = new JSONObject(mProperties);
|
||||
|
||||
properties.add(getProperty(json, names[2], "Title"));
|
||||
properties.add(getProperty(json, names[3], "Author"));
|
||||
properties.add(getProperty(json, names[4], "Subject"));
|
||||
properties.add(getProperty(json, names[5], "Keywords"));
|
||||
properties.add(getProperty(json, names[6], "CreationDate"));
|
||||
properties.add(getProperty(json, names[7], "ModDate"));
|
||||
properties.add(getProperty(json, names[8], "Producer"));
|
||||
properties.add(getProperty(json, names[9], "Creator"));
|
||||
properties.add(getProperty(json, names[10], "PDFFormatVersion"));
|
||||
properties.add(getProperty(null, names[11], String.valueOf(mNumPages)));
|
||||
|
||||
return properties;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(List<CharSequence> properties) {
|
||||
if (isReset()) {
|
||||
onReleaseResources();
|
||||
} else if (isStarted()) {
|
||||
super.deliverResult(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopLoading() {
|
||||
cancelLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled(List<CharSequence> properties) {
|
||||
super.onCanceled(properties);
|
||||
|
||||
onReleaseResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
super.onReset();
|
||||
|
||||
onStopLoading();
|
||||
onReleaseResources();
|
||||
}
|
||||
|
||||
private void onReleaseResources() {
|
||||
if (mCursor != null) {
|
||||
mCursor.close();
|
||||
mCursor = null;
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence getProperty(final JSONObject json, String name, String specName) {
|
||||
final SpannableStringBuilder property = new SpannableStringBuilder(name).append(":\n");
|
||||
final String value = json != null ? json.optString(specName, "-") : specName;
|
||||
|
||||
if (specName != null && specName.endsWith("Date")) {
|
||||
final Context context = getContext();
|
||||
try {
|
||||
property.append(value.equals("-") ? value : Utils.parseDate(value));
|
||||
} catch (ParseException e) {
|
||||
Log.w(TAG, e.getMessage() + " for " + value + " at offset: " + e.getErrorOffset());
|
||||
property.append(context.getString(R.string.document_properties_invalid_date));
|
||||
}
|
||||
} else {
|
||||
property.append(value);
|
||||
}
|
||||
property.setSpan(new StyleSpan(Typeface.BOLD), 0, name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return property;
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package app.grapheneos.pdfviewer.loader
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.Log
|
||||
import app.grapheneos.pdfviewer.R
|
||||
import app.grapheneos.pdfviewer.Utils
|
||||
import org.json.JSONException
|
||||
|
||||
class DocumentPropertiesLoader(
|
||||
private val context: Context,
|
||||
private val properties: String,
|
||||
private val numPages: Int,
|
||||
private val mUri: Uri
|
||||
) {
|
||||
|
||||
fun loadAsList(): List<CharSequence> {
|
||||
return load().map { item ->
|
||||
val name = context.getString(item.key.nameResource)
|
||||
val value = item.value
|
||||
|
||||
SpannableStringBuilder()
|
||||
.append(name)
|
||||
.append(":\n")
|
||||
.append(value)
|
||||
.apply {
|
||||
setSpan(
|
||||
StyleSpan(Typeface.BOLD),
|
||||
0,
|
||||
name.length,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun load(): Map<DocumentProperty, String> {
|
||||
val result = mutableMapOf<DocumentProperty, String>()
|
||||
result.addFileProperties()
|
||||
result.addPageSizeProperty()
|
||||
result.addPDFJsProperties()
|
||||
return result
|
||||
}
|
||||
|
||||
private fun MutableMap<DocumentProperty, String>.addPageSizeProperty() {
|
||||
this[DocumentProperty.Pages] = java.lang.String.valueOf(numPages)
|
||||
}
|
||||
|
||||
private fun MutableMap<DocumentProperty, String>.addFileProperties() {
|
||||
putAll(getFileProperties())
|
||||
}
|
||||
|
||||
private fun MutableMap<DocumentProperty, String>.addPDFJsProperties() {
|
||||
putAll(getPDFJsProperties())
|
||||
}
|
||||
|
||||
private fun getPDFJsProperties(): Map<DocumentProperty, String> {
|
||||
return try {
|
||||
PDFJsPropertiesToDocumentPropertyConverter(
|
||||
properties,
|
||||
context.getString(R.string.document_properties_invalid_date),
|
||||
parseExceptionListener = { parseException, value ->
|
||||
Log.w(
|
||||
DocumentPropertiesAsyncTaskLoader.TAG,
|
||||
"${parseException.message} for $value at offset: ${parseException.errorOffset}"
|
||||
)
|
||||
}
|
||||
).convert()
|
||||
} catch (e: JSONException) {
|
||||
Log.w(
|
||||
DocumentPropertiesAsyncTaskLoader.TAG,
|
||||
"invalid properties"
|
||||
)
|
||||
emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFileProperties(): Map<DocumentProperty, String> {
|
||||
val collections = mutableMapOf<DocumentProperty, String>()
|
||||
val proj = arrayOf(
|
||||
OpenableColumns.DISPLAY_NAME,
|
||||
OpenableColumns.SIZE
|
||||
)
|
||||
|
||||
context.contentResolver.query(
|
||||
mUri,
|
||||
proj,
|
||||
null,
|
||||
null
|
||||
)?.use { cursor ->
|
||||
cursor.moveToFirst()
|
||||
val indexName: Int = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||
|
||||
if (indexName >= 0) {
|
||||
collections[DocumentProperty.FileName] = cursor.getString(indexName)
|
||||
}
|
||||
|
||||
val indexSize: Int = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||
if (indexSize >= 0) {
|
||||
val fileSize: Long = cursor.getString(indexSize).toLong()
|
||||
collections[DocumentProperty.FileSize] = Utils.parseFileSize(fileSize)
|
||||
}
|
||||
}
|
||||
return collections
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package app.grapheneos.pdfviewer.loader
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import app.grapheneos.pdfviewer.R
|
||||
|
||||
private const val TITLE_KEY = "Title"
|
||||
private const val AUTHOR_KEY = "Author"
|
||||
private const val SUBJECT_KEY = "Subject"
|
||||
private const val KEYWORDS_KEY = "Keywords"
|
||||
private const val CREATION_DATE_KEY = "CreationDate"
|
||||
private const val MODIFY_DATE_KEY = "ModDate"
|
||||
private const val PRODUCER_KEY = "Producer"
|
||||
private const val CREATOR_KEY = "Creator"
|
||||
private const val PDF_VERSION_KEY = "PDFFormatVersion"
|
||||
|
||||
const val DEFAULT_VALUE = "-"
|
||||
|
||||
enum class DocumentProperty(
|
||||
val key: String = "",
|
||||
@StringRes val nameResource: Int,
|
||||
val isDate: Boolean = false
|
||||
) {
|
||||
FileName(key = "", nameResource = R.string.file_name),
|
||||
FileSize(key = "", nameResource = R.string.file_size),
|
||||
Pages(key = "", nameResource = R.string.pages),
|
||||
Title(key = TITLE_KEY, nameResource = R.string.title),
|
||||
Author(key = AUTHOR_KEY, nameResource = R.string.author),
|
||||
Subject(key = SUBJECT_KEY, nameResource = R.string.subject),
|
||||
Keywords(key = KEYWORDS_KEY, nameResource = R.string.keywords),
|
||||
CreationDate(key = CREATION_DATE_KEY, nameResource = R.string.creation_date, isDate = true),
|
||||
ModifyDate(key = MODIFY_DATE_KEY, nameResource = R.string.modify_date, isDate = true),
|
||||
Producer(key = PRODUCER_KEY, nameResource = R.string.producer),
|
||||
Creator(key = CREATOR_KEY, nameResource = R.string.creator),
|
||||
PDFVersion(key = PDF_VERSION_KEY, nameResource = R.string.pdf_version);
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.grapheneos.pdfviewer.loader
|
||||
|
||||
import app.grapheneos.pdfviewer.Utils
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.text.ParseException
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
class PDFJsPropertiesToDocumentPropertyConverter(
|
||||
private val properties: String,
|
||||
private val propertyInvalidDate: String,
|
||||
private val parseExceptionListener: (e: ParseException, value: String) -> Unit
|
||||
) {
|
||||
|
||||
@Throws(JSONException::class)
|
||||
fun convert(): Map<DocumentProperty, String> {
|
||||
val result = mutableMapOf<DocumentProperty, String>()
|
||||
|
||||
val json = JSONObject(properties)
|
||||
addJsonProperties(json, result)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun addJsonProperties(
|
||||
json: JSONObject,
|
||||
collections: MutableMap<DocumentProperty, String>
|
||||
) {
|
||||
for (documentProperty in DocumentProperty.values()) {
|
||||
val key = documentProperty.key
|
||||
if (key.isEmpty()) continue
|
||||
val value = json.optString(key, DEFAULT_VALUE)
|
||||
collections[documentProperty] = prettify(documentProperty, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prettify(property: DocumentProperty, value: String): String {
|
||||
if (value != DEFAULT_VALUE && property.isDate) {
|
||||
return try {
|
||||
Utils.parseDate(value)
|
||||
} catch (parseException: ParseException) {
|
||||
parseExceptionListener.invoke(parseException, value)
|
||||
propertyInvalidDate
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="property_names">
|
||||
<item>File name</item>
|
||||
<item>File size</item>
|
||||
<item>Title</item>
|
||||
<item>Author</item>
|
||||
<item>Subject</item>
|
||||
<item>Keywords</item>
|
||||
<item>Creation date</item>
|
||||
<item>Modify date</item>
|
||||
<item>Producer</item>
|
||||
<item>Creator</item>
|
||||
<item>PDF version</item>
|
||||
<item>Pages</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -31,4 +31,17 @@
|
||||
<string name="password_prompt_description">Enter the password to decrypt this PDF file</string>
|
||||
<string name="open">Open</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
|
||||
<string name="file_name">File name</string>
|
||||
<string name="file_size">File size</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="author">Author</string>
|
||||
<string name="subject">Subject</string>
|
||||
<string name="keywords">Keywords</string>
|
||||
<string name="creation_date">Creation date</string>
|
||||
<string name="modify_date">Modify date</string>
|
||||
<string name="producer">Producer</string>
|
||||
<string name="creator">Creator</string>
|
||||
<string name="pdf_version">PDF version</string>
|
||||
<string name="pages">Pages</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user