Merge pull request '[Fileviewer] Download files, Don't render specific files' (#275) from 254-download-files into master

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/275
This commit is contained in:
M M Arif 2020-03-13 19:29:24 +00:00
commit e7433fd67d
9 changed files with 291 additions and 3 deletions

View file

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"

View file

@ -1,13 +1,21 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.text.method.ScrollingMovementMethod;
import android.util.Base64;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -15,6 +23,8 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.util.FitPolicy;
import com.github.chrisbanes.photoview.PhotoView;
@ -23,13 +33,18 @@ import com.pddstudio.highlightjs.models.Theme;
import org.apache.commons.io.FilenameUtils;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetFileViewerFragment;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
@ -37,7 +52,7 @@ import retrofit2.Callback;
* Author M M Arif
*/
public class FileViewActivity extends BaseActivity {
public class FileViewActivity extends BaseActivity implements BottomSheetFileViewerFragment.BottomSheetListener {
private View.OnClickListener onClickListener;
private TextView singleFileContents;
@ -51,6 +66,7 @@ public class FileViewActivity extends BaseActivity {
private LinearLayout pdfViewFrame;
private byte[] decodedPdf;
private Boolean pdfNightMode;
private static final int PERMISSION_REQUEST_CODE = 1;
@Override
protected int getLayoutResourceId(){
@ -90,6 +106,8 @@ public class FileViewActivity extends BaseActivity {
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
tinyDb.putString("downloadFileContents", "");
try {
singleFileName = URLDecoder.decode(singleFileName, "UTF-8");
@ -134,6 +152,10 @@ public class FileViewActivity extends BaseActivity {
String fileExtension = FilenameUtils.getExtension(filename);
mProgressBar.setVisibility(View.GONE);
// download file meta
tinyDb.putString("downloadFileName", filename);
tinyDb.putString("downloadFileContents", response.body().getContent());
if(appUtil.imageExtension(fileExtension)) { // file is image
singleFileContentsFrame.setVisibility(View.GONE);
@ -186,6 +208,18 @@ public class FileViewActivity extends BaseActivity {
.nightMode(pdfNightMode)
.load();
}
else if (appUtil.excludeFilesInFileViewerExtension(fileExtension)) { // files need to be excluded
imageView.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
singleFileContents.setText(getResources().getString(R.string.excludeFilesInFileviewer));
singleFileContents.setGravity(Gravity.CENTER);
singleFileContents.setTypeface(null, Typeface.BOLD);
}
else { // file type not known - plain text view
@ -239,6 +273,113 @@ public class FileViewActivity extends BaseActivity {
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
return true;
case R.id.genericMenu:
BottomSheetFileViewerFragment bottomSheet = new BottomSheetFileViewerFragment();
bottomSheet.show(getSupportFragmentManager(), "fileViewerBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
switch (text) {
case "downloadFile":
if (Build.VERSION.SDK_INT >= 23)
{
if (checkPermission())
{
requestFileDownload();
}
else {
requestPermission();
}
}
else
{
requestFileDownload();
}
break;
}
}
private void requestFileDownload() {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(!tinyDb.getString("downloadFileContents").isEmpty()) {
File outputFileName = new File(tinyDb.getString("downloadFileName"));
final File downloadFilePath = new File(Environment.getExternalStorageDirectory().getPath() + "/Download/" + outputFileName.getName());
byte[] pdfAsBytes = Base64.decode(tinyDb.getString("downloadFileContents"), 0);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(downloadFilePath, false);
Objects.requireNonNull(fileOutputStream).write(pdfAsBytes);
fileOutputStream.flush();
fileOutputStream.close();
Toasty.info(getApplicationContext(), getString(R.string.downloadFileSaved));
}
catch (IOException e) {
Log.e("errorFileDownloading", Objects.requireNonNull(e.getMessage()));
}
}
else {
Toasty.error(getApplicationContext(), getString(R.string.waitLoadingDownloadFile));
}
}
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("PermissionsCheck", "Permission Granted");
}
else {
Log.e("PermissionsCheck", "Permission Denied");
}
break;
}
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
@ -249,4 +390,4 @@ public class FileViewActivity extends BaseActivity {
};
}
}
}

View file

@ -0,0 +1,57 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R;
/**
* Author M M Arif
*/
public class BottomSheetFileViewerFragment extends BottomSheetDialogFragment {
private BottomSheetFileViewerFragment.BottomSheetListener bmListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.bottom_sheet_file_viewer, container, false);
TextView downloadFile = v.findViewById(R.id.downloadFile);
downloadFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("downloadFile");
dismiss();
}
});
return v;
}
public interface BottomSheetListener {
void onButtonClicked(String text);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
bmListener = (BottomSheetFileViewerFragment.BottomSheetListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement BottomSheetListener");
}
}
}

View file

@ -28,4 +28,19 @@ public class Toasty {
}
public static void error(Context context, String message) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate( context.getResources().getLayout(R.layout.custom_toast_error), null );
TextView text = view.findViewById(R.id.toastText);
text.setText(message);
Toast toast = new Toast(context);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(view);
toast.show();
}
}

View file

@ -218,7 +218,8 @@ public class AppUtil {
"coffee", "rc", "rs", "rust", "basic", "clj", "css", "dart", "lisp", "erl", "hs", "lsp", "rkt",
"ss", "llvm", "ll", "lua", "matlab", "pascal", "r", "scala", "sql", "latex", "tex", "vb", "vbs",
"vhd", "tcl", "wiki.meta", "yaml", "yml", "markdown", "xml", "proto", "regex", "py", "pl", "js",
"html", "htm", "volt", "ini", "htaccess", "conf", "gitignore", "gradle", "txt", "properties", "bat"};
"html", "htm", "volt", "ini", "htaccess", "conf", "gitignore", "gradle", "txt", "properties", "bat",
"twig"};
return Arrays.asList(extValues).contains(ext);
@ -240,6 +241,16 @@ public class AppUtil {
}
public Boolean excludeFilesInFileViewerExtension(String ext) {
String[] extValues = new String[] {"doc", "docx", "ppt", "pptx", "xls", "xlsx", "xlsm", "odt",
"ott", "odf", "ods", "ots", "exe", "jar", "odg", "otg", "odp", "otp", "bin", "dmg", "psd",
"xcf"};
return Arrays.asList(extValues).contains(ext);
}
public String getLastCharactersOfWord( String str, int count ) {
return str.substring(str.length() - count);

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#368F73" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
android:background="?attr/primaryBackgroundColor"
android:paddingTop="8dp">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:id="@+id/downloadFile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/downloadFile"
android:drawableStart="@drawable/ic_file_download_24dp"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_toast_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="15dp"
android:background="@drawable/round_corners"
android:backgroundTint="@color/toastBackground">
<TextView android:id="@+id/toastText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/darkRed"
android:layout_gravity="center"
android:gravity="center" />
</LinearLayout>

View file

@ -551,4 +551,8 @@
<string name="mergePRSuccessMsg">Pull Request was merged successfully</string>
<string name="mergePR404ErrorMsg">Pull Request is not available for merge</string>
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File is saved to Download directory</string>
<string name="excludeFilesInFileviewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
</resources>