Skip to content

Commit

Permalink
Merge pull request #46 from x0b/dev-x0b
Browse files Browse the repository at this point in the history
Bugfix release 1.10.1
  • Loading branch information
x0b authored Jan 29, 2020
2 parents 10d2e49 + 038c274 commit 5d77338
Show file tree
Hide file tree
Showing 29 changed files with 207 additions and 73 deletions.
49 changes: 29 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# RcloneExplorer
[![license: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/x0b/rcloneExplorer/blob/master/LICENSE) [![Github Releases](https://img.shields.io/github/downloads/x0b/rcloneExplorer/total.svg)](https://github.com/x0b/rcloneExplorer/releases) [![GitHub release](https://img.shields.io/github/v/release/x0b/rcloneExplorer?include_prereleases)](https://github.com/x0b/rcloneExplorer/releases/latest)
[![license: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/x0b/rcloneExplorer/blob/master-x0b/LICENSE) [![Github Releases](https://img.shields.io/github/downloads/x0b/rcloneExplorer/total.svg)](https://github.com/x0b/rcloneExplorer/releases) [![GitHub release](https://img.shields.io/github/v/release/x0b/rcloneExplorer?include_prereleases)](https://github.com/x0b/rcloneExplorer/releases/latest) [![Google Play Pre-Registration](https://img.shields.io/badge/Google_Play-Pre%E2%80%93Registration-brightgreen)](https://forms.gle/5jLYhZwafx7nEfi16)

A Rclone based file explorer for Android

Expand All @@ -14,16 +14,16 @@ Cloud Access | 256 Bit AES Encryption | Integrated Experience
<img src="https://github.com/x0b/rcloneExplorer/blob/master-x0b/docs/cloud-computing.png?raw=true" alt="Cloud Access" width="192" /> | <img src="https://github.com/x0b/rcloneExplorer/blob/master-x0b/docs/locked-padlock.png?raw=true" alt="256 Bit AES End-to-End Encryption" width="144" /> | <img src="https://github.com/x0b/rcloneExplorer/blob/master-x0b/docs/smartphone.png?raw=true" alt="Integrated Experience" width="176"/>
Use your cloud storage as if it were a local folder | Keep your files private on any cloud provider | Open your files or send them to the cloud with other apps

### Full list
### All features
- File Management
- List and view files
- Download and upload files
- Move, rename, and delete files and folders
- Streaming & Integration
- Streaming media files
- Serving directories over HTTP or WebDAV
- Stream media files
- Serve directories over FTP, HTTP or WebDAV
- Remotes
- Browse any type of rclone remote (local remotes are limited though)
- Browse any type of rclone remote (with limitations on "local" remotes)
- Create new remotes in the app
- UI
- Dark theme
Expand All @@ -32,8 +32,8 @@ Use your cloud storage as if it were a local folder | Keep your files private on
- Import and export rclone configuration files
- Encrypted configurations (import only)
- Platform support
- Supports ARM and x86 devices
- Supports SDK 21+ (Lollipop 5.0)
- Runs on ARM, ARM64, x86 and x64 devices
- Runs on Android 5 or newer ([see docs](https://github.com/x0b/rcloneExplorer/wiki#android-support-roadmap))
- Supports Storage Access Framework (SAF) ([see docs](https://github.com/x0b/rcloneExplorer/wiki#adding-local-storage-saf))

Screenshots
Expand All @@ -60,20 +60,19 @@ Grab the [latest version](https://github.com/x0b/rcloneExplorer/releases/latest)

If you don't know which version to pick use ```rcloneExplorer-<version>-universal-release.apk```. Most devices run ARM 64 Bit, and 64 Bit devices often can also run the respective 32 bit version at lower performance.

Usage
------------
[See the wiki](https://github.com/x0b/rcloneExplorer/wiki).

Roadmap
------------
Note that these plans are subject to change and might not materialize completely or at all.

#### Current Version (1.10.0)
* **New:** Proxy support (for https & http)
* **New:** Various internal refactorings
* **New:** The thumbnail size limit can now be set in the settings
* **New:** Update rclone to 1.50.2
* **Fix:** Logging settings not explaining data collection
* **Fix:** External locations listed multiple times
* **Fix:** OAuth not working on newer rclone versions
* **Fix:** Crash when streaming in background
#### Current Version (1.10.1)
* **Fix:** Thubnails not loading after device rotation
* **Fix:** Crash when importing rclone config
* **Fix:** Crash when dismissing invalid dialog
* **Fix:** Crash when streaming starting stream

#### Next minor version
- Bug fixes
Expand All @@ -97,13 +96,23 @@ Known Issues

Contributing
------------
You can contribute by reporting any bugs and errors using the [issue tracker](https://github.com/x0b/rcloneExplorer/issues).
Pull requests are welcome, but you have to accept a small CLA to ensure license compatibility.
This app is developed by and for its community. Any contribution to improve the app is welcome, and there are multiple to contribute:
- Enable crash reporting in ```Settings > Logging > Send anonymous crash reports```.
- Reporting bugs using the [issue tracker](https://github.com/x0b/rcloneExplorer/issues).
- Proposing and voting (👍 👎) on [new features](https://github.com/x0b/rcloneExplorer/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement+sort%3Areactions-%2B1-desc) and ideas on the [issue tracker](https://github.com/x0b/rcloneExplorer/issues).
- Translating the app into a new language. Please open an issue if you are interested.
- Implementing features and fixing bugs. See the list of [available](https://github.com/x0b/rcloneExplorer/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) and [easier](https://github.com/x0b/rcloneExplorer/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) issues. Please comment on the issue if you want to take over.

License
-----------------
### About this app
This app is released under the terms of the [GPLv3 license](https://github.com/x0b/rcloneExplorer/blob/master-x0b/LICENSE). Community contributions are licensed under the MIT license, and [CLA Assistant](https://cla-assistant.io/) will ask you to confirm [a CLA stating that](https://gist.githubusercontent.com/x0b/889f037d76706fc9e3ab8ee1c047841b/raw/67c028b19e33111428904558cfda0c01039d1574/rcloneExplorer-cla-202001) if create a PR.

This is a modified build of rcloneExplorer because of little activity in the parent repo. For the parent repository, see [kaczmarkiewiczp/rcloneExplorer](https://github.com/kaczmarkiewiczp/rcloneExplorer). If you encounter an issue with a [version published here](https://github.com/x0b/rcloneExplorer/releases), open an issue [here](https://github.com/x0b/rcloneExplorer/issues/new).

Credits/Libraries
-----------------
If you want to convey a modified version (fork), we ask you to use a different name, app icon and package id as well as proper attribution to avoid user confusion.

### Libraries
- [rclone](https://github.com/rclone/rclone) - "rsync for cloud storage"
- [Jetpack AndroidX](https://developer.android.com/license)
- [Floating Action Button SpeedDial](https://github.com/leinardi/FloatingActionButtonSpeedDial) - A Floating Action Button Speed Dial implementation for Android that follows the Material Design specification.
Expand Down
20 changes: 18 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ android {
applicationId 'ca.pkay.rcloneexplorer.x0b'
minSdkVersion 21
targetSdkVersion 29
versionCode 5
versionName '1.10.0'
versionCode 6
versionName '1.10.1'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Expand All @@ -34,6 +34,22 @@ android {
}
}

flavorDimensions 'edition'
productFlavors {

// App id for play store
rcx {
dimension 'edition'
applicationId 'io.github.x0b.rcx'
}

// App id for github
rcloneExplorer {
dimension 'edition'
applicationId 'ca.pkay.rcloneexplorer.x0b'
}
}

splits {
abi {
enable true
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="ca.pkay.rcloneexplorer.x0b.fileprovider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/assets/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
### 1.10.1
* **Fix:** Thubnails not loading after device rotation
* **Fix:** Crash when importing rclone config
* **Fix:** Crash when dismissing invalid dialog
* **Fix:** Crash when streaming starting stream

***

### 1.10.0
* **New:** Proxy support (for https & http)
* **New:** Various internal refactorings
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/ca/pkay/rcloneexplorer/Dialogs/Dialogs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ca.pkay.rcloneexplorer.Dialogs;

import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;

public class Dialogs {

/**
* Dismiss a dialog, but only if it is still attached to a host activity.
* <br><br>
* This should be used especially in callbacks, since they have a higher
* chance of being executed in a different lifecycle phase and thus an
* elevated propability of calling DialogFrament.dismiss() on an invalid
* fragment.
* @param dialog the dialog to dismiss
*/
public static void dismissSilently(@Nullable DialogFragment dialog) {
if(dialog != null) {
if(dialog.isStateSaved()){
dialog.dismissAllowingStateLoss();
} else if(dialog.isAdded()) {
dialog.dismiss();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Base64;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
Expand Down Expand Up @@ -44,6 +45,7 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import ca.pkay.rcloneexplorer.BreadcrumbView;
import ca.pkay.rcloneexplorer.Dialogs.Dialogs;
import ca.pkay.rcloneexplorer.Dialogs.FilePropertiesDialog;
import ca.pkay.rcloneexplorer.Dialogs.GoToDialog;
import ca.pkay.rcloneexplorer.Dialogs.InputDialog;
Expand Down Expand Up @@ -77,6 +79,7 @@
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.ServerSocket;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
Expand All @@ -98,6 +101,7 @@ public class FileExplorerFragment extends Fragment implements FileExplorerRecy
SortDialog.OnClickListener,
ServeDialog.Callback {

private static final String TAG = "FileExplorerFragment";
private static final String ARG_REMOTE = "remote_param";
private static final String SHARED_PREFS_SORT_ORDER = "ca.pkay.rcexplorer.sort_order";
private static final int FILE_PICKER_UPLOAD_RESULT = 186;
Expand Down Expand Up @@ -154,6 +158,7 @@ public class FileExplorerFragment extends Fragment implements FileExplorerRecy
private boolean goToDefaultSet;
private Context context;
private String thumbnailServerAuth;
private int thumbnailServerPort;

/**
* Mandatory empty constructor for the fragment manager to instantiate the
Expand Down Expand Up @@ -737,6 +742,7 @@ private void startThumbnailService() {
Intent serveIntent = new Intent(getContext(), ThumbnailsLoadingService.class);
serveIntent.putExtra(ThumbnailsLoadingService.REMOTE_ARG, remote);
serveIntent.putExtra(ThumbnailsLoadingService.HIDDEN_PATH, thumbnailServerAuth);
serveIntent.putExtra(ThumbnailsLoadingService.SERVER_PORT, thumbnailServerPort);
context.startService(serveIntent);
isThumbnailsServiceRunning = true;
}
Expand All @@ -746,6 +752,19 @@ private void initializeThumbnailParams() {
byte[] values = new byte[16];
random.nextBytes(values);
thumbnailServerAuth = Base64.encodeToString(values, Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE);
thumbnailServerPort = allocatePort(29179, true);
}

private static int allocatePort(int port, boolean allocateFallback) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
serverSocket.setReuseAddress(true);
return serverSocket.getLocalPort();
} catch (IOException e) {
if (allocateFallback) {
return allocatePort(0, false);
}
}
throw new IllegalStateException("No port available");
}

private void searchClicked() {
Expand Down Expand Up @@ -1301,7 +1320,7 @@ public void onFileOptionsClicked(View view, FileItem fileItem) {

@Override
public String[] getThumbnailServerParams() {
return new String[]{thumbnailServerAuth};
return new String[]{thumbnailServerAuth + '/' + remote.getName(), String.valueOf(thumbnailServerPort)};
}

private void showFileMenu(View view, final FileItem fileItem) {
Expand Down Expand Up @@ -1896,15 +1915,7 @@ protected Boolean doInBackground(FileItem... fileItems) {
@Override
protected void onPostExecute(Boolean status) {
super.onPostExecute(status);
if (loadingDialog.isStateSaved()) {
loadingDialog.dismissAllowingStateLoss();
} else {
try {
loadingDialog.dismiss();
} catch (NullPointerException e) {
return;
}
}
Dialogs.dismissSilently(loadingDialog);
if (!status) {
return;
}
Expand Down Expand Up @@ -1960,9 +1971,12 @@ protected void onPreExecute() {

@Override
protected Void doInBackground(FileItem... fileItems) {
if(context == null) {
Log.w(TAG, "doInBackground: could not start stream, context is invalid");
return null;
}
FileItem fileItem = fileItems[0];

Intent serveIntent = new Intent(getContext(), StreamingService.class);
Intent serveIntent = new Intent(context, StreamingService.class);
serveIntent.putExtra(StreamingService.SERVE_PATH_ARG, fileItem.getPath());
serveIntent.putExtra(StreamingService.REMOTE_ARG, remote);
serveIntent.putExtra(StreamingService.SHOW_NOTIFICATION_TEXT, false);
Expand Down Expand Up @@ -2016,13 +2030,7 @@ protected Void doInBackground(FileItem... fileItems) {
retries--;
}

if (loadingDialog != null) {
if (loadingDialog.isStateSaved()) {
loadingDialog.dismissAllowingStateLoss();
} else if(loadingDialog.isAdded()){
loadingDialog.dismiss();
}
}
Dialogs.dismissSilently(loadingDialog);
tryStartActivityForResult(FileExplorerFragment.this, intent, STREAMING_INTENT_RESULT);
return null;
}
Expand Down Expand Up @@ -2074,13 +2082,7 @@ protected String doInBackground(String... strings) {
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (loadingDialog != null) {
if (loadingDialog.isStateSaved()) {
loadingDialog.dismissAllowingStateLoss();
} else {
loadingDialog.dismiss();
}
}
Dialogs.dismissSilently(loadingDialog);

if (s == null) {
Toasty.error(context, getString(R.string.error_generating_link), Toast.LENGTH_SHORT, true).show();
Expand All @@ -2106,11 +2108,7 @@ protected void onPostExecute(String s) {
@Override
protected void onCancelled() {
super.onCancelled();
if (loadingDialog.isStateSaved()) {
loadingDialog.dismissAllowingStateLoss();
} else {
loadingDialog.dismiss();
}
Dialogs.dismissSilently(loadingDialog);
}
}
}
13 changes: 5 additions & 8 deletions app/src/main/java/ca/pkay/rcloneexplorer/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.PreferenceManager;
import ca.pkay.rcloneexplorer.Dialogs.Dialogs;
import ca.pkay.rcloneexplorer.Dialogs.InputDialog;
import ca.pkay.rcloneexplorer.Dialogs.LoadingDialog;
import ca.pkay.rcloneexplorer.Fragments.FileExplorerFragment;
Expand Down Expand Up @@ -154,7 +155,7 @@ public void onClick(View v) {
});

boolean appUpdates = sharedPreferences.getBoolean(getString(R.string.pref_key_app_updates), true);
if (appUpdates) {
if ("rcloneExplorer".equals(BuildConfig.FLAVOR) && appUpdates) {
checkForUpdate(false);
}

Expand Down Expand Up @@ -611,7 +612,7 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO
updateLastUpdateRequest();
long publishedAt = getLastPublishTimestamp(response);
// Since the app is not published immediately during build, 15 minutes are added
long publishBarrier = publishedAt + 1000 * 60 * 15;
long publishBarrier = publishedAt - 1000 * 60 * 15;
if(BuildConfig.BUILD_TIME < publishBarrier) {
Log.i(TAG, "onResponse: App is not up-to-date");
handler.obtainMessage(MainActivity.UPDATE_AVAILABLE).sendToTarget();
Expand Down Expand Up @@ -683,11 +684,7 @@ protected Boolean doInBackground(Uri... uris) {
@Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
if (loadingDialog.isStateSaved()) {
loadingDialog.dismissAllowingStateLoss();
} else {
loadingDialog.dismiss();
}
Dialogs.dismissSilently(loadingDialog);
if (!success) {
Toasty.error(context, getString(R.string.copying_rclone_config_fail), Toast.LENGTH_LONG, true).show();
return;
Expand Down Expand Up @@ -738,7 +735,7 @@ protected Boolean doInBackground(String... strings) {
@Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
loadingDialog.dismiss();
Dialogs.dismissSilently(loadingDialog);
if (!success) {
Toasty.error(context, getString(R.string.error_unlocking_config), Toast.LENGTH_LONG, true).show();
askForConfigPassword();
Expand Down
10 changes: 9 additions & 1 deletion app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,15 @@ public Uri searchExternalConfig(){

public boolean copyConfigFile(Uri uri) throws IOException {
String appsFileDir = context.getFilesDir().getPath();
InputStream inputStream = context.getContentResolver().openInputStream(uri);
InputStream inputStream;
// The exact cause of the NPE is unknown, but the effect is the same
// - the copy process has failed, therefore bubble an IOException
// for handling at the appropriate layers.
try {
inputStream = context.getContentResolver().openInputStream(uri);
} catch(NullPointerException e) {
throw new IOException(e);
}
File tempFile = new File(appsFileDir, "rclone.conf-tmp");
File configFile = new File(appsFileDir, "rclone.conf");
FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
Expand Down
Loading

0 comments on commit 5d77338

Please sign in to comment.