Skip to content

Commit 4ebb706

Browse files
committed
add export page (enabled in debug builds only for now)...
fetch and format page byte size properly minor refinements/experimental code
1 parent a2eaf9b commit 4ebb706

File tree

4 files changed

+170
-31
lines changed

4 files changed

+170
-31
lines changed

app/src/main/java/com/nkanaev/comics/activity/ReaderActivity.java

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import androidx.fragment.app.Fragment;
1212
import com.nkanaev.comics.R;
1313
import com.nkanaev.comics.fragment.ReaderFragment;
14+
import androidx.annotation.NonNull;
1415

1516
import java.io.File;
1617

@@ -99,4 +100,11 @@ public void onBackPressed() {
99100
super.onBackPressed();
100101
finish();
101102
}
103+
104+
/*
105+
@Override
106+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
107+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
108+
}
109+
*/
102110
}

app/src/main/java/com/nkanaev/comics/fragment/ReaderFragment.java

+149-31
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
11
package com.nkanaev.comics.fragment;
22

3+
import android.Manifest;
34
import android.content.Context;
45
import android.content.DialogInterface;
56
import android.content.Intent;
67
import android.content.SharedPreferences;
8+
import android.content.pm.PackageManager;
79
import android.content.res.Configuration;
810
import android.graphics.Bitmap;
911
import android.graphics.Rect;
1012
import android.graphics.drawable.BitmapDrawable;
1113
import android.graphics.drawable.Drawable;
1214
import android.net.Uri;
1315
import android.os.Bundle;
16+
import android.os.Environment;
1417
import android.os.Handler;
1518
import android.util.Log;
1619
import android.util.SparseArray;
1720
import android.util.TypedValue;
1821
import android.view.*;
1922
import android.view.animation.Animation;
20-
import android.widget.ImageButton;
21-
import android.widget.ImageView;
22-
import android.widget.SeekBar;
23-
import android.widget.TextView;
23+
import android.widget.*;
24+
import androidx.activity.result.ActivityResultLauncher;
25+
import androidx.activity.result.contract.ActivityResultContracts;
2426
import androidx.annotation.NonNull;
2527
import androidx.annotation.Nullable;
2628
import androidx.appcompat.app.ActionBar;
2729
import androidx.appcompat.app.AlertDialog;
2830
import androidx.appcompat.app.AppCompatActivity;
31+
import androidx.core.content.ContextCompat;
2932
import androidx.fragment.app.Fragment;
3033
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
3134
import androidx.viewpager.widget.PagerAdapter;
@@ -49,17 +52,20 @@
4952
import com.squareup.picasso.Target;
5053

5154
import java.io.File;
55+
import java.io.FileOutputStream;
5256
import java.io.IOException;
5357
import java.io.InputStream;
5458
import java.lang.ref.WeakReference;
59+
import java.text.DecimalFormat;
60+
import java.text.DecimalFormatSymbols;
61+
import java.text.NumberFormat;
5562
import java.util.*;
5663

5764

5865
public class ReaderFragment extends Fragment implements View.OnTouchListener {
5966
public static final String PARAM_HANDLER = "PARAM_HANDLER";
6067
public static final String PARAM_URI = "PARAM_URI";
6168
public static final String PARAM_MODE = "PARAM_MODE";
62-
6369
public static final String STATE_FULLSCREEN = "STATE_FULLSCREEN";
6470
public static final String STATE_PAGEINFO = "STATE_PAGEINFO";
6571
public static final String STATE_NEW_COMIC = "STATE_NEW_COMIC";
@@ -112,6 +118,17 @@ public enum Mode {
112118
RESOURCE_VIEW_MODE.put(R.id.view_mode_fit_width, Constants.PageViewMode.FIT_WIDTH);
113119
}
114120

121+
/*
122+
private ActivityResultLauncher<String> requestPermissionLauncher =
123+
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
124+
if (isGranted) {
125+
Toast.makeText(getContext(), "Permission is accepted", Toast.LENGTH_SHORT).show();
126+
} else {
127+
Toast.makeText(getContext(), "Permission is denied", Toast.LENGTH_SHORT).show();
128+
}
129+
});
130+
*/
131+
115132
public static ReaderFragment create(int comicId) {
116133
ReaderFragment fragment = new ReaderFragment();
117134
Bundle args = new Bundle();
@@ -241,22 +258,6 @@ public void run() {
241258
mPageViewMode = Constants.PageViewMode.values()[viewModeInt];
242259
mIsLeftToRight = mPreferences.getBoolean(Constants.SETTINGS_READING_LEFT_TO_RIGHT, true);
243260

244-
// workaround: extract rar achive
245-
/*
246-
if (mParser instanceof RarParser) {
247-
File cacheDir = new File(getActivity().getExternalCacheDir(), "c");
248-
if (!cacheDir.exists()) {
249-
cacheDir.mkdir();
250-
}
251-
else {
252-
for (File f : cacheDir.listFiles()) {
253-
f.delete();
254-
}
255-
}
256-
((RarParser)mParser).setCacheDirectory(cacheDir);
257-
}
258-
*/
259-
260261
setHasOptionsMenu(true);
261262
}
262263

@@ -404,6 +405,14 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
404405
super.onViewCreated(view, savedInstanceState);
405406
}
406407

408+
@Override
409+
public void onPrepareOptionsMenu(@NonNull Menu menu) {
410+
super.onPrepareOptionsMenu(menu);
411+
412+
// TODO: fix up page export permission bs
413+
menu.findItem(R.id.menu_reader_export).setVisible(BuildConfig.DEBUG);
414+
}
415+
407416
@Override
408417
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
409418
inflater.inflate(R.menu.reader, menu);
@@ -521,13 +530,33 @@ public boolean onOptionsItemSelected(MenuItem item) {
521530
degrees = 0;
522531
degrees += 90;
523532
mRotations.put(pos,degrees);
524-
//apply rotation
533+
// apply rotation during (re)load
525534
mViewPager.getAdapter().notifyDataSetChanged();
535+
//updatePageViews(mViewPager,pos,true);
536+
// work in progress,
537+
// rotating imageview does not reset boundings unfortunately, dunno howto fix for now
538+
// also touch events are registered to the imageview and rotate with the image, not good
539+
//rotatePage(pos, degrees);
540+
break;
541+
case R.id.menu_reader_export:
542+
exportCurrentPage();
526543
break;
527544
}
528545
return super.onOptionsItemSelected(item);
529546
}
530547

