Austin Huang
3 years ago
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
5 changed files with 0 additions and 572 deletions
-
55app/src/main/java/awais/instagrabber/dialogs/CreateBackupDialogFragment.java
-
48app/src/main/java/awais/instagrabber/dialogs/RestoreBackupDialogFragment.java
-
94app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java
-
285app/src/main/java/awais/instagrabber/utils/DirectoryChooser.java
-
90app/src/main/java/awais/instagrabber/utils/DirectoryUtils.java
@ -1,285 +0,0 @@ |
|||
package awais.instagrabber.utils; |
|||
|
|||
import android.app.Activity; |
|||
import android.app.Dialog; |
|||
import android.content.Context; |
|||
import android.graphics.drawable.Drawable; |
|||
import android.os.Bundle; |
|||
import android.os.Environment; |
|||
import android.os.FileObserver; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.fragment.app.DialogFragment; |
|||
import androidx.fragment.app.Fragment; |
|||
import androidx.lifecycle.ViewModelProvider; |
|||
import androidx.recyclerview.widget.LinearLayoutManager; |
|||
|
|||
import java.io.File; |
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
import awais.instagrabber.R; |
|||
import awais.instagrabber.adapters.DirectoryFilesAdapter; |
|||
import awais.instagrabber.databinding.LayoutDirectoryChooserBinding; |
|||
import awais.instagrabber.viewmodels.FileListViewModel; |
|||
|
|||
public final class DirectoryChooser extends DialogFragment { |
|||
private static final String TAG = "DirectoryChooser"; |
|||
|
|||
public static final String KEY_CURRENT_DIRECTORY = "CURRENT_DIRECTORY"; |
|||
private static final File sdcardPathFile = Environment.getExternalStorageDirectory(); |
|||
private static final String sdcardPath = sdcardPathFile.getPath(); |
|||
|
|||
private Context context; |
|||
private LayoutDirectoryChooserBinding binding; |
|||
private FileObserver fileObserver; |
|||
private File selectedDir; |
|||
private String initialDirectory; |
|||
private OnFragmentInteractionListener interactionListener; |
|||
private boolean showBackupFiles = false; |
|||
private View.OnClickListener navigationOnClickListener; |
|||
private FileListViewModel fileListViewModel; |
|||
private OnCancelListener onCancelListener; |
|||
|
|||
public DirectoryChooser() { |
|||
super(); |
|||
} |
|||
|
|||
public DirectoryChooser setInitialDirectory(final String initialDirectory) { |
|||
if (!TextUtils.isEmpty(initialDirectory)) |
|||
this.initialDirectory = initialDirectory; |
|||
return this; |
|||
} |
|||
|
|||
public DirectoryChooser setShowBackupFiles(final boolean showBackupFiles) { |
|||
this.showBackupFiles = showBackupFiles; |
|||
return this; |
|||
} |
|||
|
|||
@Override |
|||
public void onAttach(@NonNull final Context context) { |
|||
super.onAttach(context); |
|||
|
|||
this.context = context; |
|||
|
|||
if (this.context instanceof OnFragmentInteractionListener) |
|||
interactionListener = (OnFragmentInteractionListener) this.context; |
|||
else { |
|||
final Fragment owner = getTargetFragment(); |
|||
if (owner instanceof OnFragmentInteractionListener) |
|||
interactionListener = (OnFragmentInteractionListener) owner; |
|||
} |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { |
|||
binding = LayoutDirectoryChooserBinding.inflate(inflater, container, false); |
|||
init(container); |
|||
return binding.getRoot(); |
|||
} |
|||
|
|||
private void init(final ViewGroup container) { |
|||
Context context = this.context; |
|||
if (context == null) context = getContext(); |
|||
if (context == null) context = getActivity(); |
|||
if (context == null) return; |
|||
// if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) != PackageManager.PERMISSION_GRANTED) { |
|||
// final String text = "Storage permissions denied!"; |
|||
// if (container == null) { |
|||
// Toast.makeText(context, text, Toast.LENGTH_LONG).show(); |
|||
// } else { |
|||
// Snackbar.make(container, text, BaseTransientBottomBar.LENGTH_LONG).show(); |
|||
// } |
|||
// dismiss(); |
|||
// } |
|||
final View.OnClickListener clickListener = v -> { |
|||
if (v == binding.btnConfirm) { |
|||
if (interactionListener != null && isValidFile(selectedDir)) |
|||
interactionListener.onSelectDirectory(selectedDir); |
|||
dismiss(); |
|||
} else if (v == binding.btnCancel) { |
|||
if (onCancelListener != null) { |
|||
onCancelListener.onCancel(); |
|||
} |
|||
dismiss(); |
|||
} |
|||
}; |
|||
|
|||
navigationOnClickListener = v -> { |
|||
final File parent; |
|||
if (selectedDir != null && (parent = selectedDir.getParentFile()) != null) { |
|||
changeDirectory(parent); |
|||
} |
|||
}; |
|||
binding.toolbar.setNavigationOnClickListener(navigationOnClickListener); |
|||
binding.toolbar.setSubtitle(showBackupFiles ? R.string.select_backup_file : R.string.select_folder); |
|||
binding.btnCancel.setOnClickListener(clickListener); |
|||
// no need to show confirm for file picker |
|||
binding.btnConfirm.setVisibility(showBackupFiles ? View.GONE : View.VISIBLE); |
|||
if (!showBackupFiles) { |
|||
binding.btnConfirm.setOnClickListener(clickListener); |
|||
} |
|||
fileListViewModel = new ViewModelProvider(this).get(FileListViewModel.class); |
|||
final DirectoryFilesAdapter listDirectoriesAdapter = new DirectoryFilesAdapter(file -> { |
|||
if (file.isDirectory()) { |
|||
changeDirectory(file); |
|||
return; |
|||
} |
|||
if (showBackupFiles && file.isFile()) { |
|||
if (interactionListener != null && file.canRead()) { |
|||
interactionListener.onSelectDirectory(file); |
|||
} |
|||
dismiss(); |
|||
} |
|||
}); |
|||
fileListViewModel.getList().observe(this, listDirectoriesAdapter::submitList); |
|||
binding.directoryList.setLayoutManager(new LinearLayoutManager(context)); |
|||
binding.directoryList.setAdapter(listDirectoriesAdapter); |
|||
final File initDir = new File(initialDirectory); |
|||
final File initialDir = !TextUtils.isEmpty(initialDirectory) && isValidFile(initDir) ? initDir : Environment.getExternalStorageDirectory(); |
|||
changeDirectory(initialDir); |
|||
} |
|||
|
|||
@Override |
|||
public void onCreate(@Nullable final Bundle savedInstanceState) { |
|||
super.onCreate(savedInstanceState); |
|||
|
|||
if (TextUtils.isEmpty(initialDirectory)) { |
|||
initialDirectory = new File(sdcardPath, "Download").getAbsolutePath(); |
|||
if (savedInstanceState != null) { |
|||
final String savedDir = savedInstanceState.getString(KEY_CURRENT_DIRECTORY); |
|||
if (!TextUtils.isEmpty(savedDir)) initialDirectory = savedDir; |
|||
} |
|||
} |
|||
|
|||
setStyle(DialogFragment.STYLE_NO_TITLE, 0); |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public Dialog onCreateDialog(final Bundle savedInstanceState) { |
|||
return new Dialog(context, R.attr.alertDialogTheme) { |
|||
@Override |
|||
public void onBackPressed() { |
|||
if (selectedDir != null) { |
|||
final String absolutePath = selectedDir.getAbsolutePath(); |
|||
if (absolutePath.equals(sdcardPath) || absolutePath.equals(sdcardPathFile.getAbsolutePath())) { |
|||
if (onCancelListener != null) { |
|||
onCancelListener.onCancel(); |
|||
} |
|||
dismiss(); |
|||
} else { |
|||
changeDirectory(selectedDir.getParentFile()); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
|
|||
@Override |
|||
public void onSaveInstanceState(@NonNull final Bundle outState) { |
|||
super.onSaveInstanceState(outState); |
|||
if (selectedDir != null) outState.putString(KEY_CURRENT_DIRECTORY, selectedDir.getAbsolutePath()); |
|||
} |
|||
|
|||
@Override |
|||
public void onResume() { |
|||
super.onResume(); |
|||
if (fileObserver != null) fileObserver.startWatching(); |
|||
} |
|||
|
|||
@Override |
|||
public void onPause() { |
|||
super.onPause(); |
|||
if (fileObserver != null) fileObserver.stopWatching(); |
|||
} |
|||
|
|||
@Override |
|||
public void onDetach() { |
|||
super.onDetach(); |
|||
interactionListener = null; |
|||
} |
|||
|
|||
private void changeDirectory(final File dir) { |
|||
if (dir != null && dir.isDirectory()) { |
|||
final String path = dir.getAbsolutePath(); |
|||
binding.toolbar.setTitle(path); |
|||
final File[] contents = dir.listFiles(); |
|||
if (contents != null) { |
|||
final List<File> fileNames = new ArrayList<>(); |
|||
for (final File f : contents) { |
|||
final String name = f.getName(); |
|||
final String nameLowerCase = name.toLowerCase(); |
|||
final boolean isBackupFile = nameLowerCase.endsWith(".zaai") || nameLowerCase.endsWith(".backup"); |
|||
if (f.isDirectory() || (showBackupFiles && f.isFile() && isBackupFile)) |
|||
fileNames.add(f); |
|||
} |
|||
Collections.sort(fileNames, (o1, o2) -> { |
|||
if ((o1.isDirectory() && o2.isDirectory()) |
|||
|| (o1.isFile() && o2.isFile())) { |
|||
return o1.getName().compareToIgnoreCase(o2.getName()); |
|||
} |
|||
if (o1.isDirectory()) return -1; |
|||
if (o2.isDirectory()) return 1; |
|||
return 0; |
|||
}); |
|||
fileListViewModel.getList().postValue(fileNames); |
|||
selectedDir = dir; |
|||
fileObserver = new FileObserver(path, FileObserver.CREATE | FileObserver.DELETE | FileObserver.MOVED_FROM | FileObserver.MOVED_TO) { |
|||
private final Runnable currentDirRefresher = () -> changeDirectory(selectedDir); |
|||
|
|||
@Override |
|||
public void onEvent(final int event, final String path) { |
|||
if (context instanceof Activity) ((Activity) context).runOnUiThread(currentDirRefresher); |
|||
} |
|||
}; |
|||
fileObserver.startWatching(); |
|||
} |
|||
} |
|||
refreshButtonState(); |
|||
} |
|||
|
|||
private void refreshButtonState() { |
|||
if (selectedDir != null) { |
|||
final String path = selectedDir.getAbsolutePath(); |
|||
toggleUpButton(!path.equals(sdcardPathFile.getAbsolutePath()) && selectedDir != sdcardPathFile); |
|||
binding.btnConfirm.setEnabled(isValidFile(selectedDir)); |
|||
} |
|||
} |
|||
|
|||
private void toggleUpButton(final boolean enable) { |
|||
binding.toolbar.setNavigationOnClickListener(enable ? navigationOnClickListener : null); |
|||
final Drawable navigationIcon = binding.toolbar.getNavigationIcon(); |
|||
if (navigationIcon == null) return; |
|||
navigationIcon.setAlpha(enable ? 255 : (int) (255 * 0.617)); |
|||
} |
|||
|
|||
private boolean isValidFile(final File file) { |
|||
return file != null && file.isDirectory() && file.canRead(); |
|||
} |
|||
|
|||
public DirectoryChooser setInteractionListener(final OnFragmentInteractionListener interactionListener) { |
|||
this.interactionListener = interactionListener; |
|||
return this; |
|||
} |
|||
|
|||
public void setOnCancelListener(final OnCancelListener onCancelListener) { |
|||
if (onCancelListener != null) { |
|||
this.onCancelListener = onCancelListener; |
|||
} |
|||
} |
|||
|
|||
public interface OnCancelListener { |
|||
void onCancel(); |
|||
} |
|||
|
|||
public interface OnFragmentInteractionListener { |
|||
void onSelectDirectory(final File file); |
|||
} |
|||
} |
@ -1,90 +0,0 @@ |
|||
package awais.instagrabber.utils; |
|||
|
|||
import android.os.Environment; |
|||
|
|||
import java.io.File; |
|||
import java.util.Collections; |
|||
import java.util.HashSet; |
|||
import java.util.Set; |
|||
import java.util.regex.Pattern; |
|||
|
|||
public class DirectoryUtils { |
|||
private static final Pattern DIR_SEPORATOR = Pattern.compile("/"); |
|||
|
|||
/** |
|||
* From: https://stackoverflow.com/a/18871043/1436766 |
|||
* <p> |
|||
* Returns all available SD-Cards in the system (include emulated) |
|||
* <p> |
|||
* Warning: Hack! Based on Android source code of version 4.3 (API 18) |
|||
* Because there is no standard way to get it. |
|||
* TODO: Test on future Android versions 4.4+ |
|||
* |
|||
* @return paths to all available SD-Cards in the system (include emulated) |
|||
*/ |
|||
public static Set<String> getStorageDirectories() { |
|||
// Final set of paths |
|||
final Set<String> rv = new HashSet<>(); |
|||
// Primary physical SD-CARD (not emulated) |
|||
final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE"); |
|||
// All Secondary SD-CARDs (all exclude primary) separated by ":" |
|||
final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE"); |
|||
// Primary emulated SD-CARD |
|||
final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET"); |
|||
if (TextUtils.isEmpty(rawEmulatedStorageTarget)) { |
|||
// Device has physical external storage; use plain paths. |
|||
if (TextUtils.isEmpty(rawExternalStorage)) { |
|||
// EXTERNAL_STORAGE undefined; falling back to default. |
|||
rv.add("/storage/sdcard0"); |
|||
} else { |
|||
rv.add(rawExternalStorage); |
|||
} |
|||
} else { |
|||
// Device has emulated storage; external storage paths should have |
|||
// userId burned into them. |
|||
final String rawUserId; |
|||
final String path = Environment.getExternalStorageDirectory().getAbsolutePath(); |
|||
final String[] folders = DIR_SEPORATOR.split(path); |
|||
final String lastFolder = folders[folders.length - 1]; |
|||
boolean isDigit = false; |
|||
try { |
|||
Integer.valueOf(lastFolder); |
|||
isDigit = true; |
|||
} catch (NumberFormatException ignored) { |
|||
} |
|||
rawUserId = isDigit ? lastFolder : ""; |
|||
// /storage/emulated/0[1,2,...] |
|||
if (TextUtils.isEmpty(rawUserId)) { |
|||
rv.add(rawEmulatedStorageTarget); |
|||
} else { |
|||
rv.add(rawEmulatedStorageTarget + File.separator + rawUserId); |
|||
} |
|||
} |
|||
// Add all secondary storages |
|||
if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) { |
|||
// All Secondary SD-CARDs splited into array |
|||
final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator); |
|||
Collections.addAll(rv, rawSecondaryStorages); |
|||
} |
|||
return rv; |
|||
} |
|||
|
|||
// public static File getOutputMediaDirectory(final Context context, final String... dirs) { |
|||
// if (context == null) return null; |
|||
// final File[] externalMediaDirs = context.getExternalMediaDirs(); |
|||
// if (externalMediaDirs == null || externalMediaDirs.length == 0) return context.getFilesDir(); |
|||
// final File externalMediaDir = externalMediaDirs[0]; |
|||
// File subDir = new File(externalMediaDir, context.getString(R.string.app_name)); |
|||
// if (dirs != null) { |
|||
// for (final String dir : dirs) { |
|||
// subDir = new File(subDir, dir); |
|||
// //noinspection ResultOfMethodCallIgnored |
|||
// subDir.mkdirs(); |
|||
// } |
|||
// } |
|||
// if (!subDir.exists()) { |
|||
// return context.getFilesDir(); |
|||
// } |
|||
// return subDir; |
|||
// } |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue