mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-16 19:57:31 +00:00
Improve folder selection UI/UX
This commit is contained in:
parent
c8704fb2dc
commit
7b60258959
@ -1,102 +1,64 @@
|
|||||||
package awais.instagrabber.activities;
|
package awais.instagrabber.activities;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.UriPermission;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.PrintWriter;
|
||||||
import java.net.URLDecoder;
|
import java.io.StringWriter;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.databinding.ActivityDirectorySelectBinding;
|
import awais.instagrabber.databinding.ActivityDirectorySelectBinding;
|
||||||
|
import awais.instagrabber.dialogs.ConfirmDialogFragment;
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.viewmodels.DirectorySelectActivityViewModel;
|
||||||
import awais.instagrabber.utils.Utils;
|
|
||||||
|
|
||||||
public class DirectorySelectActivity extends BaseLanguageActivity {
|
public class DirectorySelectActivity extends BaseLanguageActivity {
|
||||||
private static final String TAG = DirectorySelectActivity.class.getSimpleName();
|
private static final String TAG = DirectorySelectActivity.class.getSimpleName();
|
||||||
|
public static final int SELECT_DIR_REQUEST_CODE = 0x01;
|
||||||
public static final int SELECT_DIR_REQUEST_CODE = 1090;
|
private static final int ERROR_REQUEST_CODE = 0x02;
|
||||||
|
|
||||||
private Uri initialUri;
|
private Uri initialUri;
|
||||||
private ActivityDirectorySelectBinding binding;
|
private ActivityDirectorySelectBinding binding;
|
||||||
|
private DirectorySelectActivityViewModel viewModel;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
binding = ActivityDirectorySelectBinding.inflate(getLayoutInflater());
|
binding = ActivityDirectorySelectBinding.inflate(getLayoutInflater());
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
|
viewModel = new ViewModelProvider(this).get(DirectorySelectActivityViewModel.class);
|
||||||
|
setupObservers();
|
||||||
binding.selectDir.setOnClickListener(v -> openDirectoryChooser());
|
binding.selectDir.setOnClickListener(v -> openDirectoryChooser());
|
||||||
setInitialUri();
|
AppExecutors.getInstance().mainThread().execute(() -> viewModel.setInitialUri(getIntent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setInitialUri() {
|
private void setupObservers() {
|
||||||
AppExecutors.getInstance().mainThread().execute(() -> {
|
viewModel.getMessage().observe(this, message -> binding.message.setText(message));
|
||||||
final Intent intent = getIntent();
|
viewModel.getPrevUri().observe(this, prevUri -> {
|
||||||
if (intent == null) {
|
if (prevUri == null) {
|
||||||
setMessage();
|
binding.prevUri.setVisibility(View.GONE);
|
||||||
|
binding.message2.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Parcelable initialUriParcelable = intent.getParcelableExtra(Constants.EXTRA_INITIAL_URI);
|
binding.prevUri.setText(prevUri);
|
||||||
if (!(initialUriParcelable instanceof Uri)) {
|
binding.prevUri.setVisibility(View.VISIBLE);
|
||||||
setMessage();
|
binding.message2.setVisibility(View.VISIBLE);
|
||||||
return;
|
});
|
||||||
}
|
viewModel.getDirSuccess().observe(this, success -> binding.selectDir.setVisibility(success ? View.GONE : View.VISIBLE));
|
||||||
initialUri = (Uri) initialUriParcelable;
|
viewModel.isLoading().observe(this, loading -> {
|
||||||
setMessage();
|
binding.message.setVisibility(loading ? View.GONE : View.VISIBLE);
|
||||||
|
binding.loadingIndicator.setVisibility(loading ? View.VISIBLE : View.GONE);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private void setMessage() {
|
|
||||||
if (initialUri == null) {
|
|
||||||
// default message
|
|
||||||
binding.message.setText("Select a directory which Barinsta will use for downloads and temp files");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!initialUri.toString().startsWith("content")) {
|
|
||||||
final String message = String.format("Android has changed the way apps can access files and directories on storage.\n\n" +
|
|
||||||
"Please re-select the directory '%s' after clicking the button below",
|
|
||||||
initialUri.toString());
|
|
||||||
binding.message.setText(message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<UriPermission> existingPermissions = getContentResolver().getPersistedUriPermissions();
|
|
||||||
final boolean anyMatch = existingPermissions.stream().anyMatch(uriPermission -> uriPermission.getUri().equals(initialUri));
|
|
||||||
if (!anyMatch) {
|
|
||||||
// permission revoked message
|
|
||||||
final String message = "Permissions for the previously selected directory '%s' were revoked by the system.\n\n" +
|
|
||||||
"Re-select the directory or select a new directory.";
|
|
||||||
final DocumentFile documentFile = DocumentFile.fromSingleUri(this, initialUri);
|
|
||||||
String path;
|
|
||||||
try {
|
|
||||||
path = URLDecoder.decode(initialUri.toString(), StandardCharsets.UTF_8.toString());
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
path = initialUri.toString();
|
|
||||||
}
|
|
||||||
if (documentFile != null) {
|
|
||||||
try {
|
|
||||||
final File file = Utils.getDocumentFileRealPath(this, documentFile);
|
|
||||||
if (file != null) {
|
|
||||||
path = file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "setMessage: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.message.setText(String.format(message, path));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openDirectoryChooser() {
|
private void openDirectoryChooser() {
|
||||||
@ -112,17 +74,42 @@ public class DirectorySelectActivity extends BaseLanguageActivity {
|
|||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (requestCode != SELECT_DIR_REQUEST_CODE) return;
|
if (requestCode != SELECT_DIR_REQUEST_CODE) return;
|
||||||
if (resultCode != RESULT_OK) {
|
if (resultCode != RESULT_OK) {
|
||||||
// Show error
|
showErrorDialog(getString(R.string.select_a_folder));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data == null || data.getData() == null) {
|
if (data == null || data.getData() == null) {
|
||||||
// show error
|
showErrorDialog(getString(R.string.select_a_folder));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
try {
|
try {
|
||||||
Utils.setupSelectedDir(this, data);
|
viewModel.setupSelectedDir(data);
|
||||||
|
final Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// show error
|
// Should not come to this point.
|
||||||
|
// If it does, we have to show this error to the user so that they can report it.
|
||||||
|
try (final StringWriter sw = new StringWriter();
|
||||||
|
final PrintWriter pw = new PrintWriter(sw)) {
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
showErrorDialog("Please report this error to the developers:\n\n" + sw.toString());
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
Log.e(TAG, "onActivityResult: ", ioException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrorDialog(@NonNull final String message) {
|
||||||
|
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
||||||
|
ERROR_REQUEST_CODE,
|
||||||
|
R.string.error,
|
||||||
|
message,
|
||||||
|
R.string.ok,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
dialogFragment.show(getSupportFragmentManager(), ConfirmDialogFragment.class.getSimpleName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
@ -28,13 +29,37 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
@StringRes final int positiveText,
|
@StringRes final int positiveText,
|
||||||
@StringRes final int negativeText,
|
@StringRes final int negativeText,
|
||||||
@StringRes final int neutralText) {
|
@StringRes final int neutralText) {
|
||||||
|
return newInstance(requestCode, title, (Integer) message, positiveText, negativeText, neutralText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static ConfirmDialogFragment newInstance(final int requestCode,
|
||||||
|
@StringRes final int title,
|
||||||
|
final String message,
|
||||||
|
@StringRes final int positiveText,
|
||||||
|
@StringRes final int negativeText,
|
||||||
|
@StringRes final int neutralText) {
|
||||||
|
return newInstance(requestCode, title, (Object) message, positiveText, negativeText, neutralText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static ConfirmDialogFragment newInstance(final int requestCode,
|
||||||
|
@StringRes final int title,
|
||||||
|
final Object message,
|
||||||
|
@StringRes final int positiveText,
|
||||||
|
@StringRes final int negativeText,
|
||||||
|
@StringRes final int neutralText) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("requestCode", requestCode);
|
args.putInt("requestCode", requestCode);
|
||||||
if (title != 0) {
|
if (title != 0) {
|
||||||
args.putInt("title", title);
|
args.putInt("title", title);
|
||||||
}
|
}
|
||||||
if (message != 0) {
|
if (message != null) {
|
||||||
args.putInt("message", message);
|
if (message instanceof Integer) {
|
||||||
|
args.putInt("message", (int) message);
|
||||||
|
} else if (message instanceof String) {
|
||||||
|
args.putString("message", (String) message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (positiveText != 0) {
|
if (positiveText != 0) {
|
||||||
args.putInt("positive", positiveText);
|
args.putInt("positive", positiveText);
|
||||||
@ -48,6 +73,7 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
ConfirmDialogFragment fragment = new ConfirmDialogFragment();
|
ConfirmDialogFragment fragment = new ConfirmDialogFragment();
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
return fragment;
|
return fragment;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfirmDialogFragment() {}
|
public ConfirmDialogFragment() {}
|
||||||
@ -55,11 +81,16 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onAttach(@NonNull final Context context) {
|
public void onAttach(@NonNull final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
this.context = context;
|
||||||
final Fragment parentFragment = getParentFragment();
|
final Fragment parentFragment = getParentFragment();
|
||||||
if (parentFragment instanceof ConfirmDialogFragmentCallback) {
|
if (parentFragment instanceof ConfirmDialogFragmentCallback) {
|
||||||
callback = (ConfirmDialogFragmentCallback) parentFragment;
|
callback = (ConfirmDialogFragmentCallback) parentFragment;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final FragmentActivity fragmentActivity = getActivity();
|
||||||
|
if (fragmentActivity instanceof ConfirmDialogFragmentCallback) {
|
||||||
|
callback = (ConfirmDialogFragmentCallback) fragmentActivity;
|
||||||
}
|
}
|
||||||
this.context = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -67,7 +98,7 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
||||||
final Bundle arguments = getArguments();
|
final Bundle arguments = getArguments();
|
||||||
int title = 0;
|
int title = 0;
|
||||||
int message = 0;
|
String message = null;
|
||||||
int neutralButtonText = 0;
|
int neutralButtonText = 0;
|
||||||
int negativeButtonText = 0;
|
int negativeButtonText = 0;
|
||||||
|
|
||||||
@ -75,7 +106,7 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
final int requestCode;
|
final int requestCode;
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
title = arguments.getInt("title", 0);
|
title = arguments.getInt("title", 0);
|
||||||
message = arguments.getInt("message", 0);
|
message = getMessage(arguments);
|
||||||
positiveButtonText = arguments.getInt("positive", defaultPositiveButtonText);
|
positiveButtonText = arguments.getInt("positive", defaultPositiveButtonText);
|
||||||
negativeButtonText = arguments.getInt("negative", 0);
|
negativeButtonText = arguments.getInt("negative", 0);
|
||||||
neutralButtonText = arguments.getInt("neutral", 0);
|
neutralButtonText = arguments.getInt("neutral", 0);
|
||||||
@ -92,7 +123,7 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
if (title != 0) {
|
if (title != 0) {
|
||||||
builder.setTitle(title);
|
builder.setTitle(title);
|
||||||
}
|
}
|
||||||
if (message != 0) {
|
if (message != null) {
|
||||||
builder.setMessage(message);
|
builder.setMessage(message);
|
||||||
}
|
}
|
||||||
if (negativeButtonText != 0) {
|
if (negativeButtonText != 0) {
|
||||||
@ -110,6 +141,19 @@ public class ConfirmDialogFragment extends DialogFragment {
|
|||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getMessage(@NonNull final Bundle arguments) {
|
||||||
|
String message = null;
|
||||||
|
final Object messageObject = arguments.get("message");
|
||||||
|
if (messageObject != null) {
|
||||||
|
if (messageObject instanceof Integer) {
|
||||||
|
message = getString((int) messageObject);
|
||||||
|
} else if (messageObject instanceof String) {
|
||||||
|
message = (String) messageObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
public interface ConfirmDialogFragmentCallback {
|
public interface ConfirmDialogFragmentCallback {
|
||||||
void onPositiveButtonClicked(int requestCode);
|
void onPositiveButtonClicked(int requestCode);
|
||||||
|
|
||||||
|
@ -1,52 +1,81 @@
|
|||||||
package awais.instagrabber.fragments.settings;
|
package awais.instagrabber.fragments.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.widget.AppCompatButton;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.preference.PreferenceViewHolder;
|
|
||||||
import androidx.preference.SwitchPreferenceCompat;
|
import androidx.preference.SwitchPreferenceCompat;
|
||||||
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.dialogs.ConfirmDialogFragment;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
|
|
||||||
|
import static android.app.Activity.RESULT_OK;
|
||||||
|
import static awais.instagrabber.activities.DirectorySelectActivity.SELECT_DIR_REQUEST_CODE;
|
||||||
|
import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER;
|
||||||
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
|
||||||
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
||||||
private static final String TAG = DownloadsPreferencesFragment.class.getSimpleName();
|
private static final String TAG = DownloadsPreferencesFragment.class.getSimpleName();
|
||||||
private SaveToCustomFolderPreference.ResultCallback resultCallback;
|
// private SaveToCustomFolderPreference.ResultCallback resultCallback;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupPreferenceScreen(final PreferenceScreen screen) {
|
void setupPreferenceScreen(final PreferenceScreen screen) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
screen.addPreference(getDownloadUserFolderPreference(context));
|
screen.addPreference(getDownloadUserFolderPreference(context));
|
||||||
// screen.addPreference(getSaveToCustomFolderPreference(context));
|
|
||||||
screen.addPreference(getPrependUsernameToFilenamePreference(context));
|
screen.addPreference(getPrependUsernameToFilenamePreference(context));
|
||||||
|
screen.addPreference(getSaveToCustomFolderPreference(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Preference getDownloadUserFolderPreference(@NonNull final Context context) {
|
private Preference getDownloadUserFolderPreference(@NonNull final Context context) {
|
||||||
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
||||||
preference.setKey(Constants.DOWNLOAD_USER_FOLDER);
|
preference.setKey(DOWNLOAD_USER_FOLDER);
|
||||||
preference.setTitle(R.string.download_user_folder);
|
preference.setTitle(R.string.download_user_folder);
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
return preference;
|
return preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private Preference getSaveToCustomFolderPreference(@NonNull final Context context) {
|
private Preference getSaveToCustomFolderPreference(@NonNull final Context context) {
|
||||||
|
final Preference preference = new Preference(context);
|
||||||
|
preference.setKey(FOLDER_PATH);
|
||||||
|
preference.setIconSpaceReserved(false);
|
||||||
|
preference.setTitle(R.string.barinsta_folder);
|
||||||
|
preference.setSummaryProvider(p -> {
|
||||||
|
final String currentValue = settingsHelper.getString(FOLDER_PATH);
|
||||||
|
if (TextUtils.isEmpty(currentValue)) return "";
|
||||||
|
String path;
|
||||||
|
try {
|
||||||
|
path = URLDecoder.decode(currentValue, StandardCharsets.UTF_8.toString());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
path = currentValue;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
|
openDirectoryChooser(DownloadUtils.getRootDirUri());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return preference;
|
||||||
// return new SaveToCustomFolderPreference(context, checked -> {
|
// return new SaveToCustomFolderPreference(context, checked -> {
|
||||||
// try {
|
// try {
|
||||||
// DownloadUtils.init(context);
|
// DownloadUtils.init(context);
|
||||||
@ -69,40 +98,47 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
|||||||
// // })
|
// // })
|
||||||
// // .show(getParentFragmentManager(), null);
|
// // .show(getParentFragmentManager(), null);
|
||||||
// });
|
// });
|
||||||
// }
|
}
|
||||||
|
|
||||||
// private void startDocumentSelector(final Uri initialUri) {
|
private void openDirectoryChooser(final Uri initialUri) {
|
||||||
// final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && initialUri != null) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && initialUri != null) {
|
||||||
// intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri);
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri);
|
||||||
// }
|
}
|
||||||
// startActivityForResult(intent, SELECT_DIR_REQUEST_CODE);
|
startActivityForResult(intent, SELECT_DIR_REQUEST_CODE);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
||||||
// if (requestCode != SELECT_DIR_REQUEST_CODE) return;
|
if (requestCode != SELECT_DIR_REQUEST_CODE) return;
|
||||||
// final Context context = getContext();
|
if (resultCode != RESULT_OK) return;
|
||||||
// if (context == null) return;
|
if (data == null || data.getData() == null) return;
|
||||||
// if (resultCode != RESULT_OK) {
|
final Context context = getContext();
|
||||||
// try {
|
if (context == null) return;
|
||||||
// DownloadUtils.init(context, true);
|
AppExecutors.getInstance().mainThread().execute(() -> {
|
||||||
// } catch (Exception ignored) {}
|
try {
|
||||||
// return;
|
Utils.setupSelectedDir(context, data);
|
||||||
// }
|
} catch (Exception e) {
|
||||||
// if (data == null || data.getData() == null) return;
|
// Should not come to this point.
|
||||||
// Utils.setupSelectedDir(context, data);
|
// If it does, we have to show this error to the user so that they can report it.
|
||||||
// if (resultCallback != null) {
|
try (final StringWriter sw = new StringWriter();
|
||||||
// try {
|
final PrintWriter pw = new PrintWriter(sw)) {
|
||||||
// final DocumentFile root = DocumentFile.fromTreeUri(context, data.getData());
|
e.printStackTrace(pw);
|
||||||
// resultCallback.onResult(Utils.getDocumentFileRealPath(context, root).getAbsolutePath());
|
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
||||||
// } catch (Exception e) {
|
123,
|
||||||
// Log.e(TAG, "onActivityResult: ", e);
|
R.string.error,
|
||||||
// }
|
"Please report this error to the developers:\n\n" + sw.toString(),
|
||||||
// resultCallback = null;
|
R.string.ok,
|
||||||
// }
|
0,
|
||||||
// // Log.d(TAG, "onActivityResult: " + root);
|
0
|
||||||
// }
|
);
|
||||||
|
dialogFragment.show(getChildFragmentManager(), ConfirmDialogFragment.class.getSimpleName());
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
Log.e(TAG, "onActivityResult: ", ioException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
private Preference getPrependUsernameToFilenamePreference(@NonNull final Context context) {
|
private Preference getPrependUsernameToFilenamePreference(@NonNull final Context context) {
|
||||||
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
|
||||||
@ -112,74 +148,74 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment {
|
|||||||
return preference;
|
return preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SaveToCustomFolderPreference extends Preference {
|
// public static class SaveToCustomFolderPreference extends Preference {
|
||||||
private AppCompatTextView customPathTextView;
|
// private AppCompatTextView customPathTextView;
|
||||||
private final OnSaveToChangeListener onSaveToChangeListener;
|
// private final OnSaveToChangeListener onSaveToChangeListener;
|
||||||
private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener;
|
// private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener;
|
||||||
private final String key;
|
// private final String key;
|
||||||
|
//
|
||||||
public SaveToCustomFolderPreference(final Context context,
|
// public SaveToCustomFolderPreference(final Context context,
|
||||||
final OnSaveToChangeListener onSaveToChangeListener,
|
// final OnSaveToChangeListener onSaveToChangeListener,
|
||||||
final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) {
|
// final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) {
|
||||||
super(context);
|
// super(context);
|
||||||
this.onSaveToChangeListener = onSaveToChangeListener;
|
// this.onSaveToChangeListener = onSaveToChangeListener;
|
||||||
this.onSelectFolderButtonClickListener = onSelectFolderButtonClickListener;
|
// this.onSelectFolderButtonClickListener = onSelectFolderButtonClickListener;
|
||||||
key = FOLDER_SAVE_TO;
|
// key = FOLDER_SAVE_TO;
|
||||||
setLayoutResource(R.layout.pref_custom_folder);
|
// setLayoutResource(R.layout.pref_custom_folder);
|
||||||
setKey(key);
|
// setKey(key);
|
||||||
setTitle(R.string.save_to_folder);
|
// setTitle(R.string.save_to_folder);
|
||||||
setIconSpaceReserved(false);
|
// setIconSpaceReserved(false);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onBindViewHolder(final PreferenceViewHolder holder) {
|
// public void onBindViewHolder(final PreferenceViewHolder holder) {
|
||||||
super.onBindViewHolder(holder);
|
// super.onBindViewHolder(holder);
|
||||||
final SwitchMaterial cbSaveTo = (SwitchMaterial) holder.findViewById(R.id.cbSaveTo);
|
// final SwitchMaterial cbSaveTo = (SwitchMaterial) holder.findViewById(R.id.cbSaveTo);
|
||||||
final View buttonContainer = holder.findViewById(R.id.button_container);
|
// final View buttonContainer = holder.findViewById(R.id.button_container);
|
||||||
customPathTextView = (AppCompatTextView) holder.findViewById(R.id.custom_path);
|
// customPathTextView = (AppCompatTextView) holder.findViewById(R.id.custom_path);
|
||||||
cbSaveTo.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
// cbSaveTo.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
settingsHelper.putBoolean(FOLDER_SAVE_TO, isChecked);
|
// settingsHelper.putBoolean(FOLDER_SAVE_TO, isChecked);
|
||||||
buttonContainer.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
// buttonContainer.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||||
final Context context = getContext();
|
// final Context context = getContext();
|
||||||
String customPath = settingsHelper.getString(FOLDER_PATH);
|
// String customPath = settingsHelper.getString(FOLDER_PATH);
|
||||||
if (!TextUtils.isEmpty(customPath) && customPath.startsWith("content") && context != null) {
|
// if (!TextUtils.isEmpty(customPath) && customPath.startsWith("content") && context != null) {
|
||||||
final Uri uri = Uri.parse(customPath);
|
// final Uri uri = Uri.parse(customPath);
|
||||||
final DocumentFile documentFile = DocumentFile.fromSingleUri(context, uri);
|
// final DocumentFile documentFile = DocumentFile.fromSingleUri(context, uri);
|
||||||
try {
|
// try {
|
||||||
customPath = Utils.getDocumentFileRealPath(context, documentFile).getAbsolutePath();
|
// customPath = Utils.getDocumentFileRealPath(context, documentFile).getAbsolutePath();
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
Log.e(TAG, "onBindViewHolder: ", e);
|
// Log.e(TAG, "onBindViewHolder: ", e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
customPathTextView.setText(customPath);
|
// customPathTextView.setText(customPath);
|
||||||
if (onSaveToChangeListener != null) {
|
// if (onSaveToChangeListener != null) {
|
||||||
onSaveToChangeListener.onChange(isChecked);
|
// onSaveToChangeListener.onChange(isChecked);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
final boolean savedToEnabled = settingsHelper.getBoolean(key);
|
// final boolean savedToEnabled = settingsHelper.getBoolean(key);
|
||||||
holder.itemView.setOnClickListener(v -> cbSaveTo.toggle());
|
// holder.itemView.setOnClickListener(v -> cbSaveTo.toggle());
|
||||||
cbSaveTo.setChecked(savedToEnabled);
|
// cbSaveTo.setChecked(savedToEnabled);
|
||||||
buttonContainer.setVisibility(savedToEnabled ? View.VISIBLE : View.GONE);
|
// buttonContainer.setVisibility(savedToEnabled ? View.VISIBLE : View.GONE);
|
||||||
final AppCompatButton btnSaveTo = (AppCompatButton) holder.findViewById(R.id.btnSaveTo);
|
// final AppCompatButton btnSaveTo = (AppCompatButton) holder.findViewById(R.id.btnSaveTo);
|
||||||
btnSaveTo.setOnClickListener(v -> {
|
// btnSaveTo.setOnClickListener(v -> {
|
||||||
if (onSelectFolderButtonClickListener == null) return;
|
// if (onSelectFolderButtonClickListener == null) return;
|
||||||
onSelectFolderButtonClickListener.onClick(result -> {
|
// onSelectFolderButtonClickListener.onClick(result -> {
|
||||||
if (TextUtils.isEmpty(result)) return;
|
// if (TextUtils.isEmpty(result)) return;
|
||||||
customPathTextView.setText(result);
|
// customPathTextView.setText(result);
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public interface ResultCallback {
|
// public interface ResultCallback {
|
||||||
void onResult(String result);
|
// void onResult(String result);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public interface OnSelectFolderButtonClickListener {
|
// public interface OnSelectFolderButtonClickListener {
|
||||||
void onClick(ResultCallback resultCallback);
|
// void onClick(ResultCallback resultCallback);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public interface OnSaveToChangeListener {
|
// public interface OnSaveToChangeListener {
|
||||||
void onChange(boolean checked);
|
// void onChange(boolean checked);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public final class DownloadUtils {
|
|||||||
// }
|
// }
|
||||||
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH);
|
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH);
|
||||||
if (TextUtils.isEmpty(customPath)) {
|
if (TextUtils.isEmpty(customPath)) {
|
||||||
throw new ReselectDocumentTreeException();
|
throw new ReselectDocumentTreeException("folder path is null or empty");
|
||||||
// root = DOWNLOADS_DIR_FILE; // DocumentFile.fromFile(DOWNLOADS_DIR_FILE);
|
// root = DOWNLOADS_DIR_FILE; // DocumentFile.fromFile(DOWNLOADS_DIR_FILE);
|
||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
@ -92,6 +92,10 @@ public final class DownloadUtils {
|
|||||||
throw new ReselectDocumentTreeException(uri);
|
throw new ReselectDocumentTreeException(uri);
|
||||||
}
|
}
|
||||||
root = DocumentFile.fromTreeUri(context, uri);
|
root = DocumentFile.fromTreeUri(context, uri);
|
||||||
|
if (root == null || !root.exists() || root.lastModified() == 0) {
|
||||||
|
root = null;
|
||||||
|
throw new ReselectDocumentTreeException(uri);
|
||||||
|
}
|
||||||
// Log.d(TAG, "init: " + root);
|
// Log.d(TAG, "init: " + root);
|
||||||
// final File parent = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
// final File parent = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||||
// final DocumentFile documentFile = DocumentFile.fromFile(parent);
|
// final DocumentFile documentFile = DocumentFile.fromFile(parent);
|
||||||
@ -622,6 +626,11 @@ public final class DownloadUtils {
|
|||||||
.enqueue(downloadWorkRequest);
|
.enqueue(downloadWorkRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Uri getRootDirUri() {
|
||||||
|
return root != null ? root.getUri() : null;
|
||||||
|
}
|
||||||
|
|
||||||
public static class ReselectDocumentTreeException extends Exception {
|
public static class ReselectDocumentTreeException extends Exception {
|
||||||
private final Uri initialUri;
|
private final Uri initialUri;
|
||||||
|
|
||||||
@ -629,6 +638,11 @@ public final class DownloadUtils {
|
|||||||
initialUri = null;
|
initialUri = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReselectDocumentTreeException(final String message) {
|
||||||
|
super(message);
|
||||||
|
initialUri = null;
|
||||||
|
}
|
||||||
|
|
||||||
public ReselectDocumentTreeException(final Uri initialUri) {
|
public ReselectDocumentTreeException(final Uri initialUri) {
|
||||||
this.initialUri = initialUri;
|
this.initialUri = initialUri;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
package awais.instagrabber.viewmodels;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.UriPermission;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
|
|
||||||
|
public class DirectorySelectActivityViewModel extends AndroidViewModel {
|
||||||
|
private static final String TAG = DirectorySelectActivityViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
private final MutableLiveData<String> message = new MutableLiveData<>();
|
||||||
|
private final MutableLiveData<String> prevUri = new MutableLiveData<>();
|
||||||
|
private final MutableLiveData<Boolean> loading = new MutableLiveData<>(false);
|
||||||
|
private final MutableLiveData<Boolean> dirSuccess = new MutableLiveData<>(false);
|
||||||
|
|
||||||
|
public DirectorySelectActivityViewModel(final Application application) {
|
||||||
|
super(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<String> getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<String> getPrevUri() {
|
||||||
|
return prevUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> isLoading() {
|
||||||
|
return loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> getDirSuccess() {
|
||||||
|
return dirSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitialUri(final Intent intent) {
|
||||||
|
if (intent == null) {
|
||||||
|
setMessage(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Parcelable initialUriParcelable = intent.getParcelableExtra(Constants.EXTRA_INITIAL_URI);
|
||||||
|
if (!(initialUriParcelable instanceof Uri)) {
|
||||||
|
setMessage(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setMessage((Uri) initialUriParcelable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMessage(@Nullable final Uri initialUri) {
|
||||||
|
if (initialUri == null) {
|
||||||
|
// default message
|
||||||
|
message.postValue(getApplication().getString(R.string.dir_select_default_message));
|
||||||
|
prevUri.postValue(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!initialUri.toString().startsWith("content")) {
|
||||||
|
message.postValue(getApplication().getString(R.string.dir_select_reselect_message));
|
||||||
|
prevUri.postValue(initialUri.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final List<UriPermission> existingPermissions = getApplication().getContentResolver().getPersistedUriPermissions();
|
||||||
|
final boolean anyMatch = existingPermissions.stream().anyMatch(uriPermission -> uriPermission.getUri().equals(initialUri));
|
||||||
|
final DocumentFile documentFile = DocumentFile.fromSingleUri(getApplication(), initialUri);
|
||||||
|
String path;
|
||||||
|
try {
|
||||||
|
path = URLDecoder.decode(initialUri.toString(), StandardCharsets.UTF_8.toString());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
path = initialUri.toString();
|
||||||
|
}
|
||||||
|
if (!anyMatch) {
|
||||||
|
message.postValue(getApplication().getString(R.string.dir_select_permission_revoked_message));
|
||||||
|
prevUri.postValue(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (documentFile == null || !documentFile.exists() || documentFile.lastModified() == 0) {
|
||||||
|
message.postValue(getApplication().getString(R.string.dir_select_folder_not_exist));
|
||||||
|
prevUri.postValue(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupSelectedDir(@NonNull final Intent data) throws DownloadUtils.ReselectDocumentTreeException {
|
||||||
|
loading.postValue(true);
|
||||||
|
try {
|
||||||
|
Utils.setupSelectedDir(getApplication(), data);
|
||||||
|
message.postValue(getApplication().getString(R.string.dir_select_success_message));
|
||||||
|
dirSuccess.postValue(true);
|
||||||
|
} finally {
|
||||||
|
loading.postValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
@ -19,7 +20,55 @@
|
|||||||
android:id="@+id/message"
|
android:id="@+id/message"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/prev_uri"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:layout_goneMarginBottom="0dp"
|
||||||
|
tools:text="@string/dir_select_permission_revoked_message"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/prev_uri"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:padding="8dp"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
android:textColor="@color/blue_500"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/message2"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/message"
|
||||||
|
app:layout_goneMarginBottom="0dp"
|
||||||
|
tools:text="content://something/something/content/content"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/message2"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dir_select_message2"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/prev_uri"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
|
android:id="@+id/loading_indicator"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/select_dir"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||||
@ -29,11 +78,9 @@
|
|||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Select Directory"
|
android:text="@string/select_folder"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
app:layout_constraintTop_toBottomOf="@id/message"
|
|
||||||
app:layout_constraintVertical_bias="1" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -495,4 +495,12 @@
|
|||||||
<string name="copy_reply">Copy reply</string>
|
<string name="copy_reply">Copy reply</string>
|
||||||
<string name="restore">Restore</string>
|
<string name="restore">Restore</string>
|
||||||
<string name="backup">Backup</string>
|
<string name="backup">Backup</string>
|
||||||
|
<string name="dir_select_default_message">Select a folder where Barinsta can store downloads and temporary files.\n\nYou can change this later in More > Settings > Downloads.</string>
|
||||||
|
<string name="dir_select_reselect_message">Android has changed the way apps can access files and directories on storage. Currently Barinsta does not have permission to access the following folder:</string>
|
||||||
|
<string name="dir_select_permission_revoked_message">Permissions for the previously selected folder were revoked by the system:</string>
|
||||||
|
<string name="dir_select_folder_not_exist">The previously selected folder does not exist now:</string>
|
||||||
|
<string name="dir_select_message2">Re-select the directory or select a new directory by clicking the button below.</string>
|
||||||
|
<string name="select_a_folder">No folder selected!</string>
|
||||||
|
<string name="dir_select_success_message">Success! Please wait. Starting app…</string>
|
||||||
|
<string name="barinsta_folder">Barinsta folder</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user