From 9b691a453e8b1794396cb160ed551608128fa885 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 4 Apr 2021 23:53:10 +0900 Subject: [PATCH] Remove read/write storage permissions. Add an activity to select directory. --- app/src/main/AndroidManifest.xml | 5 +- .../instagrabber/InstaGrabberApplication.java | 6 +- .../activities/DirectDownload.java | 13 +- .../activities/DirectorySelectActivity.java | 128 ++++++++++++++++++ .../instagrabber/activities/MainActivity.java | 26 +++- .../dialogs/CreateBackupDialogFragment.java | 2 +- .../dialogs/ProfilePicDialogFragment.java | 11 +- .../fragments/CollectionPostsFragment.java | 46 +++---- .../fragments/HashTagFragment.java | 81 ++++++----- .../fragments/LocationFragment.java | 87 ++++++------ .../fragments/PostViewV2Fragment.java | 13 +- .../fragments/SavedViewerFragment.java | 29 ++-- .../fragments/StoryViewerFragment.java | 18 ++- .../fragments/TopicPostsFragment.java | 32 ++--- .../DirectMessageThreadFragment.java | 15 +- .../fragments/main/FeedFragment.java | 30 ++-- .../fragments/main/ProfileFragment.java | 29 ++-- .../DownloadsPreferencesFragment.java | 120 ++++++++++------ .../awais/instagrabber/utils/Constants.java | 20 +-- .../instagrabber/utils/DirectoryChooser.java | 24 ++-- .../instagrabber/utils/DownloadUtils.java | 121 +++++++++++++---- .../java/awais/instagrabber/utils/Utils.java | 89 ++++++++++-- .../viewmodels/DirectThreadViewModel.java | 2 +- .../res/layout/activity_directory_select.xml | 39 ++++++ 24 files changed, 649 insertions(+), 337 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java create mode 100644 app/src/main/res/layout/activity_directory_select.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a958a9a3..48326842 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,8 +4,8 @@ package="awais.instagrabber"> - - + + @@ -133,6 +133,7 @@ + requestListeners = new HashSet<>(); // requestListeners.add(new RequestLoggingListener()); final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig @@ -90,6 +87,5 @@ public final class InstaGrabberApplication extends Application { if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) { settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString()); } - DownloadUtils.init(this); } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/activities/DirectDownload.java b/app/src/main/java/awais/instagrabber/activities/DirectDownload.java index e2d30743..94e02280 100644 --- a/app/src/main/java/awais/instagrabber/activities/DirectDownload.java +++ b/app/src/main/java/awais/instagrabber/activities/DirectDownload.java @@ -1,6 +1,5 @@ package awais.instagrabber.activities; -import android.Manifest; import android.app.Notification; import android.content.Context; import android.content.Intent; @@ -14,10 +13,8 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; -import androidx.core.content.ContextCompat; import awais.instagrabber.R; import awais.instagrabber.asyncs.PostFetcher; @@ -74,11 +71,11 @@ public final class DirectDownload extends AppCompatActivity { } private synchronized void checkPermissions() { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - doDownload(); - return; - } - ActivityCompat.requestPermissions(this, DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + doDownload(); + // return; + // } + // ActivityCompat.requestPermissions(this, DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override diff --git a/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java b/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java new file mode 100644 index 00000000..c45338a0 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/activities/DirectorySelectActivity.java @@ -0,0 +1,128 @@ +package awais.instagrabber.activities; + +import android.content.Intent; +import android.content.UriPermission; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcelable; +import android.provider.DocumentsContract; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.documentfile.provider.DocumentFile; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import awais.instagrabber.databinding.ActivityDirectorySelectBinding; +import awais.instagrabber.utils.AppExecutors; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.Utils; + +public class DirectorySelectActivity extends BaseLanguageActivity { + private static final String TAG = DirectorySelectActivity.class.getSimpleName(); + + public static final int SELECT_DIR_REQUEST_CODE = 1090; + + private Uri initialUri; + private ActivityDirectorySelectBinding binding; + + @Override + protected void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = ActivityDirectorySelectBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + binding.selectDir.setOnClickListener(v -> openDirectoryChooser()); + setInitialUri(); + } + + private void setInitialUri() { + AppExecutors.getInstance().mainThread().execute(() -> { + final Intent intent = getIntent(); + if (intent == null) { + setMessage(); + return; + } + final Parcelable initialUriParcelable = intent.getParcelableExtra(Constants.EXTRA_INITIAL_URI); + if (!(initialUriParcelable instanceof Uri)) { + setMessage(); + return; + } + initialUri = (Uri) initialUriParcelable; + setMessage(); + }); + } + + 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 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() { + final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && initialUri != null) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri); + } + startActivityForResult(intent, SELECT_DIR_REQUEST_CODE); + } + + @Override + protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode != SELECT_DIR_REQUEST_CODE) return; + if (resultCode != RESULT_OK) { + // Show error + return; + } + if (data == null || data.getData() == null) { + // show error + return; + } + try { + Utils.setupSelectedDir(this, data); + } catch (Exception e) { + // show error + } + } +} diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 3459d632..fb2d8e6c 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -79,6 +79,7 @@ import awais.instagrabber.services.DMSyncAlarmReceiver; import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; +import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.FlavorTown; import awais.instagrabber.utils.IntentUtils; import awais.instagrabber.utils.TextUtils; @@ -92,6 +93,7 @@ import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; +import static awais.instagrabber.utils.Constants.EXTRA_INITIAL_URI; import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -134,6 +136,16 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { + try { + DownloadUtils.init(this); + } catch (DownloadUtils.ReselectDocumentTreeException e) { + super.onCreate(savedInstanceState); + final Intent intent = new Intent(this, DirectorySelectActivity.class); + intent.putExtra(EXTRA_INITIAL_URI, e.getInitialUri()); + startActivity(intent); + finish(); + return; + } RetrofitFactory.setup(this); super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); @@ -221,7 +233,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage @Override protected void onSaveInstanceState(@NonNull final Bundle outState) { outState.putString(FIRST_FRAGMENT_GRAPH_INDEX_KEY, String.valueOf(firstFragmentGraphIndex)); - outState.putString(LAST_SELECT_NAV_MENU_ID, String.valueOf(binding.bottomNavView.getSelectedItemId())); + if (binding != null) { + outState.putString(LAST_SELECT_NAV_MENU_ID, String.valueOf(binding.bottomNavView.getSelectedItemId())); + } super.onSaveInstanceState(outState); } @@ -265,7 +279,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage Log.e(TAG, "onDestroy: ", e); } unbindActivityCheckerService(); - RetrofitFactory.getInstance().destroy(); + try { + RetrofitFactory.getInstance().destroy(); + } catch (Exception ignored) {} } @Override @@ -916,9 +932,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage return currentTabs; } -// public boolean isNavRootInCurrentTabs(@IdRes final int navRootId) { -// return showBottomViewDestinations.stream().anyMatch(id -> id == navRootId); -// } + // public boolean isNavRootInCurrentTabs(@IdRes final int navRootId) { + // return showBottomViewDestinations.stream().anyMatch(id -> id == navRootId); + // } private void setNavBarDMUnreadCountBadge(final int unseenCount) { final BadgeDrawable badge = binding.bottomNavView.getOrCreateBadge(R.id.direct_messages_nav_graph); diff --git a/app/src/main/java/awais/instagrabber/dialogs/CreateBackupDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/CreateBackupDialogFragment.java index 2cbd0224..132d75a4 100644 --- a/app/src/main/java/awais/instagrabber/dialogs/CreateBackupDialogFragment.java +++ b/app/src/main/java/awais/instagrabber/dialogs/CreateBackupDialogFragment.java @@ -213,7 +213,7 @@ public class CreateBackupDialogFragment extends DialogFragment { // Optionally, specify a URI for the directory that should be opened in // the system file picker when your app creates the document. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, DownloadUtils.getDownloadDir().getUri()); + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, DownloadUtils.getBackupsDir().getUri()); } startActivityForResult(intent, CREATE_FILE_REQUEST_CODE); diff --git a/app/src/main/java/awais/instagrabber/dialogs/ProfilePicDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/ProfilePicDialogFragment.java index 9df1e552..eb8a0247 100644 --- a/app/src/main/java/awais/instagrabber/dialogs/ProfilePicDialogFragment.java +++ b/app/src/main/java/awais/instagrabber/dialogs/ProfilePicDialogFragment.java @@ -15,7 +15,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; import androidx.documentfile.provider.DocumentFile; import androidx.fragment.app.DialogFragment; @@ -109,11 +108,11 @@ public class ProfilePicDialogFragment extends DialogFragment { binding.download.setOnClickListener(v -> { final Context context = getContext(); if (context == null) return; - if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) { - downloadProfilePicture(); - return; - } - requestPermissions(DownloadUtils.PERMS, 8020); + // if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) { + downloadProfilePicture(); + // return; + // } + // requestPermissions(DownloadUtils.PERMS, 8020); }); } diff --git a/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java b/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java index 9a850045..ab7190c8 100644 --- a/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java @@ -27,7 +27,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.PermissionChecker; import androidx.core.graphics.ColorUtils; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; @@ -65,9 +64,6 @@ import awais.instagrabber.utils.Utils; import awais.instagrabber.webservices.CollectionService; import awais.instagrabber.webservices.ServiceCallback; -import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; - public class CollectionPostsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "CollectionPostsFragment"; private static final int STORAGE_PERM_REQUEST_CODE = 8020; @@ -105,12 +101,12 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay if (CollectionPostsFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(CollectionPostsFragment.this.selectedFeedModels)); - binding.posts.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(CollectionPostsFragment.this.selectedFeedModels)); + binding.posts.endSelection(); + // return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); } return false; } @@ -140,13 +136,13 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = -1; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = -1; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override @@ -288,8 +284,7 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay if (item.getItemId() == R.id.layout) { showPostsLayoutPreferences(); return true; - } - else if (item.getItemId() == R.id.delete) { + } else if (item.getItemId() == R.id.delete) { final Context context = getContext(); new AlertDialog.Builder(context) .setTitle(R.string.delete_collection) @@ -309,15 +304,13 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay Log.e(TAG, "Error deleting collection", t); try { Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(final Throwable e) {} + } catch (final Throwable e) {} } }); }) .setNegativeButton(R.string.cancel, null) .show(); - } - else if (item.getItemId() == R.id.edit) { + } else if (item.getItemId() == R.id.edit) { final Context context = getContext(); final EditText input = new EditText(context); new AlertDialog.Builder(context) @@ -339,8 +332,7 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay Log.e(TAG, "Error editing collection", t); try { Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(final Throwable e) {} + } catch (final Throwable e) {} } }); }) @@ -443,8 +435,8 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay private void setupCover() { final String coverUrl = ResponseBodyUtils.getImageUrl(savedCollection.getCoverMedias() == null - ? savedCollection.getCoverMedia() - : savedCollection.getCoverMedias().get(0)); + ? savedCollection.getCoverMedia() + : savedCollection.getCoverMedias().get(0)); final DraweeController controller = Fresco .newDraweeControllerBuilder() .setOldController(binding.cover.getController()) diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 3f974816..d43101c7 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -24,7 +24,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.NavDirections; @@ -70,8 +69,6 @@ import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesService; import awais.instagrabber.webservices.TagsService; -import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { @@ -121,13 +118,13 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe if (HashTagFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(HashTagFragment.this.selectedFeedModels)); - binding.posts.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(HashTagFragment.this.selectedFeedModels)); + binding.posts.endSelection(); return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // return true; } return false; } @@ -157,13 +154,13 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = childPosition; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = childPosition; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override @@ -400,8 +397,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe try { Toast.makeText(getContext(), R.string.error_loading_hashtag, Toast.LENGTH_SHORT).show(); binding.swipeRefreshLayout.setEnabled(false); - } - catch (Exception ignored) {} + } catch (Exception ignored) {} return; } setTitle(); @@ -428,31 +424,32 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe userId, deviceUuid, new ServiceCallback() { - @Override - public void onSuccess(final Boolean result) { - hashtagDetailsBinding.btnFollowTag.setClickable(true); - if (!result) { - Log.e(TAG, "onSuccess: result is false"); - Snackbar.make(root, R.string.downloader_unknown_error, BaseTransientBottomBar.LENGTH_LONG) - .show(); - return; - } - hashtagDetailsBinding.btnFollowTag.setText(R.string.unfollow); - hashtagDetailsBinding.btnFollowTag.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24); - } + @Override + public void onSuccess(final Boolean result) { + hashtagDetailsBinding.btnFollowTag.setClickable(true); + if (!result) { + Log.e(TAG, "onSuccess: result is false"); + Snackbar.make(root, R.string.downloader_unknown_error, BaseTransientBottomBar.LENGTH_LONG) + .show(); + return; + } + hashtagDetailsBinding.btnFollowTag.setText(R.string.unfollow); + hashtagDetailsBinding.btnFollowTag + .setChipIconResource(R.drawable.ic_outline_person_add_disabled_24); + } - @Override - public void onFailure(@NonNull final Throwable t) { - hashtagDetailsBinding.btnFollowTag.setClickable(true); - Log.e(TAG, "onFailure: ", t); - final String message = t.getMessage(); - Snackbar.make(root, - message != null ? message - : getString(R.string.downloader_unknown_error), - BaseTransientBottomBar.LENGTH_LONG) - .show(); - } - }); + @Override + public void onFailure(@NonNull final Throwable t) { + hashtagDetailsBinding.btnFollowTag.setClickable(true); + Log.e(TAG, "onFailure: ", t); + final String message = t.getMessage(); + Snackbar.make(root, + message != null ? message + : getString(R.string.downloader_unknown_error), + BaseTransientBottomBar.LENGTH_LONG) + .show(); + } + }); return; } }); diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index c42809c5..c8e15e1e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -22,7 +22,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.NavDirections; @@ -66,13 +65,8 @@ import awais.instagrabber.webservices.LocationService; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesService; -import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; -//import awaisomereport.LogCollector; -//import static awais.instagrabber.utils.Utils.logCollector; - public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "LocationFragment"; private static final int STORAGE_PERM_REQUEST_CODE = 8020; @@ -118,12 +112,12 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR if (LocationFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(LocationFragment.this.selectedFeedModels)); - binding.posts.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(LocationFragment.this.selectedFeedModels)); + binding.posts.endSelection(); + return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); } return false; } @@ -153,13 +147,13 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = childPosition; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = childPosition; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override @@ -399,8 +393,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR try { Toast.makeText(getContext(), R.string.error_loading_location, Toast.LENGTH_SHORT).show(); binding.swipeRefreshLayout.setEnabled(false); - } - catch (Exception ignored) {} + } catch (Exception ignored) {} return; } setTitle(); @@ -409,16 +402,16 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR final long locationId = locationModel.getPk(); // binding.swipeRefreshLayout.setRefreshing(true); locationDetailsBinding.mainLocationImage.setImageURI("res:/" + R.drawable.ic_location); -// final String postCount = String.valueOf(locationModel.getCount()); -// final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, -// locationModel.getPostCount() > 2000000000L -// ? 2000000000 -// : locationModel.getPostCount().intValue(), -// postCount)); -// span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); -// span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); -// locationDetailsBinding.mainLocPostCount.setText(span); -// locationDetailsBinding.mainLocPostCount.setVisibility(View.VISIBLE); + // final String postCount = String.valueOf(locationModel.getCount()); + // final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, + // locationModel.getPostCount() > 2000000000L + // ? 2000000000 + // : locationModel.getPostCount().intValue(), + // postCount)); + // span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); + // span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); + // locationDetailsBinding.mainLocPostCount.setText(span); + // locationDetailsBinding.mainLocPostCount.setVisibility(View.VISIBLE); locationDetailsBinding.locationFullName.setText(locationModel.getName()); CharSequence biography = locationModel.getAddress() + "\n" + locationModel.getCity(); // binding.locationBiography.setCaptionIsExpandable(true); @@ -431,22 +424,22 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR } else { locationDetailsBinding.locationBiography.setVisibility(View.VISIBLE); locationDetailsBinding.locationBiography.setText(biography); -// locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> { -// final NavController navController = NavHostFragment.findNavController(this); -// final Bundle bundle = new Bundle(); -// final String originalText = autoLinkItem.getOriginalText().trim(); -// bundle.putString(ARG_HASHTAG, originalText); -// navController.navigate(R.id.action_global_hashTagFragment, bundle); -// }); -// locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> { -// final String originalText = autoLinkItem.getOriginalText().trim(); -// navigateToProfile(originalText); -// }); -// locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(context, -// autoLinkItem.getOriginalText() -// .trim())); -// locationDetailsBinding.locationBiography -// .addOnURLClickListener(autoLinkItem -> Utils.openURL(context, autoLinkItem.getOriginalText().trim())); + // locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> { + // final NavController navController = NavHostFragment.findNavController(this); + // final Bundle bundle = new Bundle(); + // final String originalText = autoLinkItem.getOriginalText().trim(); + // bundle.putString(ARG_HASHTAG, originalText); + // navController.navigate(R.id.action_global_hashTagFragment, bundle); + // }); + // locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> { + // final String originalText = autoLinkItem.getOriginalText().trim(); + // navigateToProfile(originalText); + // }); + // locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(context, + // autoLinkItem.getOriginalText() + // .trim())); + // locationDetailsBinding.locationBiography + // .addOnURLClickListener(autoLinkItem -> Utils.openURL(context, autoLinkItem.getOriginalText().trim())); locationDetailsBinding.locationBiography.setOnLongClickListener(v -> { Utils.copyText(context, biography); return true; diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 0d0c7865..9a349418 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -43,7 +43,6 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.widget.PopupMenu; import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.content.PermissionChecker; import androidx.core.view.ViewCompat; import androidx.core.widget.NestedScrollView; import androidx.fragment.app.DialogFragment; @@ -100,9 +99,7 @@ import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.viewmodels.PostViewV2ViewModel; -import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; public class PostViewV2Fragment extends SharedElementTransitionDialogFragment implements EditTextDialogFragment.EditTextDialogFragmentCallback { @@ -622,11 +619,11 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void setupDownload() { binding.download.setOnClickListener(v -> { - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, viewModel.getMedia(), sliderPosition); - return; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, viewModel.getMedia(), sliderPosition); + // return; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); }); binding.download.setOnLongClickListener(v -> { Utils.displayToastAboveView(context, v, getString(R.string.action_download)); diff --git a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java index b6ee5431..456c82d1 100644 --- a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java @@ -18,7 +18,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.NavDirections; @@ -45,8 +44,6 @@ import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; -import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; public final class SavedViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { @@ -86,12 +83,12 @@ public final class SavedViewerFragment extends Fragment implements SwipeRefreshL if (SavedViewerFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(SavedViewerFragment.this.selectedFeedModels)); - binding.posts.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(SavedViewerFragment.this.selectedFeedModels)); + binding.posts.endSelection(); + // return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); } return false; } @@ -121,13 +118,13 @@ public final class SavedViewerFragment extends Fragment implements SwipeRefreshL public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = childPosition; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = childPosition; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 6de66afe..60e62f80 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -29,8 +29,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; import androidx.core.view.GestureDetectorCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModel; @@ -210,10 +208,10 @@ public class StoryViewerFragment extends Fragment { if (context == null) return false; int itemId = item.getItemId(); if (itemId == R.id.action_download) { - if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) - downloadStory(); - else - ActivityCompat.requestPermissions(requireActivity(), DownloadUtils.PERMS, 8020); + // if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) + downloadStory(); + // else + // ActivityCompat.requestPermissions(requireActivity(), DownloadUtils.PERMS, 8020); return true; } if (itemId == R.id.action_dms) { @@ -415,10 +413,10 @@ public class StoryViewerFragment extends Fragment { return true; } } catch (final Exception e) { -// if (logCollector != null) -// logCollector.appendException(e, LogCollector.LogFile.ACTIVITY_STORY_VIEWER, "setupListeners", -// new Pair<>("swipeEvent", swipeEvent), -// new Pair<>("diffX", diffX)); + // if (logCollector != null) + // logCollector.appendException(e, LogCollector.LogFile.ACTIVITY_STORY_VIEWER, "setupListeners", + // new Pair<>("swipeEvent", swipeEvent), + // new Pair<>("diffX", diffX)); if (BuildConfig.DEBUG) Log.e(TAG, "Error", e); } return false; diff --git a/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java b/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java index 9b680d64..3a87b4e6 100644 --- a/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java @@ -23,7 +23,6 @@ import androidx.activity.OnBackPressedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.PermissionChecker; import androidx.core.graphics.ColorUtils; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; @@ -51,17 +50,14 @@ import awais.instagrabber.databinding.FragmentTopicPostsBinding; import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; import awais.instagrabber.fragments.main.DiscoverFragmentDirections; import awais.instagrabber.models.PostsLayoutPreferences; -import awais.instagrabber.repositories.responses.discover.TopicCluster; import awais.instagrabber.repositories.responses.Media; +import awais.instagrabber.repositories.responses.discover.TopicCluster; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.webservices.DiscoverService; -import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; - public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final int STORAGE_PERM_REQUEST_CODE = 8020; private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030; @@ -97,12 +93,12 @@ public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.O if (TopicPostsFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(TopicPostsFragment.this.selectedFeedModels)); - binding.posts.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(TopicPostsFragment.this.selectedFeedModels)); + binding.posts.endSelection(); + return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); } return false; } @@ -132,13 +128,13 @@ public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.O public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = -1; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = -1; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java index a6b1cb4c..ac3d5078 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -30,7 +30,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.LiveData; import androidx.lifecycle.MediatorLiveData; @@ -1337,13 +1336,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); return; } - if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) { - DownloadUtils.download(context, media); - Toast.makeText(context, R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show(); - return; - } - tempMedia = media; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (ContextCompat.checkSelfPermission(context, DownloadUtils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) { + DownloadUtils.download(context, media); + Toast.makeText(context, R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show(); + // return; + // } + // tempMedia = media; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @NonNull diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index bfc1dee3..e5567ef2 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -19,7 +19,6 @@ import androidx.activity.OnBackPressedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavController; @@ -55,9 +54,6 @@ import awais.instagrabber.viewmodels.FeedStoriesViewModel; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesService; -import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; - public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "FeedFragment"; private static final int STORAGE_PERM_REQUEST_CODE = 8020; @@ -123,13 +119,13 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = childPosition; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = childPosition; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override @@ -204,13 +200,13 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre if (FeedFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(FeedFragment.this.selectedFeedModels)); - binding.feedRecyclerView.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(FeedFragment.this.selectedFeedModels)); + binding.feedRecyclerView.endSelection(); return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // return true; } return false; } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index cc2ce13a..3da981d0 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -28,7 +28,6 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.content.res.AppCompatResources; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; @@ -98,9 +97,7 @@ import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesService; import awais.instagrabber.webservices.UserService; -import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; -import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "ProfileFragment"; @@ -164,13 +161,13 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe if (ProfileFragment.this.selectedFeedModels == null) return false; final Context context = getContext(); if (context == null) return false; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.download(context, ImmutableList.copyOf(ProfileFragment.this.selectedFeedModels)); - binding.postsRecyclerView.endSelection(); - return true; - } - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.download(context, ImmutableList.copyOf(ProfileFragment.this.selectedFeedModels)); + binding.postsRecyclerView.endSelection(); return true; + // } + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION); + // return true; } return false; } @@ -200,13 +197,13 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe public void onDownloadClick(final Media feedModel, final int childPosition) { final Context context = getContext(); if (context == null) return; - if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { - DownloadUtils.showDownloadDialog(context, feedModel, childPosition); - return; - } - downloadFeedModel = feedModel; - downloadChildPosition = childPosition; - requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); + // if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { + DownloadUtils.showDownloadDialog(context, feedModel, childPosition); + // return; + // } + // downloadFeedModel = feedModel; + // downloadChildPosition = childPosition; + // requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java index 8a2a03b3..254d3479 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/DownloadsPreferencesFragment.java @@ -1,13 +1,11 @@ package awais.instagrabber.fragments.settings; import android.content.Context; -import android.content.Intent; import android.net.Uri; import android.util.Log; import android.view.View; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatTextView; import androidx.documentfile.provider.DocumentFile; @@ -21,15 +19,14 @@ import com.google.android.material.switchmaterial.SwitchMaterial; import awais.instagrabber.R; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.Utils; -import static android.app.Activity.RESULT_OK; import static awais.instagrabber.utils.Constants.FOLDER_PATH; import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO; import static awais.instagrabber.utils.Utils.settingsHelper; public class DownloadsPreferencesFragment extends BasePreferencesFragment { private static final String TAG = DownloadsPreferencesFragment.class.getSimpleName(); - private static final int SELECT_DIR_REQUEST_CODE = 1; private SaveToCustomFolderPreference.ResultCallback resultCallback; @Override @@ -37,7 +34,7 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { final Context context = getContext(); if (context == null) return; screen.addPreference(getDownloadUserFolderPreference(context)); - screen.addPreference(getSaveToCustomFolderPreference(context)); + // screen.addPreference(getSaveToCustomFolderPreference(context)); screen.addPreference(getPrependUsernameToFilenamePreference(context)); } @@ -49,41 +46,63 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { return preference; } - private Preference getSaveToCustomFolderPreference(@NonNull final Context context) { - return new SaveToCustomFolderPreference(context, (resultCallback) -> { - // Choose a directory using the system's file picker. - final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); - startActivityForResult(intent, SELECT_DIR_REQUEST_CODE); - this.resultCallback = resultCallback; + // private Preference getSaveToCustomFolderPreference(@NonNull final Context context) { + // return new SaveToCustomFolderPreference(context, checked -> { + // try { + // DownloadUtils.init(context); + // } catch (DownloadUtils.ReselectDocumentTreeException e) { + // if (!checked) return; + // startDocumentSelector(e.getInitialUri()); + // } catch (Exception e) { + // Log.e(TAG, "getSaveToCustomFolderPreference: ", e); + // } + // }, (resultCallback) -> { + // // Choose a directory using the system's file picker. + // startDocumentSelector(null); + // this.resultCallback = resultCallback; + // + // // new DirectoryChooser() + // // .setInitialDirectory(settingsHelper.getString(FOLDER_PATH)) + // // .setInteractionListener(file -> { + // // settingsHelper.putString(FOLDER_PATH, file.getAbsolutePath()); + // // resultCallback.onResult(file.getAbsolutePath()); + // // }) + // // .show(getParentFragmentManager(), null); + // }); + // } - // new DirectoryChooser() - // .setInitialDirectory(settingsHelper.getString(FOLDER_PATH)) - // .setInteractionListener(file -> { - // settingsHelper.putString(FOLDER_PATH, file.getAbsolutePath()); - // resultCallback.onResult(file.getAbsolutePath()); - // }) - // .show(getParentFragmentManager(), null); - }); - } + // private void startDocumentSelector(final Uri initialUri) { + // final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && initialUri != null) { + // intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri); + // } + // startActivityForResult(intent, SELECT_DIR_REQUEST_CODE); + // } - @Override - public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { - if (data == null || data.getData() == null) return; - if (resultCode != RESULT_OK || requestCode != SELECT_DIR_REQUEST_CODE) return; - final Context context = getContext(); - if (context == null) return; - final Uri dirUri = data.getData(); - Log.d(TAG, "onActivityResult: " + dirUri); - final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - context.getContentResolver().takePersistableUriPermission(dirUri, takeFlags); - final DocumentFile root = DocumentFile.fromTreeUri(context, dirUri); - settingsHelper.putString(FOLDER_PATH, data.getData().toString()); - if (resultCallback != null) { - resultCallback.onResult(root.getName()); - resultCallback = null; - } - // Log.d(TAG, "onActivityResult: " + root); - } + // @Override + // public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { + // if (requestCode != SELECT_DIR_REQUEST_CODE) return; + // final Context context = getContext(); + // if (context == null) return; + // if (resultCode != RESULT_OK) { + // try { + // DownloadUtils.init(context, true); + // } catch (Exception ignored) {} + // return; + // } + // if (data == null || data.getData() == null) return; + // Utils.setupSelectedDir(context, data); + // if (resultCallback != null) { + // try { + // final DocumentFile root = DocumentFile.fromTreeUri(context, data.getData()); + // resultCallback.onResult(Utils.getDocumentFileRealPath(context, root).getAbsolutePath()); + // } catch (Exception e) { + // Log.e(TAG, "onActivityResult: ", e); + // } + // resultCallback = null; + // } + // // Log.d(TAG, "onActivityResult: " + root); + // } private Preference getPrependUsernameToFilenamePreference(@NonNull final Context context) { final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context); @@ -95,11 +114,15 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { public static class SaveToCustomFolderPreference extends Preference { private AppCompatTextView customPathTextView; + private final OnSaveToChangeListener onSaveToChangeListener; private final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener; private final String key; - public SaveToCustomFolderPreference(final Context context, final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) { + public SaveToCustomFolderPreference(final Context context, + final OnSaveToChangeListener onSaveToChangeListener, + final OnSelectFolderButtonClickListener onSelectFolderButtonClickListener) { super(context); + this.onSaveToChangeListener = onSaveToChangeListener; this.onSelectFolderButtonClickListener = onSelectFolderButtonClickListener; key = FOLDER_SAVE_TO; setLayoutResource(R.layout.pref_custom_folder); @@ -117,8 +140,21 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { cbSaveTo.setOnCheckedChangeListener((buttonView, isChecked) -> { settingsHelper.putBoolean(FOLDER_SAVE_TO, isChecked); buttonContainer.setVisibility(isChecked ? View.VISIBLE : View.GONE); - final String customPath = settingsHelper.getString(FOLDER_PATH); + final Context context = getContext(); + String customPath = settingsHelper.getString(FOLDER_PATH); + if (!TextUtils.isEmpty(customPath) && customPath.startsWith("content") && context != null) { + final Uri uri = Uri.parse(customPath); + final DocumentFile documentFile = DocumentFile.fromSingleUri(context, uri); + try { + customPath = Utils.getDocumentFileRealPath(context, documentFile).getAbsolutePath(); + } catch (Exception e) { + Log.e(TAG, "onBindViewHolder: ", e); + } + } customPathTextView.setText(customPath); + if (onSaveToChangeListener != null) { + onSaveToChangeListener.onChange(isChecked); + } }); final boolean savedToEnabled = settingsHelper.getBoolean(key); holder.itemView.setOnClickListener(v -> cbSaveTo.toggle()); @@ -141,5 +177,9 @@ public class DownloadsPreferencesFragment extends BasePreferencesFragment { public interface OnSelectFolderButtonClickListener { void onClick(ResultCallback resultCallback); } + + public interface OnSaveToChangeListener { + void onChange(boolean checked); + } } } diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index a2a5fd13..69f63f23 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -70,15 +70,15 @@ public final class Constants { public static final int DM_CHECK_NOTIFICATION_ID = 11; // see https://github.com/dilame/instagram-private-api/blob/master/src/core/constants.ts -// public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" + -// " \"13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0," + -// "32.0,33.0,34.0,35.0,36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0," + -// "52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,60.0,61.0,62.0,63.0,64.0,65.0,66.0\" }, { \"name\": \"FACE_TRACKER_VERSION\", " + -// "\"value\": 12 }, { \"name\": \"segmentation\", \"value\": \"segmentation_enabled\" }, { \"name\": \"COMPRESSION\", " + -// "\"value\": \"ETC2_COMPRESSION\" }, { \"name\": \"world_tracker\", \"value\": \"world_tracker_enabled\" }, { \"name\": " + -// "\"gyroscope\", \"value\": \"gyroscope_enabled\" } ]"; -// public static final String SIGNATURE_VERSION = "4"; -// public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc"; + // public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" + + // " \"13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0," + + // "32.0,33.0,34.0,35.0,36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0," + + // "52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,60.0,61.0,62.0,63.0,64.0,65.0,66.0\" }, { \"name\": \"FACE_TRACKER_VERSION\", " + + // "\"value\": 12 }, { \"name\": \"segmentation\", \"value\": \"segmentation_enabled\" }, { \"name\": \"COMPRESSION\", " + + // "\"value\": \"ETC2_COMPRESSION\" }, { \"name\": \"world_tracker\", \"value\": \"world_tracker_enabled\" }, { \"name\": " + + // "\"gyroscope\", \"value\": \"gyroscope_enabled\" } ]"; + // public static final String SIGNATURE_VERSION = "4"; + // public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc"; public static final String BREADCRUMB_KEY = "iN4$aGr0m"; public static final int LOGIN_RESULT_CODE = 5000; public static final String SKIPPED_VERSION = "skipped_version"; @@ -123,4 +123,6 @@ public final class Constants { public static final String DM_THREAD_ACTION_EXTRA_THREAD_TITLE = "thread_title"; public static final String X_IG_APP_ID = "936619743392459"; + + public static final String EXTRA_INITIAL_URI = "initial_uri"; } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/DirectoryChooser.java b/app/src/main/java/awais/instagrabber/utils/DirectoryChooser.java index d349e490..1ea880a5 100755 --- a/app/src/main/java/awais/instagrabber/utils/DirectoryChooser.java +++ b/app/src/main/java/awais/instagrabber/utils/DirectoryChooser.java @@ -3,7 +3,6 @@ package awais.instagrabber.utils; import android.app.Activity; import android.app.Dialog; import android.content.Context; -import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Environment; @@ -11,19 +10,14 @@ import android.os.FileObserver; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; -import com.google.android.material.snackbar.BaseTransientBottomBar; -import com.google.android.material.snackbar.Snackbar; - import java.io.File; import java.util.ArrayList; import java.util.Collections; @@ -95,15 +89,15 @@ public final class DirectoryChooser extends DialogFragment { 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(); - } + // 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)) diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java index df8fef91..88be98db 100644 --- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java @@ -1,9 +1,9 @@ package awais.instagrabber.utils; -import android.Manifest; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; +import android.content.UriPermission; import android.net.Uri; import android.provider.DocumentsContract; import android.util.Log; @@ -49,32 +49,65 @@ import static awais.instagrabber.utils.Constants.FOLDER_PATH; public final class DownloadUtils { private static final String TAG = DownloadUtils.class.getSimpleName(); - - public static final String WRITE_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE; - public static final String[] PERMS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; - private static final String DIR_BARINSTA = "Barinsta"; + // private static final String DIR_BARINSTA = "Barinsta"; private static final String DIR_DOWNLOADS = "Downloads"; private static final String DIR_CAMERA = "Camera"; private static final String DIR_EDIT = "Edit"; - private static final String TEMP_DIR = "Temp"; + private static final String DIR_RECORDINGS = "Recordings"; + private static final String DIR_TEMP = "Temp"; + private static final String DIR_BACKUPS = "Backups"; + + // public static final String WRITE_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE; + // public static final String[] PERMS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; private static DocumentFile root; + // private static DocumentFile DOWNLOADS_DIR_FILE; - public static void init(@NonNull final Context context) { - // if (!Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) return; + public static void init(@NonNull final Context context) throws ReselectDocumentTreeException { + // if (DOWNLOADS_DIR_FILE == null) { + // final Uri uri = Utils.getSafUris(context, new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS))[0]; + // DOWNLOADS_DIR_FILE = DocumentFile.fromTreeUri(context, uri); + // } + // if (!Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) { + // root = DOWNLOADS_DIR_FILE; // DocumentFile.fromFile(DOWNLOADS_DIR_FILE); + // return; + // } final String customPath = Utils.settingsHelper.getString(FOLDER_PATH); - if (TextUtils.isEmpty(customPath)) return; - // dir = new File(customPath); - root = DocumentFile.fromTreeUri(context, Uri.parse(customPath)); + if (TextUtils.isEmpty(customPath)) { + throw new ReselectDocumentTreeException(); + // root = DOWNLOADS_DIR_FILE; // DocumentFile.fromFile(DOWNLOADS_DIR_FILE); + // return; + } + if (!customPath.startsWith("content")) { + // if (customPath.equals(DOWNLOADS_DIR_FILE.getAbsolutePath())) { + // throw new ReselectDocumentTreeException(); + // } + // reselect the folder in selector view + throw new ReselectDocumentTreeException(Uri.parse(customPath)); + } + final Uri uri = Uri.parse(customPath); + final List existingPermissions = context.getContentResolver().getPersistedUriPermissions(); + if (existingPermissions.isEmpty()) { + // reselect the folder in selector view + throw new ReselectDocumentTreeException(uri); + } + final boolean anyMatch = existingPermissions.stream().anyMatch(uriPermission -> uriPermission.getUri().equals(uri)); + if (!anyMatch) { + // reselect the folder in selector view + throw new ReselectDocumentTreeException(uri); + } + root = DocumentFile.fromTreeUri(context, uri); Log.d(TAG, "init: " + root); // final File parent = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); // final DocumentFile documentFile = DocumentFile.fromFile(parent); // Log.d(TAG, "init: " + documentFile); } + @Nullable public static DocumentFile getDownloadDir(final String... dirs) { - // final File parent = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS); - // File subDir = new File(parent, DIR_BARINSTA); + if (root == null) { + return null; + } DocumentFile subDir = root; if (dirs != null) { for (final String dir : dirs) { @@ -87,7 +120,7 @@ public final class DownloadUtils { return subDir; } - @NonNull + @Nullable public static DocumentFile getDownloadDir() { // final File parent = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS); // final File dir = new File(new File(parent, "barinsta"), "downloads"); @@ -106,14 +139,26 @@ public final class DownloadUtils { return getDownloadDir(DIR_DOWNLOADS); } + @Nullable public static DocumentFile getCameraDir() { return getDownloadDir(DIR_CAMERA); } + @Nullable public static DocumentFile getImageEditDir(final String sessionId) { return getDownloadDir(DIR_EDIT, sessionId); } + @Nullable + public static DocumentFile getRecordingsDir() { + return getDownloadDir(DIR_RECORDINGS); + } + + @Nullable + public static DocumentFile getBackupsDir() { + return getDownloadDir(DIR_BACKUPS); + } + // @Nullable // private static DocumentFile getDownloadDir(@NonNull final Context context, @Nullable final String username) { // return getDownloadDir(context, username, false); @@ -156,9 +201,9 @@ public final class DownloadUtils { } private static DocumentFile getTempDir() { - DocumentFile file = root.findFile(TEMP_DIR); + DocumentFile file = root.findFile(DIR_TEMP); if (file == null) { - file = root.createDirectory(TEMP_DIR); + file = root.createDirectory(DIR_TEMP); } return file; } @@ -202,11 +247,11 @@ public final class DownloadUtils { return getDownloadSavePaths(paths, postId, "", displayUrl, username); } - private static Pair, String> getDownloadChildSaveFile(final List paths, - final String postId, - final int childPosition, - final String url, - final String username) { + private static Pair, String> getDownloadChildSavePaths(final List paths, + final String postId, + final int childPosition, + final String url, + final String username) { final String sliderPostfix = "_slide_" + childPosition; return getDownloadSavePaths(paths, postId, sliderPostfix, url, username); } @@ -231,9 +276,9 @@ public final class DownloadUtils { return new Pair<>(paths, mimeType); } - public static DocumentFile getTempFile() { - return getTempFile(null, null); - } + // public static DocumentFile getTempFile() { + // return getTempFile(null, null); + // } public static DocumentFile getTempFile(final String fileName, final String extension) { final DocumentFile dir = getTempDir(); @@ -317,8 +362,8 @@ public final class DownloadUtils { final Media child = sliderItems.get(i); if (child == null) continue; final String url = ResponseBodyUtils.getImageUrl(child); - final Pair, String> file = getDownloadChildSaveFile(userFolderPaths, media.getCode(), i + 1, url, ""); - final Pair, String> usernameFile = getDownloadChildSaveFile(userFolderPaths, media.getCode(), i + 1, url, username); + final Pair, String> file = getDownloadChildSavePaths(userFolderPaths, media.getCode(), i + 1, url, ""); + final Pair, String> usernameFile = getDownloadChildSavePaths(userFolderPaths, media.getCode(), i + 1, url, username); checkList.add(checkPathExists(context, file.first) || checkPathExists(context, usernameFile.first)); } break; @@ -329,6 +374,7 @@ public final class DownloadUtils { private static boolean checkPathExists(@NonNull final Context context, @NonNull final List paths) { + if (root == null) return false; final String joined = android.text.TextUtils.join("/", paths); final Uri userFolderUri = DocumentsContract.buildDocumentUriUsingTree(root.getUri(), joined); final DocumentFile userFolder = DocumentFile.fromSingleUri(context, userFolderUri); @@ -455,8 +501,8 @@ public final class DownloadUtils { final String usernamePrepend = Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_PREPEND_USER_NAME) && mediaUser != null ? mediaUser.getUsername() : ""; - final Pair, String> pair = getDownloadChildSaveFile(userFolderPaths, media.getCode(), i + 1, url, - usernamePrepend); + final Pair, String> pair = getDownloadChildSavePaths(userFolderPaths, media.getCode(), i + 1, url, + usernamePrepend); final DocumentFile file = createFile(pair); if (file == null) continue; map.put(url, file); @@ -469,7 +515,9 @@ public final class DownloadUtils { download(context, map); } + @Nullable private static DocumentFile createFile(@NonNull final Pair, String> pair) { + if (root == null) return null; if (pair.first == null || pair.second == null) return null; DocumentFile dir = root; final List first = pair.first; @@ -558,4 +606,21 @@ public final class DownloadUtils { WorkManager.getInstance(context) .enqueue(downloadWorkRequest); } + + + public static class ReselectDocumentTreeException extends Exception { + private final Uri initialUri; + + public ReselectDocumentTreeException() { + initialUri = null; + } + + public ReselectDocumentTreeException(final Uri initialUri) { + this.initialUri = initialUri; + } + + public Uri getInitialUri() { + return initialUri; + } + } } diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index b7c8e429..e9832715 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -36,6 +36,7 @@ import android.widget.Toast; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; @@ -70,6 +71,8 @@ import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.Tab; import awais.instagrabber.models.enums.FavoriteType; +import static awais.instagrabber.utils.Constants.FOLDER_PATH; + public final class Utils { private static final String TAG = "Utils"; private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024; @@ -520,7 +523,8 @@ public final class Utils { callback); } - private static File getDocumentFileRealPath(Context context, DocumentFile documentFile) + public static File getDocumentFileRealPath(@NonNull final Context context, + @NonNull final DocumentFile documentFile) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { final String docId = DocumentsContract.getDocumentId(documentFile.getUri()); final String[] split = docId.split(":"); @@ -530,18 +534,19 @@ public final class Utils { return new File(Environment.getExternalStorageDirectory(), split[1]); } else { if (volumes == null) { - StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); - Method getVolumeListMethod = sm.getClass().getMethod("getVolumeList"); + final StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + if (sm == null) return null; + final Method getVolumeListMethod = sm.getClass().getMethod("getVolumeList"); volumes = (Object[]) getVolumeListMethod.invoke(sm); } - + if (volumes == null) return null; for (Object volume : volumes) { - Method getUuidMethod = volume.getClass().getMethod("getUuid"); - String uuid = (String) getUuidMethod.invoke(volume); + final Method getUuidMethod = volume.getClass().getMethod("getUuid"); + final String uuid = (String) getUuidMethod.invoke(volume); if (uuid != null && uuid.equalsIgnoreCase(type)) { - Method getPathMethod = volume.getClass().getMethod("getPath"); - String path = (String) getPathMethod.invoke(volume); + final Method getPathMethod = volume.getClass().getMethod("getPath"); + final String path = (String) getPathMethod.invoke(volume); return new File(path, split[1]); } } @@ -549,4 +554,72 @@ public final class Utils { return null; } + + public static void setupSelectedDir(@NonNull final Context context, + @NonNull final Intent intent) throws DownloadUtils.ReselectDocumentTreeException { + final Uri dirUri = intent.getData(); + Log.d(TAG, "onActivityResult: " + dirUri); + if (dirUri == null) return; + final int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + context.getContentResolver().takePersistableUriPermission(dirUri, takeFlags); + settingsHelper.putString(FOLDER_PATH, dirUri.toString()); + // re-init DownloadUtils + DownloadUtils.init(context); + } + + /** + * Ing.N.Nyerges 2019 V2.0 + *

+ * Storage Access Framework(SAF) Uri's creator from File (java.IO), + * for removable external storages + * + * @param context Application Context + * @param file File path + file name + * @return Uri[]: + * uri[0] = SAF TREE Uri + * uri[1] = SAF DOCUMENT Uri + */ + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + public static Uri[] getSafUris(Context context, File file) { + + Uri[] uri = new Uri[2]; + String scheme = "content"; + String authority = "com.android.externalstorage.documents"; + + // Separate each element of the File path + // File format: "/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename" + // (XXXX-XXXX is external removable number + String[] ele = file.getPath().split(File.separator); + // ele[0] = not used (empty) + // ele[1] = not used (storage name) + // ele[2] = storage number + // ele[3 to (n-1)] = folders + // ele[n] = file name + + // Construct folders strings using SAF format + StringBuilder folders = new StringBuilder(); + if (ele.length > 4) { + folders.append(ele[3]); + for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]); + } + + String common = ele[2] + "%3A" + folders.toString(); + + // Construct TREE Uri + Uri.Builder builder = new Uri.Builder(); + builder.scheme(scheme); + builder.authority(authority); + builder.encodedPath("/tree/" + common); + uri[0] = builder.build(); + + // Construct DOCUMENT Uri + builder = new Uri.Builder(); + builder.scheme(scheme); + builder.authority(authority); + if (ele.length > 4) common = common + "%2F"; + builder.encodedPath("/document/" + common + file.getName()); + uri[1] = builder.build(); + + return uri; + } } diff --git a/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.java index 440d4765..fd23f755 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.java @@ -72,7 +72,7 @@ public class DirectThreadViewModel extends AndroidViewModel { throw new IllegalArgumentException("User is not logged in!"); } contentResolver = application.getContentResolver(); - recordingsDir = DownloadUtils.getDownloadDir("Recordings"); + recordingsDir = DownloadUtils.getRecordingsDir(); final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance(); threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver); threadManager.fetchPendingRequests(); diff --git a/app/src/main/res/layout/activity_directory_select.xml b/app/src/main/res/layout/activity_directory_select.xml new file mode 100644 index 00000000..01f81a9f --- /dev/null +++ b/app/src/main/res/layout/activity_directory_select.xml @@ -0,0 +1,39 @@ + + + + + + + + + + \ No newline at end of file