548+
private void rotatePage(int pos, int degrees){
549+
try {
550+
MyTarget t = mTargets.get(pos);
551+
View v = t.mLayout.get();
552+
PageImageView piv = v.findViewById(R.id.pageImageView);
553+
piv.rotate(degrees);
554+
} catch (NullPointerException ne) {
555+
// huh, wasn't there, need to reload it
556+
mViewPager.getAdapter().notifyDataSetChanged();
557+
}
558+
}
559+
531560
private void setCurrentPage(int page) {
532561
setCurrentPage(page, true);
533562
}
@@ -570,34 +599,48 @@ private void updatePageImageInfo() {
570599
new Thread(new Runnable() {
571600
@Override
572601
public void run() {
573-
Map<String, String> metadata = null;
602+
Map<String, Object> metadata = null;
574603
try {
575604
metadata = mParser.getPageMetaData(pageNum);
576605
} catch (IOException e) {
577606
Log.e("", "", e);
578607
}
579608
String metaText = "";
580609
if (metadata != null && !metadata.isEmpty()) {
581-
String name = metadata.get(Parser.PAGEMETADATA_KEY_NAME);
610+
String name = (String) metadata.get(Parser.PAGEMETADATA_KEY_NAME);
582611
if (name != null)
583612
metaText += name;
584-
String t = metadata.get(Parser.PAGEMETADATA_KEY_MIME);
585-
String w = metadata.get(Parser.PAGEMETADATA_KEY_WIDTH);
586-
String h = metadata.get(Parser.PAGEMETADATA_KEY_HEIGHT);
613+
Object t = metadata.get(Parser.PAGEMETADATA_KEY_MIME);
614+
Object w = metadata.get(Parser.PAGEMETADATA_KEY_WIDTH);
615+
Object h = metadata.get(Parser.PAGEMETADATA_KEY_HEIGHT);
587616
if (t != null)
588617
metaText += (metaText.isEmpty() ? "" : "\n")
589618
+ String.valueOf(t) + ", "
590619
+ String.valueOf(w) + "x" + String.valueOf(h) + "px";
620+
// append Byte size
621+
Object size = metadata.get(Parser.PAGEMETADATA_KEY_SIZE);
622+
if (size != null) {
623+
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
624+
DecimalFormatSymbols symbols = formatter.getDecimalFormatSymbols();
625+
symbols.setGroupingSeparator('.');
626+
formatter.setDecimalFormatSymbols(symbols);
627+
try {
628+
metaText += (t != null ? ", " : "") + formatter.format(Long.valueOf(size.toString())) + " Bytes";
629+
} catch (Exception e) {
630+
// eat it
631+
}
632+
}
591633
// append the rest, ignore the already added from above
592-
List<String> ignoredKeys =
634+
List<String> keysToIgnore =
593635
Arrays.asList(new String[]{
594636
Parser.PAGEMETADATA_KEY_NAME,
595637
Parser.PAGEMETADATA_KEY_MIME,
596638
Parser.PAGEMETADATA_KEY_WIDTH,
597-
Parser.PAGEMETADATA_KEY_HEIGHT});
598-
for (Map.Entry<String, String> entry : metadata.entrySet()) {
639+
Parser.PAGEMETADATA_KEY_HEIGHT,
640+
Parser.PAGEMETADATA_KEY_SIZE});
641+
for (Map.Entry<String, Object> entry : metadata.entrySet()) {
599642
String key = entry.getKey();
600-
if (ignoredKeys.contains(key))
643+
if (keysToIgnore.contains(key))
601644
continue;
602645
metaText += (metaText.isEmpty() ? "" : "\n") +
603646
key + ": " + String.valueOf(entry.getValue());
@@ -658,6 +701,7 @@ public Object instantiateItem(ViewGroup container, int position) {
658701
loadImage(t);
659702
mTargets.put(position, t);
660703

704+
layout.setTag(Integer.valueOf(position));
661705
return layout;
662706
}
663707

@@ -1044,4 +1088,78 @@ private void updateSeekBar() {
10441088
mPageSeekBar.getProgressDrawable().setBounds(bounds);
10451089
}
10461090

1091+
private void exportCurrentPage() {
1092+
int pageNum = getCurrentPage();
1093+
int index = pageNum-1;
1094+
File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
1095+
FileOutputStream fOut = null;
1096+
Bitmap bitmap = null;
1097+
try {
1098+
if (folder==null)
1099+
throw new Exception("Cannot determine Downloads folder.");
1100+
else if (!folder.isDirectory() && !folder.mkdirs())
1101+
throw new Exception("Couldn't create Downloads folder.");
1102+
else if (mFile==null)
1103+
throw new Exception("Not a file");
1104+
1105+
String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
1106+
1107+
/*
1108+
new Handler().post(new Runnable() {
1109+
@Override
1110+
public void run() {
1111+
requestPermissionLauncher.launch(permission, ActivityOptionsCompat.makeBasic());
1112+
}
1113+
});
1114+
*/
1115+
1116+
//if (true) return;
1117+
1118+
if (ContextCompat.checkSelfPermission(getActivity(), permission)
1119+
!= PackageManager.PERMISSION_GRANTED) {
1120+
requestPermissions(new String[]{permission},
1121+
1);
1122+
// still no permission?
1123+
if (ContextCompat.checkSelfPermission(getActivity(), permission)
1124+
!= PackageManager.PERMISSION_GRANTED)
1125+
throw new Exception("No write permission.");
1126+
}
1127+
1128+
Map metadata = mParser.getPageMetaData(index);
1129+
String mime = (String) metadata.get(Parser.PAGEMETADATA_KEY_MIME);
1130+
File file = new File(folder,
1131+
(mFile.isDirectory()?mFile.getName():Utils.removeExtensionIfAny(mFile.getName()))+
1132+
".page"+pageNum+".jpg");
1133+
if (mime!=null && mime.endsWith("/jpeg")) {
1134+
InputStream is = mParser.getPage(index);
1135+
Utils.copyToFile(is, file);
1136+
}
1137+
else {
1138+
bitmap = null; //BitmapFactory.decodeStream(is);
1139+
if (bitmap == null){
1140+
MyTarget t = mTargets.get(index);
1141+
View v = t.mLayout.get();
1142+
PageImageView piv = v.findViewById(R.id.pageImageView);
1143+
bitmap = ((BitmapDrawable)piv.getDrawable()).getBitmap();
1144+
}
1145+
fOut = new FileOutputStream(file);
1146+
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, fOut);
1147+
}
1148+
} catch (Exception e) {
1149+
throw new RuntimeException(e);
1150+
} finally {
1151+
Utils.close(fOut);
1152+
//Utils.close(bitmap);
1153+
}
1154+
}
1155+
1156+
@Override
1157+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
1158+
if (requestCode == 1) {
1159+
if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
1160+
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
1161+
Log.d("granted","profit+1");
1162+
}
1163+
}
1164+
}
10471165
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="960"
5+
android:viewportHeight="960">
6+
<path
7+
android:fillColor="#fff"
8+
android:pathData="M480,640L280,440L336,382L440,486L440,160L520,160L520,486L624,382L680,440L480,640ZM240,800Q207,800 183.5,776.5Q160,753 160,720L160,600L240,600L240,720Q240,720 240,720Q240,720 240,720L720,720Q720,720 720,720Q720,720 720,720L720,600L800,600L800,720Q800,753 776.5,776.5Q753,800 720,800L240,800Z"/>
9+
</vector>

app/src/main/res/menu/reader.xml

+4
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@
3434
</group>
3535
</menu>
3636
</item>
37+
<item android:id="@+id/menu_reader_export"
38+
android:title="@string/action_view_export"
39+
android:icon="@drawable/ic_download_18"
40+
app:showAsAction="ifRoom"/>
3741
</menu>

0 commit comments

Comments
 (0)