From 93fc9d82b9e8ef84ac2c9f7e27736e25d0ab037f Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Fri, 4 Sep 2020 00:15:53 +0900 Subject: [PATCH] Converted SavedViewer activity to fragment --- app/src/main/AndroidManifest.xml | 70 +-- .../java/awais/instagrabber/MainHelper.java | 28 +- .../instagrabber/activities/MainActivity.java | 3 +- .../instagrabber/activities/PostViewer.java | 9 +- .../activities/ProfileViewer.java | 27 +- .../instagrabber/activities/SavedViewer.java | 288 ------------ .../instagrabber/asyncs/PostsFetcher.java | 72 +-- .../fragments/HashTagFragment.java | 13 +- .../fragments/LocationFragment.java | 3 +- .../fragments/PostViewFragment.java | 20 +- .../fragments/SavedViewerFragment.java | 333 ++++++++++++++ .../fragments/StoryViewerFragment.java | 1 + .../fragments/main/DiscoverFragment.java | 28 +- .../fragments/main/ProfileFragment.java | 412 ++++++++---------- .../models/enums/PostItemType.java | 6 +- .../java/awais/instagrabber/utils/Utils.java | 239 +++++----- ...{activity_saved.xml => fragment_saved.xml} | 8 +- .../res/navigation/discover_nav_graph.xml | 1 + .../main/res/navigation/profile_nav_graph.xml | 21 + 19 files changed, 818 insertions(+), 764 deletions(-) delete mode 100755 app/src/main/java/awais/instagrabber/activities/SavedViewer.java create mode 100644 app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java rename app/src/main/res/layout/{activity_saved.xml => fragment_saved.xml} (84%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f3398ac6..01838249 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -132,14 +132,14 @@ - + + + - - + + + + - + + + - - + + + + - + + + - - + + + + - + + + - - + + + + - + + + - - + + + + new ProfileAction().execute("follow")) .show(); - } - else new ProfileAction().execute("follow"); + } else new ProfileAction().execute("follow"); } else if (v == mainActivity.mainBinding.profileView.btnRestrict && isLoggedIn) { new ProfileAction().execute("restrict"); } else if (v == mainActivity.mainBinding.profileView.btnSaved && !isSelf) { @@ -1431,17 +1435,17 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { } else if (v == mainActivity.mainBinding.profileView.btnFollowTag) { new ProfileAction().execute("followtag"); } else if (v == mainActivity.mainBinding.profileView.btnTagged || v == mainActivity.mainBinding.profileView.btnRestrict) { - mainActivity.startActivity(new Intent(mainActivity, SavedViewer.class) + mainActivity.startActivity(new Intent(mainActivity, SavedViewerFragment.class) .putExtra(Constants.EXTRAS_INDEX, "%" + mainActivity.profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + mainActivity.profileModel.getUsername()) ); } else if (v == mainActivity.mainBinding.profileView.btnSaved) { - mainActivity.startActivity(new Intent(mainActivity, SavedViewer.class) + mainActivity.startActivity(new Intent(mainActivity, SavedViewerFragment.class) .putExtra(Constants.EXTRAS_INDEX, "$" + mainActivity.profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + mainActivity.profileModel.getUsername()) ); } else if (v == mainActivity.mainBinding.profileView.btnLiked) { - mainActivity.startActivity(new Intent(mainActivity, SavedViewer.class) + mainActivity.startActivity(new Intent(mainActivity, SavedViewerFragment.class) .putExtra(Constants.EXTRAS_INDEX, "^" + mainActivity.profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + mainActivity.profileModel.getUsername()) ); diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 003feff8..673beb2c 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -45,7 +45,8 @@ public class MainActivity extends BaseLanguageActivity { R.id.morePreferencesFragment, R.id.settingsPreferencesFragment, R.id.hashTagFragment, - R.id.locationFragment); + R.id.locationFragment, + R.id.savedViewerFragment); private ActivityMainBinding binding; private LiveData currentNavControllerLiveData; diff --git a/app/src/main/java/awais/instagrabber/activities/PostViewer.java b/app/src/main/java/awais/instagrabber/activities/PostViewer.java index 34c2320e..0b63fa28 100755 --- a/app/src/main/java/awais/instagrabber/activities/PostViewer.java +++ b/app/src/main/java/awais/instagrabber/activities/PostViewer.java @@ -313,10 +313,11 @@ public final class PostViewer extends BaseLanguageActivity { final List itemGetterItems; final boolean isSwipeable; - if (postItemType == PostItemType.SAVED && SavedViewer.itemGetter != null) { - itemGetterItems = SavedViewer.itemGetter.get(postItemType); - isSwipeable = !(itemGetterItems.size() < 1 || postItemType == PostItemType.SAVED && isFromShare); - } else if (postItemType != null && MainActivityBackup.itemGetter != null) { + // if (postItemType == PostItemType.SAVED && SavedViewerFragment.itemGetter != null) { + // itemGetterItems = SavedViewerFragment.itemGetter.get(postItemType); + // isSwipeable = !(itemGetterItems.size() < 1 || postItemType == PostItemType.SAVED && isFromShare); + // } else + if (postItemType != null && MainActivityBackup.itemGetter != null) { itemGetterItems = MainActivityBackup.itemGetter.get(postItemType); isSwipeable = !(itemGetterItems.size() < 1 || postItemType == PostItemType.MAIN && isFromShare); } else { diff --git a/app/src/main/java/awais/instagrabber/activities/ProfileViewer.java b/app/src/main/java/awais/instagrabber/activities/ProfileViewer.java index 5dd49e18..d781d637 100755 --- a/app/src/main/java/awais/instagrabber/activities/ProfileViewer.java +++ b/app/src/main/java/awais/instagrabber/activities/ProfileViewer.java @@ -52,6 +52,7 @@ import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager; import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.ActivityProfileBinding; +import awais.instagrabber.fragments.SavedViewerFragment; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.interfaces.MentionClickListener; import awais.instagrabber.models.BasePostModel; @@ -62,6 +63,7 @@ import awais.instagrabber.models.PostModel; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.DownloadMethod; +import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.DataBox; import awais.instagrabber.utils.Utils; @@ -109,8 +111,8 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe if (autoloadPosts && hasNextPage) currentlyExecuting = new PostsFetcher( profileModel != null ? profileModel.getId() - : (hashtagModel != null ? ("#" + hashtagModel.getName()) : locationModel.getId()), - false, + : (hashtagModel != null ? (hashtagModel.getName()) : locationModel.getId()), + profileModel != null ? PostItemType.MAIN : (hashtagModel != null ? PostItemType.HASHTAG : PostItemType.LOCATION), endCursor, this) .setUsername((isLocation || isHashtag) ? null : profileModel.getUsername()) @@ -247,7 +249,9 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe : (hashtagModel != null ? ("#" + hashtagModel.getName()) : locationModel.getId()), - isHashtag, + profileModel != null + ? PostItemType.MAIN + : (hashtagModel != null ? PostItemType.HASHTAG : PostItemType.LOCATION), endCursor, postsFetchListener) .setUsername((isHashtag || isLocation) ? null : profileModel.getUsername()) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -371,7 +375,7 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe return; } - currentlyExecuting = new PostsFetcher(userQuery, postsFetchListener) + currentlyExecuting = new PostsFetcher(userQuery, PostItemType.HASHTAG, null, postsFetchListener) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); profileBinding.profileView.btnFollowTag.setVisibility(View.VISIBLE); @@ -383,7 +387,7 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe profileBinding.profileView.mainHashtagImage.setStoriesBorder(); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - if (hashtagModel.getFollowing() == true) { + if (hashtagModel.getFollowing()) { profileBinding.profileView.btnFollowTag.setText(R.string.unfollow); profileBinding.profileView.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor( ProfileViewer.this, R.color.btn_purple_background))); @@ -614,8 +618,9 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe } else { profileBinding.profileView.swipeRefreshLayout.setRefreshing(true); profileBinding.profileView.mainPosts.setVisibility(View.VISIBLE); - currentlyExecuting = new PostsFetcher(profileId, postsFetchListener).setUsername(profileModel.getUsername()) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + currentlyExecuting = new PostsFetcher(profileId, PostItemType.MAIN, null, postsFetchListener) + .setUsername(profileModel.getUsername()) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } else { profileBinding.profileView.mainFollowers.setClickable(false); @@ -720,7 +725,7 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe } else { profileBinding.profileView.swipeRefreshLayout.setRefreshing(true); profileBinding.profileView.mainPosts.setVisibility(View.VISIBLE); - currentlyExecuting = new PostsFetcher(profileId, postsFetchListener) + currentlyExecuting = new PostsFetcher(profileId, PostItemType.LOCATION, null, postsFetchListener) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } @@ -870,17 +875,17 @@ public final class ProfileViewer extends BaseLanguageActivity implements SwipeRe } else if (v == profileBinding.profileView.btnFollowTag) { new ProfileAction().execute("followtag"); } else if (v == profileBinding.profileView.btnTagged || (v == profileBinding.profileView.btnRestrict && !isLoggedIn)) { - startActivity(new Intent(ProfileViewer.this, SavedViewer.class) + startActivity(new Intent(ProfileViewer.this, SavedViewerFragment.class) .putExtra(Constants.EXTRAS_INDEX, "%" + profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + profileModel.getUsername()) ); } else if (v == profileBinding.profileView.btnSaved) { - startActivity(new Intent(ProfileViewer.this, SavedViewer.class) + startActivity(new Intent(ProfileViewer.this, SavedViewerFragment.class) .putExtra(Constants.EXTRAS_INDEX, "$" + profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + profileModel.getUsername()) ); } else if (v == profileBinding.profileView.btnLiked) { - startActivity(new Intent(ProfileViewer.this, SavedViewer.class) + startActivity(new Intent(ProfileViewer.this, SavedViewerFragment.class) .putExtra(Constants.EXTRAS_INDEX, "^" + profileModel.getId()) .putExtra(Constants.EXTRAS_USER, "@" + profileModel.getUsername()) ); diff --git a/app/src/main/java/awais/instagrabber/activities/SavedViewer.java b/app/src/main/java/awais/instagrabber/activities/SavedViewer.java deleted file mode 100755 index f2b8a214..00000000 --- a/app/src/main/java/awais/instagrabber/activities/SavedViewer.java +++ /dev/null @@ -1,288 +0,0 @@ -package awais.instagrabber.activities; - -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import android.view.ActionMode; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; - -import androidx.activity.OnBackPressedCallback; -import androidx.activity.OnBackPressedDispatcher; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.lifecycle.ViewModelProvider; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.R; -import awais.instagrabber.adapters.PostsAdapter; -import awais.instagrabber.asyncs.PostsFetcher; -import awais.instagrabber.asyncs.i.iLikedFetcher; -import awais.instagrabber.customviews.PrimaryActionModeCallback; -import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager; -import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; -import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; -import awais.instagrabber.databinding.ActivitySavedBinding; -import awais.instagrabber.fragments.main.viewmodels.PostsViewModel; -import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.interfaces.ItemGetter; -import awais.instagrabber.models.PostModel; -import awais.instagrabber.models.enums.DownloadMethod; -import awais.instagrabber.models.enums.PostItemType; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.Utils; -import awaisomereport.LogCollector; - -import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS; -import static awais.instagrabber.utils.Utils.logCollector; - -public final class SavedViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener { - private static AsyncTask currentlyExecuting; - public static ItemGetter itemGetter; - private PostsAdapter postsAdapter; - private boolean hasNextPage, autoloadPosts; - //private CommentModel commentModel; - private ActivitySavedBinding savedBinding; - private String action, username, endCursor; - private RecyclerLazyLoader lazyLoader; - private Resources resources; - private ArrayList selectedItems = new ArrayList<>(); - private ActionMode actionMode; - private PostsViewModel postsViewModel; - - private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); - private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { - @Override - public void handleOnBackPressed() { - if (postsAdapter == null) { - remove(); - return; - } - postsAdapter.clearSelection(); - remove(); - } - }; - private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( - R.menu.multi_select_download_menu, - new PrimaryActionModeCallback.CallbacksHelper() { - @Override - public void onDestroy(final ActionMode mode) { - onBackPressedCallback.handleOnBackPressed(); - } - - @Override - public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { - if (item.getItemId() == R.id.action_download) { - if (postsAdapter == null || username == null) { - return false; - } - Utils.batchDownload(SavedViewer.this, - username, - DownloadMethod.DOWNLOAD_MAIN, - postsAdapter.getSelectedModels()); - checkAndResetAction(); - return true; - } - return false; - } - }); - private final FetchListener postsFetchListener = new FetchListener() { - @Override - public void onResult(final PostModel[] result) { - if (result != null) { - final List current = postsViewModel.getList().getValue(); - final List resultList = Arrays.asList(result); - if (current == null) { - postsViewModel.getList().postValue(resultList); - } else { - final List currentCopy = new ArrayList<>(current); - currentCopy.addAll(resultList); - postsViewModel.getList().postValue(currentCopy); - } - savedBinding.mainPosts.post(() -> { - savedBinding.mainPosts.setNestedScrollingEnabled(true); - savedBinding.mainPosts.setVisibility(View.VISIBLE); - }); - - final PostModel model = result.length > 0 ? result[result.length - 1] : null; - if (model != null) { - endCursor = model.getEndCursor(); - - hasNextPage = model.hasNextPage(); - if (autoloadPosts && hasNextPage && action.charAt(0) == '^') - currentlyExecuting = new iLikedFetcher(endCursor, postsFetchListener) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else if (autoloadPosts && hasNextPage) - currentlyExecuting = new PostsFetcher(action, false, endCursor, this) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else { - savedBinding.swipeRefreshLayout.setRefreshing(false); - } - model.setPageCursor(false, null); - } - } - savedBinding.swipeRefreshLayout.setRefreshing(false); - // if (oldSize == 0) { - // Toast.makeText(getApplicationContext(), R.string.empty_list, Toast.LENGTH_SHORT).show(); - // finish(); - // } - } - }; - - @Override - protected void onCreate(@Nullable final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - savedBinding = ActivitySavedBinding.inflate(getLayoutInflater()); - setContentView(savedBinding.getRoot()); - savedBinding.swipeRefreshLayout.setOnRefreshListener(this); - autoloadPosts = Utils.settingsHelper.getBoolean(AUTOLOAD_POSTS); - savedBinding.mainPosts.setNestedScrollingEnabled(false); - final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(this, Utils.convertDpToPx(110)); - savedBinding.mainPosts.setLayoutManager(layoutManager); - savedBinding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4))); - - final Intent intent = getIntent(); - if (intent == null || !intent.hasExtra(Constants.EXTRAS_INDEX) - || Utils.isEmpty((action = intent.getStringExtra(Constants.EXTRAS_INDEX))) - || !intent.hasExtra(Constants.EXTRAS_USER) - || Utils.isEmpty((username = intent.getStringExtra(Constants.EXTRAS_USER)))) { - Utils.errorFinish(this); - return; - } - - postsViewModel = new ViewModelProvider(this).get(PostsViewModel.class); - postsAdapter = new PostsAdapter((postModel, position) -> { - if (postsAdapter.isSelecting()) { - if (actionMode == null) return; - final String title = getString(R.string.number_selected, postsAdapter.getSelectedModels().size()); - actionMode.setTitle(title); - return; - } - if (checkAndResetAction()) return; - startActivity(new Intent(this, PostViewer.class) - .putExtra(Constants.EXTRAS_INDEX, position) - .putExtra(Constants.EXTRAS_POST, postModel) - .putExtra(Constants.EXTRAS_USER, username) - .putExtra(Constants.EXTRAS_TYPE, PostItemType.SAVED)); - - }, (model, position) -> { - if (!postsAdapter.isSelecting()) { - checkAndResetAction(); - return true; - } - final OnBackPressedDispatcher onBackPressedDispatcher = getOnBackPressedDispatcher(); - if (onBackPressedDispatcher.hasEnabledCallbacks()) return true; - actionMode = startActionMode(multiSelectAction); - final String title = getString(R.string.number_selected, 1); - actionMode.setTitle(title); - onBackPressedDispatcher.addCallback(onBackPressedCallback); - return true; - }); - savedBinding.mainPosts.setAdapter(postsAdapter); - postsViewModel.getList().observe(this, postsAdapter::submitList); - savedBinding.swipeRefreshLayout.setRefreshing(true); - setSupportActionBar(savedBinding.toolbar.toolbar); - savedBinding.toolbar.toolbar.setTitle((action.charAt(0) == '$' ? R.string.saved : - (action.charAt(0) == '%' ? R.string.tagged : R.string.liked))); - savedBinding.toolbar.toolbar.setSubtitle(username); - - lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { - if (!autoloadPosts && hasNextPage) { - savedBinding.swipeRefreshLayout.setRefreshing(true); - stopCurrentExecutor(); - - currentlyExecuting = action.charAt(0) == '^' - ? new iLikedFetcher(endCursor, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) - : new PostsFetcher(action, false, endCursor, postsFetchListener) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - endCursor = null; - } - }); - savedBinding.mainPosts.addOnScrollListener(lazyLoader); - - itemGetter = itemGetType -> { - if (itemGetType == PostItemType.SAVED) - return postsViewModel.getList().getValue(); - return null; - }; - - if (action.charAt(0) == '^') - new iLikedFetcher(postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else - new PostsFetcher(action, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.saved, menu); - - final MenuItem downloadAction = menu.findItem(R.id.downloadAction); - downloadAction.setVisible(false); - - menu.findItem(R.id.favouriteAction).setVisible(false); - - downloadAction.setOnMenuItemClickListener(item -> { - if (selectedItems.size() > 0) { - Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_SAVED, selectedItems); - } - return true; - }); - return true; - } - - @Override - public void onRefresh() { - if (lazyLoader != null) lazyLoader.resetState(); - stopCurrentExecutor(); - postsViewModel.getList().postValue(Collections.emptyList()); - selectedItems.clear(); - if (postsAdapter != null) { - // postsAdapter.isSelecting = false; - postsAdapter.notifyDataSetChanged(); - } - savedBinding.swipeRefreshLayout.setRefreshing(true); - if (action.charAt(0) == '^') - new iLikedFetcher(postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else - new PostsFetcher(action, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - @Override - public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED && selectedItems.size() > 0) - Utils.batchDownload(this, null, DownloadMethod.DOWNLOAD_SAVED, selectedItems); - } - - public static void stopCurrentExecutor() { - if (currentlyExecuting != null) { - try { - currentlyExecuting.cancel(true); - } catch (final Exception e) { - if (logCollector != null) - logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor"); - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - } - } - } - - private boolean checkAndResetAction() { - final OnBackPressedDispatcher onBackPressedDispatcher = getOnBackPressedDispatcher(); - if (!onBackPressedDispatcher.hasEnabledCallbacks() || actionMode == null) { - return false; - } - actionMode.finish(); - actionMode = null; - return true; - } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/asyncs/PostsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/PostsFetcher.java index 5861b990..97efc042 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/PostsFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/PostsFetcher.java @@ -15,6 +15,7 @@ import awais.instagrabber.BuildConfig; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.PostModel; import awais.instagrabber.models.enums.MediaItemType; +import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Utils; import awaisomereport.LogCollector; @@ -26,24 +27,18 @@ import static awais.instagrabber.utils.Utils.logCollector; public final class PostsFetcher extends AsyncTask { private static final String TAG = "PostsFetcher"; - private boolean isLocation; + private final PostItemType type; private final String endCursor; private final String id; private final FetchListener fetchListener; private String username = null; - public PostsFetcher(final String id, final FetchListener fetchListener) { - this.id = id; - this.endCursor = ""; - this.fetchListener = fetchListener; - } - public PostsFetcher(final String id, - final boolean isLocation, + final PostItemType type, final String endCursor, final FetchListener fetchListener) { this.id = id; - this.isLocation = isLocation; + this.type = type; this.endCursor = endCursor == null ? "" : endCursor; this.fetchListener = fetchListener; } @@ -55,27 +50,32 @@ public final class PostsFetcher extends AsyncTask { @Override protected PostModel[] doInBackground(final Void... voids) { - final boolean isHashTag = id.charAt(0) == '#'; - final boolean isSaved = id.charAt(0) == '$'; - final boolean isTagged = id.charAt(0) == '%'; + // final boolean isHashTag = id.charAt(0) == '#'; + // final boolean isSaved = id.charAt(0) == '$'; + // final boolean isTagged = id.charAt(0) == '%'; // final boolean isLocation = id.contains("/"); final String url; - if (isHashTag) - url = "https://www.instagram.com/graphql/query/?query_hash=9b498c08113f1e09617a1703c22b2f32&variables=" + - "{\"tag_name\":\"" + id.substring(1).toLowerCase() + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; - else if (isLocation) - url = "https://www.instagram.com/graphql/query/?query_hash=36bd0f2bf5911908de389b8ceaa3be6d&variables=" + - "{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; - else if (isSaved) - url = "https://www.instagram.com/graphql/query/?query_hash=8c86fed24fa03a8a2eea2a70a80c7b6b&variables=" + - "{\"id\":\"" + id.substring(1) + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; - else if (isTagged) - url = "https://www.instagram.com/graphql/query/?query_hash=ff260833edf142911047af6024eb634a&variables=" + - "{\"id\":\"" + id.substring(1) + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; - else - url = "https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=" + id + "&first=50&after=" + endCursor; - + switch (type) { + case HASHTAG: + url = "https://www.instagram.com/graphql/query/?query_hash=9b498c08113f1e09617a1703c22b2f32&variables=" + + "{\"tag_name\":\"" + id.toLowerCase() + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; + break; + case LOCATION: + url = "https://www.instagram.com/graphql/query/?query_hash=36bd0f2bf5911908de389b8ceaa3be6d&variables=" + + "{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; + break; + case SAVED: + url = "https://www.instagram.com/graphql/query/?query_hash=8c86fed24fa03a8a2eea2a70a80c7b6b&variables=" + + "{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; + break; + case TAGGED: + url = "https://www.instagram.com/graphql/query/?query_hash=31fe64d9463cbbe58319dced405c6206&variables=" + + "{\"id\":\"" + id + "\",\"first\":150,\"after\":\"" + endCursor + "\"}"; + break; + default: + url = "https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=" + id + "&first=50&after=" + endCursor; + } PostModel[] result = null; try { final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); @@ -95,14 +95,20 @@ public final class PostsFetcher extends AsyncTask { if (!Utils.isEmpty(customPath)) customDir = new File(customPath); } + final boolean isHashtag = type == PostItemType.HASHTAG; + final boolean isLocation = type == PostItemType.LOCATION; + final boolean isSaved = type == PostItemType.SAVED; + final boolean isTagged = type == PostItemType.TAGGED; final JSONObject mediaPosts = new JSONObject(Utils.readFromConnection(conn)) .getJSONObject("data") - .getJSONObject(isHashTag ? Constants.EXTRAS_HASHTAG : - (isLocation ? Constants.EXTRAS_LOCATION : Constants.EXTRAS_USER)) - .getJSONObject(isHashTag ? "edge_hashtag_to_media" : - (isLocation ? "edge_location_to_media" : - (isSaved ? "edge_saved_media" : - (isTagged ? "edge_user_to_photos_of_you" : "edge_owner_to_timeline_media")))); + .getJSONObject(isHashtag + ? Constants.EXTRAS_HASHTAG + : (isLocation ? Constants.EXTRAS_LOCATION + : Constants.EXTRAS_USER)) + .getJSONObject(isHashtag ? "edge_hashtag_to_media" : + isLocation ? "edge_location_to_media" : isSaved ? "edge_saved_media" + : isTagged ? "edge_user_to_photos_of_you" + : "edge_owner_to_timeline_media"); final String endCursor; final boolean hasNextPage; diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 3ba62570..bfead2b0 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -50,6 +50,7 @@ import awais.instagrabber.models.HashtagModel; import awais.instagrabber.models.PostModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.DownloadMethod; +import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Utils; import awaisomereport.LogCollector; @@ -78,14 +79,10 @@ public class HashTagFragment extends Fragment { private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { @Override public void handleOnBackPressed() { - if (postsAdapter == null) { - setEnabled(false); - remove(); - return; - } - postsAdapter.clearSelection(); setEnabled(false); remove(); + if (postsAdapter == null) return; + postsAdapter.clearSelection(); } }; private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( @@ -256,7 +253,9 @@ public class HashTagFragment extends Fragment { stopCurrentExecutor(); binding.btnFollowTag.setVisibility(View.VISIBLE); binding.swipeRefreshLayout.setRefreshing(true); - currentlyExecuting = new PostsFetcher(hashtag, false, endCursor, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (Utils.isEmpty(hashtag)) return; + currentlyExecuting = new PostsFetcher(hashtag.substring(1), PostItemType.HASHTAG, endCursor, postsFetchListener) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); if (isLoggedIn) { new iStoryStatusFetcher(hashtagModel.getName(), null, false, true, false, false, stories -> { storyModels = stories; diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 2fee4e8f..1994328c 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -50,6 +50,7 @@ import awais.instagrabber.models.LocationModel; import awais.instagrabber.models.PostModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.DownloadMethod; +import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Utils; import awaisomereport.LogCollector; @@ -328,7 +329,7 @@ public class LocationFragment extends Fragment { private void fetchPosts() { stopCurrentExecutor(); - currentlyExecuting = new PostsFetcher(locationModel.getId(), true, endCursor, postsFetchListener) + currentlyExecuting = new PostsFetcher(locationModel.getId(), PostItemType.LOCATION, endCursor, postsFetchListener) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewFragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewFragment.java index 5fa8bc75..bcb58d8b 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewFragment.java @@ -139,9 +139,11 @@ public class PostViewFragment extends Fragment { if (mediaService != null) { final String userId = Utils.getUserIdFromCookie(COOKIE); final String csrfToken = Utils.getCsrfTokenFromCookie(COOKIE); + v.setEnabled(false); final ServiceCallback likeCallback = new ServiceCallback() { @Override public void onSuccess(final Boolean result) { + v.setEnabled(true); if (result) { postModel.setManualLike(!postModel.getLike()); adapter.notifyItemChanged(postPosition); @@ -152,6 +154,7 @@ public class PostViewFragment extends Fragment { @Override public void onFailure(final Throwable t) { + v.setEnabled(true); Log.e(TAG, "Error during like/unlike", t); } }; @@ -166,9 +169,11 @@ public class PostViewFragment extends Fragment { if (mediaService != null) { final String userId = Utils.getUserIdFromCookie(COOKIE); final String csrfToken = Utils.getCsrfTokenFromCookie(COOKIE); + v.setEnabled(false); final ServiceCallback saveCallback = new ServiceCallback() { @Override public void onSuccess(final Boolean result) { + v.setEnabled(true); if (result) { postModel.setBookmarked(!postModel.getBookmark()); adapter.notifyItemChanged(postPosition); @@ -179,6 +184,7 @@ public class PostViewFragment extends Fragment { @Override public void onFailure(final Throwable t) { + v.setEnabled(true); Log.e(TAG, "Error during save/unsave", t); } }; @@ -219,6 +225,7 @@ public class PostViewFragment extends Fragment { public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { if (!shouldRefresh) return; init(); + shouldRefresh = false; } private void setupViewPager() { @@ -252,9 +259,7 @@ public class PostViewFragment extends Fragment { idOrCodeList = Arrays.asList(idOrCodeArray); viewerPostViewModel.getList().setValue(createPlaceholderModels(idOrCodeArray.length)); isId = fragmentArgs.getIsId(); - // binding.getRoot().postDelayed(() -> binding.getRoot().setCurrentItem(currentPostIndex), 500); fetchPost(); - // binding.getRoot().setCurrentItem(currentPostIndex); } private List createPlaceholderModels(final int size) { @@ -274,17 +279,6 @@ public class PostViewFragment extends Fragment { if (viewerPostModels != null && viewerPostModels .getViewerPostModels() != null && viewerPostModels .getViewerPostModels().length > 0) { - // final ViewerPostModel viewerPostModel = viewerPostModels[0]; - // if (viewerPostModel != null) { - // final String postId = viewerPostModel.getPostId(); - // try { - // if (postId != null && Integer.parseInt(postId) > 0) { - // // already fetched, don't fetch again - // Log.d(TAG, "returning without fetching"); - // return; - // } - // } catch (NumberFormatException ignored) {} - // } Log.d(TAG, "returning without fetching"); return; } diff --git a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java new file mode 100644 index 00000000..5587811c --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java @@ -0,0 +1,333 @@ +package awais.instagrabber.fragments; + +import android.content.pm.PackageManager; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.ActionMode; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import androidx.activity.OnBackPressedCallback; +import androidx.activity.OnBackPressedDispatcher; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavDirections; +import androidx.navigation.fragment.NavHostFragment; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.R; +import awais.instagrabber.adapters.PostsAdapter; +import awais.instagrabber.asyncs.PostsFetcher; +import awais.instagrabber.asyncs.i.iLikedFetcher; +import awais.instagrabber.customviews.PrimaryActionModeCallback; +import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager; +import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; +import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; +import awais.instagrabber.databinding.FragmentSavedBinding; +import awais.instagrabber.fragments.main.ProfileFragmentDirections; +import awais.instagrabber.fragments.main.viewmodels.PostsViewModel; +import awais.instagrabber.interfaces.FetchListener; +import awais.instagrabber.models.PostModel; +import awais.instagrabber.models.enums.DownloadMethod; +import awais.instagrabber.models.enums.PostItemType; +import awais.instagrabber.utils.Utils; +import awaisomereport.LogCollector; + +import static awais.instagrabber.utils.Utils.logCollector; + +public final class SavedViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { + private static AsyncTask currentlyExecuting; + private PostsAdapter postsAdapter; + private boolean hasNextPage; + private boolean autoloadPosts; + private FragmentSavedBinding binding; + private String username; + private String endCursor; + private RecyclerLazyLoader lazyLoader; + private ArrayList selectedItems = new ArrayList<>(); + private ActionMode actionMode; + private PostsViewModel postsViewModel; + private LinearLayout root; + private AppCompatActivity fragmentActivity; + private boolean shouldRefresh = true; + private PostItemType type; + private String profileId; + + private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { + @Override + public void handleOnBackPressed() { + setEnabled(false); + remove(); + if (postsAdapter == null) return; + postsAdapter.clearSelection(); + } + }; + private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( + R.menu.multi_select_download_menu, + new PrimaryActionModeCallback.CallbacksHelper() { + @Override + public void onDestroy(final ActionMode mode) { + onBackPressedCallback.handleOnBackPressed(); + } + + @Override + public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { + if (item.getItemId() == R.id.action_download) { + if (postsAdapter == null || username == null) { + return false; + } + Utils.batchDownload(requireContext(), + username, + DownloadMethod.DOWNLOAD_SAVED, + postsAdapter.getSelectedModels()); + checkAndResetAction(); + return true; + } + return false; + } + }); + private final FetchListener postsFetchListener = new FetchListener() { + @Override + public void onResult(final PostModel[] result) { + if (result != null) { + final List current = postsViewModel.getList().getValue(); + final List resultList = Arrays.asList(result); + if (current == null) { + postsViewModel.getList().postValue(resultList); + } else { + final List currentCopy = new ArrayList<>(current); + currentCopy.addAll(resultList); + postsViewModel.getList().postValue(currentCopy); + } + binding.mainPosts.post(() -> { + binding.mainPosts.setNestedScrollingEnabled(true); + binding.mainPosts.setVisibility(View.VISIBLE); + }); + + final PostModel model = result.length > 0 ? result[result.length - 1] : null; + if (model != null) { + endCursor = model.getEndCursor(); + hasNextPage = model.hasNextPage(); + if (autoloadPosts && hasNextPage) { + fetchPosts(); + } else { + binding.swipeRefreshLayout.setRefreshing(false); + } + model.setPageCursor(false, null); + } + } + binding.swipeRefreshLayout.setRefreshing(false); + } + }; + private Observer> listObserver; + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fragmentActivity = (AppCompatActivity) getActivity(); + } + + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { + if (root != null) { + shouldRefresh = false; + return root; + } + binding = FragmentSavedBinding.inflate(getLayoutInflater(), container, false); + root = binding.getRoot(); + return root; + } + + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + if (!shouldRefresh) return; + init(); + } + + @Override + public void onResume() { + super.onResume(); + setTitle(); + observeData(); + } + + private void observeData() { + postsViewModel = new ViewModelProvider(this).get(PostsViewModel.class); + postsViewModel.getList().removeObserver(listObserver); + if (postsAdapter != null) { + postsViewModel.getList().observe(getViewLifecycleOwner(), listObserver); + } + } + + private void init() { + final Bundle arguments = getArguments(); + if (arguments == null) return; + final SavedViewerFragmentArgs fragmentArgs = SavedViewerFragmentArgs.fromBundle(arguments); + username = fragmentArgs.getUsername(); + profileId = fragmentArgs.getProfileId(); + type = fragmentArgs.getType(); + setTitle(); + binding.swipeRefreshLayout.setOnRefreshListener(this); + // autoloadPosts = Utils.settingsHelper.getBoolean(AUTOLOAD_POSTS); + binding.mainPosts.setNestedScrollingEnabled(false); + final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(requireContext(), Utils.convertDpToPx(110)); + binding.mainPosts.setLayoutManager(layoutManager); + binding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4))); + postsAdapter = new PostsAdapter((postModel, position) -> { + if (postsAdapter.isSelecting()) { + if (actionMode == null) return; + final String title = getString(R.string.number_selected, postsAdapter.getSelectedModels().size()); + actionMode.setTitle(title); + return; + } + if (checkAndResetAction()) return; + final List postModels = postsViewModel.getList().getValue(); + if (postModels == null || postModels.size() == 0) return; + if (postModels.get(0) == null) return; + final String postId = postModels.get(0).getPostId(); + final boolean isId = postId != null; + final String[] idsOrShortCodes = new String[postModels.size()]; + for (int i = 0; i < postModels.size(); i++) { + final PostModel tempPostModel = postModels.get(i); + final String tempId = tempPostModel.getPostId(); + final String finalPostId = type == PostItemType.LIKED ? tempId.substring(0, tempId.indexOf("_")) : tempId; + idsOrShortCodes[i] = isId ? finalPostId + : tempPostModel.getShortCode(); + } + final NavDirections action = ProfileFragmentDirections.actionGlobalPostViewFragment( + position, + idsOrShortCodes, + isId); + NavHostFragment.findNavController(this).navigate(action); + }, (model, position) -> { + if (!postsAdapter.isSelecting()) { + checkAndResetAction(); + return true; + } + final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher(); + if (onBackPressedCallback.isEnabled()) return true; + actionMode = fragmentActivity.startActionMode(multiSelectAction); + final String title = getString(R.string.number_selected, 1); + actionMode.setTitle(title); + onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback); + return true; + }); + binding.mainPosts.setAdapter(postsAdapter); + listObserver = list -> postsAdapter.submitList(list); + observeData(); + binding.swipeRefreshLayout.setRefreshing(true); + + lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { + if (!autoloadPosts && hasNextPage) { + binding.swipeRefreshLayout.setRefreshing(true); + fetchPosts(); + endCursor = null; + } + }); + binding.mainPosts.addOnScrollListener(lazyLoader); + fetchPosts(); + } + + private void fetchPosts() { + stopCurrentExecutor(); + final AsyncTask asyncTask; + switch (type) { + case LIKED: + asyncTask = new iLikedFetcher(endCursor, postsFetchListener); + break; + case SAVED: + case TAGGED: + if (Utils.isEmpty(profileId)) return; + asyncTask = new PostsFetcher(profileId, type, endCursor, postsFetchListener); + break; + default: + return; + } + currentlyExecuting = asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + @Override + public void onRefresh() { + if (lazyLoader != null) lazyLoader.resetState(); + stopCurrentExecutor(); + endCursor = null; + postsViewModel.getList().postValue(Collections.emptyList()); + selectedItems.clear(); + if (postsAdapter != null) { + // postsAdapter.isSelecting = false; + postsAdapter.notifyDataSetChanged(); + } + binding.swipeRefreshLayout.setRefreshing(true); + fetchPosts(); + } + + @Override + public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 8020 && grantResults[0] == PackageManager.PERMISSION_GRANTED && selectedItems.size() > 0) + Utils.batchDownload(requireContext(), null, DownloadMethod.DOWNLOAD_SAVED, selectedItems); + } + + public static void stopCurrentExecutor() { + if (currentlyExecuting != null) { + try { + currentlyExecuting.cancel(true); + } catch (final Exception e) { + if (logCollector != null) + logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor"); + if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); + } + } + } + + private void setTitle() { + final ActionBar actionBar = fragmentActivity.getSupportActionBar(); + if (actionBar == null) return; + final int titleRes; + switch (type) { + case SAVED: + titleRes = R.string.saved; + break; + case LIKED: + titleRes = R.string.liked; + break; + case TAGGED: + titleRes = R.string.tagged; + break; + default: + return; // no other types supported in this view + } + actionBar.setTitle(titleRes); + actionBar.setSubtitle(username); + } + + private boolean checkAndResetAction() { + if (!onBackPressedCallback.isEnabled() && actionMode == null) { + return false; + } + if (onBackPressedCallback.isEnabled()) { + onBackPressedCallback.setEnabled(false); + onBackPressedCallback.remove(); + } + if (actionMode != null) { + actionMode.finish(); + actionMode = null; + } + return true; + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 0550fa1b..826ca22c 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -150,6 +150,7 @@ public class StoryViewerFragment extends Fragment { public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { if (!shouldRefresh) return; init(); + shouldRefresh = false; } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java index 09453b7b..71eb75b0 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java @@ -107,15 +107,13 @@ public class DiscoverFragment extends Fragment { } } }; - private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { + private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { @Override public void handleOnBackPressed() { - if (discoverAdapter == null) { - remove(); - return; - } - discoverAdapter.clearSelection(); + setEnabled(false); remove(); + if (discoverAdapter == null) return; + discoverAdapter.clearSelection(); } }; private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( @@ -164,6 +162,7 @@ public class DiscoverFragment extends Fragment { public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { if (!shouldRefresh) return; setupExplore(); + shouldRefresh = false; } private void setupExplore() { @@ -228,13 +227,13 @@ public class DiscoverFragment extends Fragment { return true; } final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher(); - if (onBackPressedDispatcher.hasEnabledCallbacks()) { + if (onBackPressedCallback.isEnabled()) { return true; } actionMode = fragmentActivity.startActionMode(multiSelectAction); final String title = getString(R.string.number_selected, 1); actionMode.setTitle(title); - onBackPressedDispatcher.addCallback(onBackPressedCallback); + onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback); return true; }); binding.discoverPosts.setAdapter(discoverAdapter); @@ -251,12 +250,17 @@ public class DiscoverFragment extends Fragment { } private boolean checkAndResetAction() { - final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher(); - if (!onBackPressedDispatcher.hasEnabledCallbacks() || actionMode == null) { + if (!onBackPressedCallback.isEnabled() && actionMode == null) { return false; } - actionMode.finish(); - actionMode = null; + if (onBackPressedCallback.isEnabled()) { + onBackPressedCallback.setEnabled(false); + onBackPressedCallback.remove(); + } + if (actionMode != null) { + actionMode.finish(); + actionMode = null; + } return true; } } 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 56e0cbd1..7707fa13 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -41,7 +41,6 @@ import awais.instagrabber.ProfileNavGraphDirections; import awais.instagrabber.R; import awais.instagrabber.activities.FollowViewer; import awais.instagrabber.activities.MainActivity; -import awais.instagrabber.activities.SavedViewer; import awais.instagrabber.adapters.PostsAdapter; import awais.instagrabber.asyncs.HighlightsFetcher; import awais.instagrabber.asyncs.PostsFetcher; @@ -61,6 +60,7 @@ import awais.instagrabber.models.PostModel; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.DownloadMethod; +import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse; import awais.instagrabber.repositories.responses.FriendshipRepoRestrictRootResponse; import awais.instagrabber.services.FriendshipService; @@ -100,48 +100,42 @@ public class ProfileFragment extends Fragment { final String finalUsername = username.startsWith("@") ? username.substring(1) : username; actionBar.setTitle(finalUsername); + actionBar.setSubtitle(null); } }; - private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { + private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { @Override public void handleOnBackPressed() { - if (postsAdapter == null) { - remove(); - return; - } - postsAdapter.clearSelection(); + setEnabled(false); remove(); + if (postsAdapter == null) return; + postsAdapter.clearSelection(); } }; - private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback(R.menu.multi_select_download_menu, - new CallbacksHelper() { - @Override - public void onDestroy( - final ActionMode mode) { - onBackPressedCallback - .handleOnBackPressed(); - } + private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( + R.menu.multi_select_download_menu, + new CallbacksHelper() { + @Override + public void onDestroy(final ActionMode mode) { + onBackPressedCallback.handleOnBackPressed(); + } - @Override - public boolean onActionItemClicked( - final ActionMode mode, - final MenuItem item) { - if (item.getItemId() == R.id.action_download) { - if (postsAdapter == null || username == null) { - return false; - } - Utils.batchDownload( - requireContext(), - username, - DownloadMethod.DOWNLOAD_MAIN, - postsAdapter - .getSelectedModels()); - checkAndResetAction(); - return true; - } - return false; - } - }); + @Override + public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { + if (item.getItemId() == R.id.action_download) { + if (postsAdapter == null || username == null) { + return false; + } + Utils.batchDownload(requireContext(), + username, + DownloadMethod.DOWNLOAD_MAIN, + postsAdapter.getSelectedModels()); + checkAndResetAction(); + return true; + } + return false; + } + }); private final FetchListener postsFetchListener = new FetchListener() { @Override public void onResult(final PostModel[] result) { @@ -201,9 +195,18 @@ public class ProfileFragment extends Fragment { final Bundle savedInstanceState) { if (root != null) { if (getArguments() != null) { - final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs - .fromBundle(getArguments()); - if (!fragmentArgs.getUsername().equals(username)) { + final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments()); + final String username = fragmentArgs.getUsername(); + if (Utils.isEmpty(username) && profileModel != null) { + final String profileModelUsername = profileModel.getUsername(); + final boolean isSame = ("@" + profileModelUsername).equals(this.username); + if (isSame) { + setUsernameDelayed(); + shouldRefresh = false; + return root; + } + } + if (username == null || !username.equals(this.username)) { shouldRefresh = true; return root; } @@ -264,8 +267,7 @@ public class ProfileFragment extends Fragment { fetchProfileDetails(); // adds cookies to database for quick access final DataBox.CookieModel cookieModel = Utils.dataBox.getCookie(uid); - if (Utils.dataBox.getCookieCount() == 0 || cookieModel == null || Utils - .isEmpty(cookieModel.getUsername())) + if (Utils.dataBox.getCookieCount() == 0 || cookieModel == null || Utils.isEmpty(cookieModel.getUsername())) Utils.dataBox.addUserCookie(new DataBox.CookieModel(uid, username, cookie)); }; boolean found = false; @@ -279,8 +281,7 @@ public class ProfileFragment extends Fragment { } if (!found) { // if not in database, fetch info from instagram - new UsernameFetcher(uid, fetchListener) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new UsernameFetcher(uid, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } return; } @@ -298,8 +299,7 @@ public class ProfileFragment extends Fragment { private void setProfileDetails() { if (profileModel == null) { binding.swipeRefreshLayout.setRefreshing(false); - Toast.makeText(requireContext(), R.string.error_loading_profile, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(requireContext(), R.string.error_loading_profile, Toast.LENGTH_SHORT).show(); return; } binding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE); @@ -309,7 +309,7 @@ public class ProfileFragment extends Fragment { profileModel.getUsername(), false, false, - (!isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG)), + !isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG), false, result -> { storyModels = result; @@ -319,7 +319,7 @@ public class ProfileFragment extends Fragment { }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new HighlightsFetcher(profileId, - (!isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG)), + !isLoggedIn && settingsHelper.getBoolean(Constants.STORIESIG), result -> { if (result != null && result.length > 0) { binding.highlightsList.setVisibility(View.VISIBLE); @@ -336,9 +336,7 @@ public class ProfileFragment extends Fragment { binding.btnLiked.setVisibility(View.VISIBLE); binding.btnSaved.setText(R.string.saved); ViewCompat.setBackgroundTintList(binding.btnSaved, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_orange_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_orange_background))); } else { binding.btnTagged.setVisibility(View.GONE); binding.btnSaved.setVisibility(View.GONE); @@ -347,74 +345,54 @@ public class ProfileFragment extends Fragment { if (profileModel.getFollowing()) { binding.btnFollow.setText(R.string.unfollow); ViewCompat.setBackgroundTintList(binding.btnFollow, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_purple_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_purple_background))); } else if (profileModel.getRequested()) { binding.btnFollow.setText(R.string.cancel); ViewCompat.setBackgroundTintList(binding.btnFollow, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_purple_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_purple_background))); } else { binding.btnFollow.setText(R.string.follow); ViewCompat.setBackgroundTintList(binding.btnFollow, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_pink_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_pink_background))); } binding.btnRestrict.setVisibility(View.VISIBLE); if (profileModel.getRestricted()) { binding.btnRestrict.setText(R.string.unrestrict); ViewCompat.setBackgroundTintList(binding.btnRestrict, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_green_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_green_background))); } else { binding.btnRestrict.setText(R.string.restrict); ViewCompat.setBackgroundTintList(binding.btnRestrict, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_orange_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_orange_background))); } binding.btnBlock.setVisibility(View.VISIBLE); binding.btnTagged.setVisibility(View.VISIBLE); if (profileModel.getBlocked()) { binding.btnBlock.setText(R.string.unblock); ViewCompat.setBackgroundTintList(binding.btnBlock, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_green_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_green_background))); } else { binding.btnBlock.setText(R.string.block); ViewCompat.setBackgroundTintList(binding.btnBlock, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_red_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_red_background))); } } } else { if (Utils.dataBox.getFavorite(username) != null) { binding.btnFollow.setText(R.string.unfavorite_short); ViewCompat.setBackgroundTintList(binding.btnFollow, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_purple_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_purple_background))); } else { binding.btnFollow.setText(R.string.favorite_short); ViewCompat.setBackgroundTintList(binding.btnFollow, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_pink_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_pink_background))); } binding.btnFollow.setVisibility(View.VISIBLE); if (!profileModel.isReallyPrivate()) { binding.btnRestrict.setVisibility(View.VISIBLE); binding.btnRestrict.setText(R.string.tagged); ViewCompat.setBackgroundTintList(binding.btnRestrict, - ColorStateList.valueOf(ContextCompat.getColor( - requireContext(), - R.color.btn_blue_background))); + ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.btn_blue_background))); } } @@ -480,10 +458,8 @@ public class ProfileFragment extends Fragment { if (isLoggedIn) { final View.OnClickListener followClickListener = v -> startActivity(new Intent( requireContext(), - FollowViewer.class).putExtra(Constants.EXTRAS_FOLLOWERS, - v == binding.mainFollowers) - .putExtra(Constants.EXTRAS_NAME, - profileModel.getUsername()) + FollowViewer.class).putExtra(Constants.EXTRAS_FOLLOWERS, v == binding.mainFollowers) + .putExtra(Constants.EXTRAS_NAME, profileModel.getUsername()) .putExtra(Constants.EXTRAS_ID, profileId)); binding.mainFollowers @@ -517,144 +493,149 @@ public class ProfileFragment extends Fragment { private void setupCommonListeners() { final String userIdFromCookie = Utils.getUserIdFromCookie(cookie); - final boolean isSelf = isLoggedIn && profileModel != null && userIdFromCookie != null && userIdFromCookie - .equals(profileModel.getId()); + // final boolean isSelf = isLoggedIn && profileModel != null && userIdFromCookie != null && userIdFromCookie + // .equals(profileModel.getId()); final String favorite = Utils.dataBox.getFavorite(username); binding.btnFollow.setOnClickListener(v -> { if (!isLoggedIn) { if (favorite != null && v == binding.btnFollow) { - Utils.dataBox.delFavorite(new DataBox.FavoriteModel(username, - Long.parseLong(favorite.split( - "/")[1]), - username.replaceAll("^@", - ""))); + Utils.dataBox.delFavorite(new DataBox.FavoriteModel( + username, + Long.parseLong(favorite.split("/")[1]), + username.replaceAll("^@", ""))); } else if (v == binding.btnFollow) { - Utils.dataBox.addFavorite(new DataBox.FavoriteModel(username, - System.currentTimeMillis(), - username.replaceAll("^@", - ""))); + Utils.dataBox.addFavorite(new DataBox.FavoriteModel( + username, + System.currentTimeMillis(), + username.replaceAll("^@", ""))); } fetchProfileDetails(); return; } if (profileModel.getFollowing() || profileModel.getRequested()) { - friendshipService.unfollow(userIdFromCookie, - profileModel.getId(), - Utils.getCsrfTokenFromCookie(cookie), - new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoChangeRootResponse result) { - Log.d(TAG, "Unfollow success: " + result); - fetchProfileDetails(); - } + friendshipService.unfollow( + userIdFromCookie, + profileModel.getId(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoChangeRootResponse result) { + Log.d(TAG, "Unfollow success: " + result); + fetchProfileDetails(); + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error unfollowing", t); - } - }); + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error unfollowing", t); + } + }); } else { - friendshipService.follow(userIdFromCookie, - profileModel.getId(), - Utils.getCsrfTokenFromCookie(cookie), - new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoChangeRootResponse result) { - Log.d(TAG, "Follow success: " + result); - fetchProfileDetails(); - } + friendshipService.follow( + userIdFromCookie, + profileModel.getId(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoChangeRootResponse result) { + Log.d(TAG, "Follow success: " + result); + fetchProfileDetails(); + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error following", t); - } - }); + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error following", t); + } + }); } }); binding.btnRestrict.setOnClickListener(v -> { if (!isLoggedIn) return; final String action = profileModel.getRestricted() ? "Unrestrict" : "Restrict"; - friendshipService.toggleRestrict(profileModel.getId(), - !profileModel.getRestricted(), - Utils.getCsrfTokenFromCookie(cookie), - new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoRestrictRootResponse result) { - Log.d(TAG, action + " success: " + result); - fetchProfileDetails(); - } + friendshipService.toggleRestrict( + profileModel.getId(), + !profileModel.getRestricted(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoRestrictRootResponse result) { + Log.d(TAG, action + " success: " + result); + fetchProfileDetails(); + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, - "Error while performing " + action, - t); - } - }); + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error while performing " + action, t); + } + }); }); binding.btnBlock.setOnClickListener(v -> { if (!isLoggedIn) return; if (profileModel.getBlocked()) { - friendshipService.unblock(userIdFromCookie, - profileModel.getId(), - Utils.getCsrfTokenFromCookie(cookie), - new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoChangeRootResponse result) { - Log.d(TAG, "Unblock success: " + result); - fetchProfileDetails(); - } + friendshipService.unblock( + userIdFromCookie, + profileModel.getId(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoChangeRootResponse result) { + Log.d(TAG, "Unblock success: " + result); + fetchProfileDetails(); + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error unblocking", t); - } - }); + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error unblocking", t); + } + }); return; } - friendshipService.block(userIdFromCookie, - profileModel.getId(), - Utils.getCsrfTokenFromCookie(cookie), - new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoChangeRootResponse result) { - Log.d(TAG, "Block success: " + result); - fetchProfileDetails(); - } + friendshipService.block( + userIdFromCookie, + profileModel.getId(), + Utils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoChangeRootResponse result) { + Log.d(TAG, "Block success: " + result); + fetchProfileDetails(); + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error blocking", t); - } - }); + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error blocking", t); + } + }); + }); + binding.btnSaved.setOnClickListener(v -> { + // startActivity(new Intent(requireContext(), SavedViewerFragment.class) + // .putExtra(Constants.EXTRAS_INDEX, "$" + profileModel.getId()) + // .putExtra(Constants.EXTRAS_USER, "@" + profileModel.getUsername())); + final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToSavedViewerFragment(profileModel.getUsername(), + profileModel.getId(), + PostItemType.SAVED); + NavHostFragment.findNavController(this).navigate(action); + }); + binding.btnLiked.setOnClickListener(v -> { + // startActivity(new Intent(requireContext(), SavedViewerFragment.class) + // .putExtra(Constants.EXTRAS_INDEX, "^" + profileModel.getId()) + // .putExtra(Constants.EXTRAS_USER, username)); + final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToSavedViewerFragment(profileModel.getUsername(), + profileModel.getId(), + PostItemType.LIKED); + NavHostFragment.findNavController(this).navigate(action); }); - binding.btnSaved.setOnClickListener(v -> startActivity(new Intent(requireContext(), - SavedViewer.class) - .putExtra(Constants.EXTRAS_INDEX, - "$" + profileModel - .getId()) - .putExtra(Constants.EXTRAS_USER, - "@" + profileModel - .getUsername()))); - binding.btnLiked.setOnClickListener(v -> startActivity(new Intent(requireContext(), - SavedViewer.class) - .putExtra(Constants.EXTRAS_INDEX, - "^" + profileModel - .getId()) - .putExtra(Constants.EXTRAS_USER, - "@" + profileModel - .getUsername()))); - binding.btnTagged.setOnClickListener(v -> startActivity(new Intent(requireContext(), - SavedViewer.class) - .putExtra(Constants.EXTRAS_INDEX, - "%" + profileModel - .getId()) - .putExtra(Constants.EXTRAS_USER, - "@" + profileModel - .getUsername()))); + binding.btnTagged.setOnClickListener(v -> { + // startActivity(new Intent(requireContext(), SavedViewerFragment.class) + // .putExtra(Constants.EXTRAS_INDEX, "%" + profileModel.getId()) + // .putExtra(Constants.EXTRAS_USER, username)); + final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToSavedViewerFragment(profileModel.getUsername(), + profileModel.getId(), + PostItemType.TAGGED); + NavHostFragment.findNavController(this).navigate(action); + }); } private void setUsernameDelayed() { @@ -666,9 +647,7 @@ public class ProfileFragment extends Fragment { private void setupPosts() { postsViewModel = new ViewModelProvider(this).get(PostsViewModel.class); - final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(requireContext(), - Utils.convertDpToPx( - 110)); + final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(requireContext(), Utils.convertDpToPx(110)); binding.mainPosts.setLayoutManager(layoutManager); binding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4))); postsAdapter = new PostsAdapter((postModel, position) -> { @@ -680,11 +659,6 @@ public class ProfileFragment extends Fragment { return; } if (checkAndResetAction()) return; - // startActivity(new Intent(requireContext(), PostViewer.class) - // .putExtra(Constants.EXTRAS_INDEX, position) - // .putExtra(Constants.EXTRAS_POST, postModel) - // .putExtra(Constants.EXTRAS_USER, username) - // .putExtra(Constants.EXTRAS_TYPE, PostItemType.MAIN)); final List postModels = postsViewModel.getList().getValue(); if (postModels == null || postModels.size() == 0) return; if (postModels.get(0) == null) return; @@ -706,33 +680,31 @@ public class ProfileFragment extends Fragment { checkAndResetAction(); return true; } - final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity - .getOnBackPressedDispatcher(); - if (onBackPressedDispatcher.hasEnabledCallbacks()) { + if (onBackPressedCallback.isEnabled()) { return true; } + final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher(); + onBackPressedCallback.setEnabled(true); actionMode = fragmentActivity.startActionMode(multiSelectAction); final String title = getString(R.string.number_selected, 1); actionMode.setTitle(title); - onBackPressedDispatcher.addCallback(onBackPressedCallback); + onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback); return true; }); postsViewModel.getList().observe(fragmentActivity, postsAdapter::submitList); binding.mainPosts.setAdapter(postsAdapter); - final RecyclerLazyLoader lazyLoader = new RecyclerLazyLoader(layoutManager, - (page, totalItemsCount) -> { - if (!hasNextPage) return; - binding.swipeRefreshLayout - .setRefreshing(true); - fetchPosts(); - endCursor = null; - }); + final RecyclerLazyLoader lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { + if (!hasNextPage) return; + binding.swipeRefreshLayout.setRefreshing(true); + fetchPosts(); + endCursor = null; + }); binding.mainPosts.addOnScrollListener(lazyLoader); } private void fetchPosts() { stopCurrentExecutor(); - currentlyExecuting = new PostsFetcher(profileModel.getId(), false, endCursor, postsFetchListener) + currentlyExecuting = new PostsFetcher(profileModel.getId(), PostItemType.MAIN, endCursor, postsFetchListener) .setUsername(profileModel.getUsername()) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -742,22 +714,24 @@ public class ProfileFragment extends Fragment { try { currentlyExecuting.cancel(true); } catch (final Exception e) { - if (logCollector != null) logCollector.appendException(e, - LogCollector.LogFile.MAIN_HELPER, - "stopCurrentExecutor"); + if (logCollector != null) logCollector.appendException(e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor"); Log.e(TAG, "", e); } } } private boolean checkAndResetAction() { - final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity - .getOnBackPressedDispatcher(); - if (!onBackPressedDispatcher.hasEnabledCallbacks() || actionMode == null) { + if (!onBackPressedCallback.isEnabled() && actionMode == null) { return false; } - actionMode.finish(); - actionMode = null; + if (onBackPressedCallback.isEnabled()) { + onBackPressedCallback.setEnabled(false); + onBackPressedCallback.remove(); + } + if (actionMode != null) { + actionMode.finish(); + actionMode = null; + } return true; } } diff --git a/app/src/main/java/awais/instagrabber/models/enums/PostItemType.java b/app/src/main/java/awais/instagrabber/models/enums/PostItemType.java index 4bd0269d..bb4b84d8 100644 --- a/app/src/main/java/awais/instagrabber/models/enums/PostItemType.java +++ b/app/src/main/java/awais/instagrabber/models/enums/PostItemType.java @@ -6,5 +6,9 @@ public enum PostItemType implements Serializable { MAIN, DISCOVER, FEED, - SAVED + SAVED, + LIKED, + TAGGED, + HASHTAG, + LOCATION } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index 89ee1216..75874785 100755 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -71,10 +71,6 @@ import javax.crypto.spec.SecretKeySpec; import awais.instagrabber.BuildConfig; import awais.instagrabber.R; -import awais.instagrabber.activities.MainActivity; -import awais.instagrabber.activities.MainActivityBackup; -import awais.instagrabber.activities.ProfileViewer; -import awais.instagrabber.activities.SavedViewer; import awais.instagrabber.asyncs.DownloadAsync; import awais.instagrabber.asyncs.PostFetcher; import awais.instagrabber.customviews.CommentMentionClickSpan; @@ -265,8 +261,8 @@ public final class Utils { final int endLen = currChar != '#' ? i : i + 1; // for merged hashtags stringBuilder.setSpan(new CommentMentionClickSpan(), startLen, - Math.min(commentLength, endLen), // fixed - crash when end index is greater than comment length ( @kernoeb ) - Spanned.SPAN_EXCLUSIVE_INCLUSIVE); + Math.min(commentLength, endLen), // fixed - crash when end index is greater than comment length ( @kernoeb ) + Spanned.SPAN_EXCLUSIVE_INCLUSIVE); } } @@ -315,8 +311,8 @@ public final class Utils { } catch (final Exception e) { if (logCollector != null) logCollector.appendException(e, LogCollector.LogFile.UTILS, "getHighQualityPost", - new Pair<>("resourcesNull", resources == null), - new Pair<>("isVideo", isVideo)); + new Pair<>("resourcesNull", resources == null), + new Pair<>("isVideo", isVideo)); if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); } return null; @@ -333,7 +329,7 @@ public final class Utils { } catch (final Exception e) { if (logCollector != null) logCollector.appendException(e, LogCollector.LogFile.UTILS, "getHighQualityImage", - new Pair<>("resourcesNull", resources == null)); + new Pair<>("resourcesNull", resources == null)); if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); } return src; @@ -346,7 +342,7 @@ public final class Utils { } catch (final Exception e) { if (logCollector != null) logCollector.appendException(e, LogCollector.LogFile.UTILS, "getLowQualityImage", - new Pair<>("resourcesNull", resources == null)); + new Pair<>("resourcesNull", resources == null)); if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); } return src; @@ -443,13 +439,13 @@ public final class Utils { if (Utils.isEmpty(id)) id = null; mediaModel = new DirectItemMediaModel(mediaType, - mediaObj.optLong("expiring_at"), - mediaObj.optLong("pk"), - id, - getThumbnailUrl(mediaObj, mediaType), - mediaType == MediaItemType.MEDIA_TYPE_VIDEO ? getVideoUrl(mediaObj) : null, - user, - mediaObj.optString("code")); + mediaObj.optLong("expiring_at"), + mediaObj.optLong("pk"), + id, + getThumbnailUrl(mediaObj, mediaType), + mediaType == MediaItemType.MEDIA_TYPE_VIDEO ? getVideoUrl(mediaObj) : null, + user, + mediaObj.optString("code")); } return mediaModel; } @@ -510,28 +506,28 @@ public final class Utils { for (int j = 0; j < usersLen; ++j) { final JSONObject userObject = users.getJSONObject(j); userModels[j] = new ProfileModel(userObject.getBoolean("is_private"), - false, - userObject.optBoolean("is_verified"), - String.valueOf(userObject.get("pk")), - userObject.getString("username"), - userObject.getString("full_name"), - null, null, - userObject.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + false, + userObject.optBoolean("is_verified"), + String.valueOf(userObject.get("pk")), + userObject.getString("username"), + userObject.getString("full_name"), + null, null, + userObject.getString("profile_pic_url"), + null, 0, 0, 0, false, false, false, false); } final ProfileModel[] leftuserModels = new ProfileModel[leftusersLen]; for (int j = 0; j < leftusersLen; ++j) { final JSONObject userObject = leftusers.getJSONObject(j); leftuserModels[j] = new ProfileModel(userObject.getBoolean("is_private"), - false, - userObject.optBoolean("is_verified"), - String.valueOf(userObject.get("pk")), - userObject.getString("username"), - userObject.getString("full_name"), - null, null, - userObject.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + false, + userObject.optBoolean("is_verified"), + String.valueOf(userObject.get("pk")), + userObject.getString("username"), + userObject.getString("full_name"), + null, null, + userObject.getString("profile_pic_url"), + null, 0, 0, 0, false, false, false, false); } final Long[] adminIDs = new Long[adminsLen]; @@ -564,9 +560,10 @@ public final class Utils { final JSONObject stickerImage = animatedMedia.getJSONObject("images").getJSONObject("fixed_height"); animatedMediaModel = new DirectItemAnimatedMediaModel(animatedMedia.getBoolean("is_random"), - animatedMedia.getBoolean("is_sticker"), animatedMedia.getString("id"), - stickerImage.getString("url"), stickerImage.optString("webp"), stickerImage.optString("mp4"), - stickerImage.getInt("height"), stickerImage.getInt("width")); + animatedMedia.getBoolean("is_sticker"), animatedMedia.getString("id"), + stickerImage.getString("url"), stickerImage.optString("webp"), + stickerImage.optString("mp4"), + stickerImage.getInt("height"), stickerImage.getInt("width")); } break; @@ -586,8 +583,8 @@ public final class Utils { } voiceMediaModel = new DirectItemVoiceMediaModel(voiceMedia.getString("id"), - audio.getString("audio_src"), audio.getLong("duration"), - waveformData); + audio.getString("audio_src"), audio.getLong("duration"), + waveformData); } break; @@ -606,9 +603,9 @@ public final class Utils { } linkModel = new DirectItemLinkModel(linkObj.getString("text"), - linkObj.getString("client_context"), - linkObj.optString("mutation_token"), - itemLinkContext); + linkObj.getString("client_context"), + linkObj.optString("mutation_token"), + itemLinkContext); } break; @@ -672,23 +669,23 @@ public final class Utils { case VIDEO_CALL_EVENT: { final JSONObject videoCallEvent = itemObject.getJSONObject("video_call_event"); videoCallEventModel = new DirectItemVideoCallEventModel(videoCallEvent.getLong("vc_id"), - videoCallEvent.optBoolean("thread_has_audio_only_call"), - videoCallEvent.getString("action"), - videoCallEvent.getString("description")); + videoCallEvent.optBoolean("thread_has_audio_only_call"), + videoCallEvent.getString("action"), + videoCallEvent.getString("description")); } break; case PROFILE: { final JSONObject profile = itemObject.getJSONObject("profile"); profileModel = new ProfileModel(profile.getBoolean("is_private"), - false, - profile.getBoolean("is_verified"), - Long.toString(profile.getLong("pk")), - profile.getString("username"), - profile.getString("full_name"), - null, null, - profile.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + false, + profile.getBoolean("is_verified"), + Long.toString(profile.getLong("pk")), + profile.getString("username"), + profile.getString("full_name"), + null, null, + profile.getString("profile_pic_url"), + null, 0, 0, 0, false, false, false, false); } break; @@ -783,12 +780,12 @@ public final class Utils { itemModels.trimToSize(); return new InboxThreadModel(readState, threadId, threadV2Id, threadType, threadTitle, - threadNewestCursor, threadOldestCursor, threadNextCursor, threadPrevCursor, - null, // todo - userModels, leftuserModels, adminIDs, - itemModels.toArray(new DirectItemModel[0]), - muted, isPin, named, canonical, - pending, threadHasOlder, unreadCount, isSpam, isGroup, archived, lastActivityAt); + threadNewestCursor, threadOldestCursor, threadNextCursor, threadPrevCursor, + null, // todo + userModels, leftuserModels, adminIDs, + itemModels.toArray(new DirectItemModel[0]), + muted, isPin, named, canonical, + pending, threadHasOlder, unreadCount, isSpam, isGroup, archived, lastActivityAt); } private static RavenExpiringMediaType getExpiringMediaType(final String type) { @@ -945,8 +942,10 @@ public final class Utils { ActivityCompat.requestPermissions((Activity) context, Utils.PERMS, 8020); } - private static void batchDownloadImpl(@NonNull final Context context, @Nullable final String username, - final DownloadMethod method, final List itemsToDownload) { + private static void batchDownloadImpl(@NonNull final Context context, + @Nullable final String username, + final DownloadMethod method, + final List itemsToDownload) { File dir = new File(Environment.getExternalStorageDirectory(), "Download"); if (settingsHelper.getBoolean(FOLDER_SAVE_TO)) { @@ -957,61 +956,54 @@ public final class Utils { if (settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) && !isEmpty(username)) dir = new File(dir, username); - if (dir.exists() || dir.mkdirs()) { - final MainActivityBackup mainActivity = method != DownloadMethod.DOWNLOAD_FEED && context instanceof MainActivityBackup ? (MainActivityBackup) context : null; - final ProfileViewer pv = method == DownloadMethod.DOWNLOAD_MAIN && context instanceof ProfileViewer ? (ProfileViewer) context : null; - final SavedViewer saved = method == DownloadMethod.DOWNLOAD_SAVED && context instanceof SavedViewer ? (SavedViewer) context : null; - - final int itemsToDownloadSize = itemsToDownload.size(); - - final File finalDir = dir; - for (int i = itemsToDownloadSize - 1; i >= 0; i--) { - final BasePostModel selectedItem = itemsToDownload.get(i); - - if (mainActivity == null && saved == null && pv == null) { - new DownloadAsync(context, - selectedItem.getDisplayUrl(), - getDownloadSaveFile(finalDir, selectedItem, ""), - null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - - } else { - new PostFetcher(selectedItem.getShortCode(), result -> { - if (result != null) { - final int resultsSize = result.length; - final boolean multiResult = resultsSize > 1; - - for (int j = 0; j < resultsSize; j++) { - final BasePostModel model = result[j]; - final File saveFile = getDownloadSaveFile(finalDir, model, multiResult ? "_slide_" + (j + 1) : ""); - - new DownloadAsync(context, - model.getDisplayUrl(), - saveFile, - file -> { - model.setDownloaded(true); - // if (saved != null) - // saved.deselectSelection(selectedItem); - // else if (mainActivity != null) - // mainActivity.mainHelper.deselectSelection(selectedItem); - // else pv.deselectSelection(selectedItem); - }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - // else { - // if (saved != null) saved.deselectSelection(selectedItem); - // else if (mainActivity != null) - // mainActivity.mainHelper.deselectSelection(selectedItem); - // else if (pv != null) pv.deselectSelection(selectedItem); - // } - }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - } else + if (!dir.exists() && !dir.mkdirs()) { Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show(); + return; + } + boolean checkEachPost = false; + switch (method) { + case DOWNLOAD_SAVED: + case DOWNLOAD_MAIN: + checkEachPost = true; + break; + case DOWNLOAD_FEED: + checkEachPost = false; + break; + } + final int itemsToDownloadSize = itemsToDownload.size(); + for (int i = 0; i < itemsToDownloadSize; i++) { + final BasePostModel selectedItem = itemsToDownload.get(i); + if (!checkEachPost) { + final boolean isSlider = itemsToDownloadSize > 1; + final File saveFile = getDownloadSaveFile(dir, selectedItem, isSlider ? "_slide_" + (i + 1) : ""); + new DownloadAsync(context, + selectedItem.getDisplayUrl(), + saveFile, + file -> selectedItem.setDownloaded(true)) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + final File finalDir = dir; + new PostFetcher(selectedItem.getShortCode(), result -> { + if (result != null) { + final int resultsSize = result.length; + final boolean multiResult = resultsSize > 1; + for (int j = 0; j < resultsSize; j++) { + final BasePostModel model = result[j]; + final File saveFile = getDownloadSaveFile(finalDir, model, multiResult ? "_slide_" + (j + 1) : ""); + new DownloadAsync(context, + model.getDisplayUrl(), + saveFile, + file -> model.setDownloaded(true)) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } } public static void dmDownload(@NonNull final Context context, @Nullable final String username, final DownloadMethod method, - final DirectItemMediaModel itemsToDownload) { + final DirectItemMediaModel itemsToDownload) { if (settingsHelper == null) settingsHelper = new SettingsHelper(context); if (itemsToDownload == null) return; @@ -1023,7 +1015,7 @@ public final class Utils { } private static void dmDownloadImpl(@NonNull final Context context, @Nullable final String username, - final DownloadMethod method, final DirectItemMediaModel selectedItem) { + final DownloadMethod method, final DirectItemMediaModel selectedItem) { File dir = new File(Environment.getExternalStorageDirectory(), "Download"); if (settingsHelper.getBoolean(FOLDER_SAVE_TO)) { @@ -1035,11 +1027,10 @@ public final class Utils { dir = new File(dir, username); if (dir.exists() || dir.mkdirs()) { - final File finalDir = dir; new DownloadAsync(context, - selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? selectedItem.getVideoUrl() : selectedItem.getThumbUrl(), - getDownloadSaveFileDm(finalDir, selectedItem, ""), - null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? selectedItem.getVideoUrl() : selectedItem.getThumbUrl(), + getDownloadSaveFileDm(dir, selectedItem, ""), + null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show(); } @@ -1104,8 +1095,8 @@ public final class Utils { } catch (final Exception e) { if (logCollector != null) logCollector.appendException(e, LogCollector.LogFile.UTILS, "checkExistence", - new Pair<>("isSlider", isSlider), - new Pair<>("model", model)); + new Pair<>("isSlider", isSlider), + new Pair<>("model", model)); if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); } @@ -1132,7 +1123,7 @@ public final class Utils { final View importSettingsParent = (View) importExportBinding.cbImportSettings.getParent(); importExportBinding.cbPassword.setOnCheckedChangeListener((buttonView, isChecked) -> - importExportBinding.etPassword.etPassword.setEnabled(isChecked)); + importExportBinding.etPassword.etPassword.setEnabled(isChecked)); final AlertDialog[] dialog = new AlertDialog[1]; final View.OnClickListener onClickListener = v -> { @@ -1171,7 +1162,8 @@ public final class Utils { flags |= ExportImportUtils.FLAG_COOKIES; ExportImportUtils.Export(password, flags, file, result -> { - Toast.makeText(context, result ? R.string.dialog_export_success : R.string.dialog_export_failed, Toast.LENGTH_SHORT).show(); + Toast.makeText(context, result ? R.string.dialog_export_success : R.string.dialog_export_failed, Toast.LENGTH_SHORT) + .show(); if (dialog[0] != null && dialog[0].isShowing()) dialog[0].dismiss(); }); @@ -1190,7 +1182,8 @@ public final class Utils { ExportImportUtils.Import(context, flags, new File(path), result -> { ((AppCompatActivity) context).recreate(); - Toast.makeText(context, result ? R.string.dialog_import_success : R.string.dialog_import_failed, Toast.LENGTH_SHORT).show(); + Toast.makeText(context, result ? R.string.dialog_import_success : R.string.dialog_import_failed, Toast.LENGTH_SHORT) + .show(); if (dialog[0] != null && dialog[0].isShowing()) dialog[0].dismiss(); }); @@ -1284,8 +1277,8 @@ public final class Utils { mimeType = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(itemUri.toString()).toLowerCase()); else mimeType = scheme.equals(ContentResolver.SCHEME_CONTENT) ? contentResolver.getType(itemUri) - : mimeTypeMap.getMimeTypeFromExtension - (MimeTypeMap.getFileExtensionFromUrl(itemUri.toString()).toLowerCase()); + : mimeTypeMap.getMimeTypeFromExtension + (MimeTypeMap.getFileExtensionFromUrl(itemUri.toString()).toLowerCase()); if (isEmpty(mimeType)) return true; mimeType = mimeType.toLowerCase(); diff --git a/app/src/main/res/layout/activity_saved.xml b/app/src/main/res/layout/fragment_saved.xml similarity index 84% rename from app/src/main/res/layout/activity_saved.xml rename to app/src/main/res/layout/fragment_saved.xml index 7dbd46a1..3dee6ef6 100644 --- a/app/src/main/res/layout/activity_saved.xml +++ b/app/src/main/res/layout/fragment_saved.xml @@ -4,11 +4,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".activities.SavedViewer"> + tools:context=".fragments.SavedViewerFragment"> - + + + + + + + + + + \ No newline at end of file