mirror of
https://codeberg.org/gitnex/GitNex.git
synced 2024-12-26 16:04:07 +08:00
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:
commit
e7433fd67d
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
package org.mian.gitnex.activities;
|
package org.mian.gitnex.activities;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.text.method.ScrollingMovementMethod;
|
import android.text.method.ScrollingMovementMethod;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
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.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@ -15,6 +23,8 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
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.PDFView;
|
||||||
import com.github.barteksc.pdfviewer.util.FitPolicy;
|
import com.github.barteksc.pdfviewer.util.FitPolicy;
|
||||||
import com.github.chrisbanes.photoview.PhotoView;
|
import com.github.chrisbanes.photoview.PhotoView;
|
||||||
@ -23,13 +33,18 @@ import com.pddstudio.highlightjs.models.Theme;
|
|||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.mian.gitnex.R;
|
import org.mian.gitnex.R;
|
||||||
import org.mian.gitnex.clients.RetrofitClient;
|
import org.mian.gitnex.clients.RetrofitClient;
|
||||||
|
import org.mian.gitnex.fragments.BottomSheetFileViewerFragment;
|
||||||
import org.mian.gitnex.helpers.AlertDialogs;
|
import org.mian.gitnex.helpers.AlertDialogs;
|
||||||
import org.mian.gitnex.helpers.Toasty;
|
import org.mian.gitnex.helpers.Toasty;
|
||||||
import org.mian.gitnex.models.Files;
|
import org.mian.gitnex.models.Files;
|
||||||
import org.mian.gitnex.util.AppUtil;
|
import org.mian.gitnex.util.AppUtil;
|
||||||
import org.mian.gitnex.util.TinyDB;
|
import org.mian.gitnex.util.TinyDB;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.util.Objects;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
|
|
||||||
@ -37,7 +52,7 @@ import retrofit2.Callback;
|
|||||||
* Author M M Arif
|
* Author M M Arif
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class FileViewActivity extends BaseActivity {
|
public class FileViewActivity extends BaseActivity implements BottomSheetFileViewerFragment.BottomSheetListener {
|
||||||
|
|
||||||
private View.OnClickListener onClickListener;
|
private View.OnClickListener onClickListener;
|
||||||
private TextView singleFileContents;
|
private TextView singleFileContents;
|
||||||
@ -51,6 +66,7 @@ public class FileViewActivity extends BaseActivity {
|
|||||||
private LinearLayout pdfViewFrame;
|
private LinearLayout pdfViewFrame;
|
||||||
private byte[] decodedPdf;
|
private byte[] decodedPdf;
|
||||||
private Boolean pdfNightMode;
|
private Boolean pdfNightMode;
|
||||||
|
private static final int PERMISSION_REQUEST_CODE = 1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getLayoutResourceId(){
|
protected int getLayoutResourceId(){
|
||||||
@ -90,6 +106,8 @@ public class FileViewActivity extends BaseActivity {
|
|||||||
initCloseListener();
|
initCloseListener();
|
||||||
closeActivity.setOnClickListener(onClickListener);
|
closeActivity.setOnClickListener(onClickListener);
|
||||||
|
|
||||||
|
tinyDb.putString("downloadFileContents", "");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
singleFileName = URLDecoder.decode(singleFileName, "UTF-8");
|
singleFileName = URLDecoder.decode(singleFileName, "UTF-8");
|
||||||
@ -134,6 +152,10 @@ public class FileViewActivity extends BaseActivity {
|
|||||||
String fileExtension = FilenameUtils.getExtension(filename);
|
String fileExtension = FilenameUtils.getExtension(filename);
|
||||||
mProgressBar.setVisibility(View.GONE);
|
mProgressBar.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// download file meta
|
||||||
|
tinyDb.putString("downloadFileName", filename);
|
||||||
|
tinyDb.putString("downloadFileContents", response.body().getContent());
|
||||||
|
|
||||||
if(appUtil.imageExtension(fileExtension)) { // file is image
|
if(appUtil.imageExtension(fileExtension)) { // file is image
|
||||||
|
|
||||||
singleFileContentsFrame.setVisibility(View.GONE);
|
singleFileContentsFrame.setVisibility(View.GONE);
|
||||||
@ -186,6 +208,18 @@ public class FileViewActivity extends BaseActivity {
|
|||||||
.nightMode(pdfNightMode)
|
.nightMode(pdfNightMode)
|
||||||
.load();
|
.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
|
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() {
|
private void initCloseListener() {
|
||||||
onClickListener = new View.OnClickListener() {
|
onClickListener = new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -249,4 +390,4 @@ public class FileViewActivity extends BaseActivity {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,8 @@ public class AppUtil {
|
|||||||
"coffee", "rc", "rs", "rust", "basic", "clj", "css", "dart", "lisp", "erl", "hs", "lsp", "rkt",
|
"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",
|
"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",
|
"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);
|
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 ) {
|
public String getLastCharactersOfWord( String str, int count ) {
|
||||||
|
|
||||||
return str.substring(str.length() - count);
|
return str.substring(str.length() - count);
|
||||||
|
5
app/src/main/res/drawable/ic_file_download_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_file_download_24dp.xml
Normal 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>
|
36
app/src/main/res/layout/bottom_sheet_file_viewer.xml
Normal file
36
app/src/main/res/layout/bottom_sheet_file_viewer.xml
Normal 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>
|
18
app/src/main/res/layout/custom_toast_error.xml
Normal file
18
app/src/main/res/layout/custom_toast_error.xml
Normal 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>
|
@ -551,4 +551,8 @@
|
|||||||
<string name="mergePRSuccessMsg">Pull Request was merged successfully</string>
|
<string name="mergePRSuccessMsg">Pull Request was merged successfully</string>
|
||||||
<string name="mergePR404ErrorMsg">Pull Request is not available for merge</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>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user