Skip to content

Commit 2bd1b17

Browse files
[Application] Implement functionality to share and save converted document
1 parent 0a93677 commit 2bd1b17

6 files changed

Lines changed: 192 additions & 2 deletions

File tree

application/app/src/main/java/com/viliussutkus89/android/pdf2htmlex/application/HTMLReaderActivity.java

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
package com.viliussutkus89.android.pdf2htmlex.application;
22

33
import android.annotation.SuppressLint;
4+
import android.content.ActivityNotFoundException;
5+
import android.content.Intent;
46
import android.net.Uri;
7+
import android.os.Build;
58
import android.os.Bundle;
9+
import android.view.Menu;
10+
import android.view.MenuItem;
611
import android.webkit.WebSettings;
712
import android.webkit.WebView;
13+
import android.widget.Toast;
814

15+
import androidx.activity.result.ActivityResultLauncher;
16+
import androidx.activity.result.contract.ActivityResultContracts;
917
import androidx.annotation.NonNull;
1018
import androidx.appcompat.app.ActionBar;
1119
import androidx.appcompat.app.AppCompatActivity;
1220
import androidx.appcompat.widget.Toolbar;
21+
import androidx.work.Data;
22+
import androidx.work.OneTimeWorkRequest;
23+
import androidx.work.WorkManager;
24+
import androidx.work.WorkRequest;
1325

1426
public class HTMLReaderActivity extends AppCompatActivity {
1527
static final String INTENT_EXTRA_INPUT__FILENAME = "input.filename.pdf";
1628
private static final String BUNDLE_KEY__WEB_VIEW = "m_webView.state";
1729

1830
private WebView m_webView = null;
1931

32+
private ActivityResultLauncher<String> m_saveDocument;
33+
2034
@SuppressLint("SetJavaScriptEnabled")
2135
@Override
2236
protected void onCreate(Bundle savedInstanceState) {
@@ -44,12 +58,42 @@ protected void onCreate(Bundle savedInstanceState) {
4458
ws.setAllowFileAccess(false);
4559
ws.setBlockNetworkLoads(true);
4660

61+
final Uri convertedDocument = getIntent().getData();
4762
try {
4863
Bundle wvBundle = savedInstanceState.getBundle(BUNDLE_KEY__WEB_VIEW);
4964
m_webView.restoreState(wvBundle);
5065
} catch (NullPointerException ignored) {
51-
Uri convertedResult = getIntent().getData();
52-
m_webView.loadUrl(convertedResult.toString());
66+
m_webView.loadUrl(convertedDocument.toString());
67+
}
68+
69+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
70+
m_saveDocument = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
71+
selectedOutputDocument -> {
72+
if (null == selectedOutputDocument) {
73+
return;
74+
}
75+
WorkRequest saveWork = new OneTimeWorkRequest.Builder(SaveWorker.class)
76+
.setInputData(new Data.Builder()
77+
.putString(SaveWorker.INPUT__INPUT_URI, convertedDocument.toString())
78+
.putString(SaveWorker.INPUT__OUTPUT_URI, selectedOutputDocument.toString())
79+
.build())
80+
.build();
81+
WorkManager workManager = WorkManager.getInstance(getApplicationContext());
82+
workManager.enqueue(saveWork);
83+
workManager.getWorkInfoByIdLiveData(saveWork.getId()).observe(this, workInfo -> {
84+
if (null == workInfo) {
85+
return;
86+
}
87+
switch (workInfo.getState()) {
88+
case SUCCEEDED:
89+
Toast.makeText(getApplicationContext(), R.string.save_successful, Toast.LENGTH_LONG).show();
90+
break;
91+
case FAILED:
92+
Toast.makeText(getApplicationContext(), R.string.error_save_failed, Toast.LENGTH_LONG).show();
93+
break;
94+
}
95+
});
96+
});
5397
}
5498
}
5599

@@ -61,4 +105,37 @@ protected void onSaveInstanceState(@NonNull Bundle outState) {
61105
m_webView.saveState(wwBundle);
62106
outState.putBundle(BUNDLE_KEY__WEB_VIEW, wwBundle);
63107
}
108+
109+
@Override
110+
public boolean onCreateOptionsMenu(Menu menu) {
111+
getMenuInflater().inflate(R.menu.html_reader_menu, menu);
112+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
113+
menu.findItem(R.id.action_save).setEnabled(false);
114+
}
115+
return super.onCreateOptionsMenu(menu);
116+
}
117+
118+
@Override
119+
public boolean onOptionsItemSelected(MenuItem item) {
120+
if (R.id.action_share == item.getItemId()) {
121+
Intent shareIntent = new Intent(Intent.ACTION_SEND);
122+
shareIntent.setType("text/html");
123+
shareIntent.putExtra(Intent.EXTRA_STREAM, getIntent().getData());
124+
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
125+
try {
126+
startActivity(shareIntent);
127+
} catch (ActivityNotFoundException e) {
128+
Toast.makeText(this, R.string.error_share_failed, Toast.LENGTH_LONG).show();
129+
}
130+
return true;
131+
}
132+
133+
if (R.id.action_save == item.getItemId()) {
134+
String filename = GetFileName.FromUri(getContentResolver(), getIntent().getData());
135+
m_saveDocument.launch(filename);
136+
return true;
137+
}
138+
139+
return super.onOptionsItemSelected(item);
140+
}
64141
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* SaveWorker.java
3+
*
4+
* Copyright (C) 2021 Vilius Sutkus'89
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package com.viliussutkus89.android.pdf2htmlex.application;
21+
22+
import android.content.ContentResolver;
23+
import android.content.Context;
24+
import android.net.Uri;
25+
26+
import androidx.annotation.NonNull;
27+
import androidx.work.Worker;
28+
import androidx.work.WorkerParameters;
29+
30+
import java.io.IOException;
31+
import java.io.InputStream;
32+
import java.io.OutputStream;
33+
34+
public class SaveWorker extends Worker {
35+
static final String INPUT__INPUT_URI = "input__input_uri";
36+
static final String INPUT__OUTPUT_URI = "input__output_uri";
37+
38+
public SaveWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
39+
super(context, workerParams);
40+
}
41+
42+
@NonNull
43+
@Override
44+
public Result doWork() {
45+
final Uri inputUri = Uri.parse(getInputData().getString(INPUT__INPUT_URI));
46+
final Uri outputUri = Uri.parse(getInputData().getString(INPUT__OUTPUT_URI));
47+
if (null == inputUri || null == outputUri) {
48+
return Result.failure();
49+
}
50+
51+
ContentResolver contentResolver = getApplicationContext().getContentResolver();
52+
53+
try (InputStream inputStream = contentResolver.openInputStream(inputUri)) {
54+
try (OutputStream outputStream = contentResolver.openOutputStream(outputUri)) {
55+
final int readBufferSize = 2048;
56+
final byte[] buffer = new byte[readBufferSize];
57+
58+
int didRead;
59+
while (-1 != (didRead = inputStream.read(buffer, 0, readBufferSize))) {
60+
outputStream.write(buffer, 0, didRead);
61+
}
62+
}
63+
} catch (IOException e) {
64+
return Result.failure();
65+
}
66+
67+
return Result.success();
68+
}
69+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
10+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
10+
</vector>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<menu
2+
xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
4+
5+
<item
6+
android:id="@+id/action_share"
7+
android:icon="@drawable/ic_baseline_share_24"
8+
android:title="@string/action_share"
9+
app:showAsAction="ifRoom" />
10+
11+
<item
12+
android:id="@+id/action_save"
13+
android:icon="@drawable/ic_baseline_save_24"
14+
android:title="@string/action_save"
15+
app:showAsAction="ifRoom" />
16+
17+
</menu>

application/app/src/main/res/values/strings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,11 @@
1616
<string name="conversion_status_output">Loading HTML file …</string>
1717

1818
<string name="button_cancel">Cancel</string>
19+
20+
<string name="action_share">Share HTML document</string>
21+
<string name="action_save">Save HTML document</string>
22+
23+
<string name="error_share_failed">Failed to share HTML document!</string>
24+
<string name="error_save_failed">Failed to save HTML document!</string>
25+
<string name="save_successful">HTML document saved.</string>
1926
</resources>

0 commit comments

Comments
 (0)