diff --git a/app/build.gradle b/app/build.gradle index 5a6611dc..3e81b904 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,7 +87,7 @@ dependencies { annotationProcessor "androidx.room:room-compiler:$room_version" // implementation 'com.github.hendrawd:StorageUtil:1.1.0' - implementation 'com.github.ammargitham:AutoLinkTextViewV2:master-SNAPSHOT' + implementation 'me.austinhuang:AutoLinkTextViewV2:-SNAPSHOT' implementation 'org.jsoup:jsoup:1.13.1' implementation 'com.facebook.fresco:fresco:2.3.0' diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java index 6396d4b2..1f38cecb 100755 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java @@ -23,7 +23,6 @@ public final class FollowsViewHolder extends RecyclerView.ViewHolder { public void bind(final ProfileModel model, final List admins, final View.OnClickListener onClickListener) { - Log.d("austin_debug", "bind "+model); if (model == null) return; itemView.setTag(model); itemView.setOnClickListener(onClickListener); diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index f27d2c91..1ccb3464 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -20,29 +20,22 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SearchView; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import java.util.ArrayList; -import java.util.Arrays; -import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.adapters.FollowAdapter; +import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.FragmentFollowersViewerBinding; import awais.instagrabber.models.FollowModel; -import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse; import awais.instagrabber.repositories.responses.FriendshipRepoListFetchResponse; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.webservices.FriendshipService; import awais.instagrabber.webservices.ServiceCallback; -import awaisomereport.LogCollector; import thoughtbot.expandableadapter.ExpandableGroup; -import static awais.instagrabber.utils.Utils.logCollector; -import static awais.instagrabber.utils.Utils.settingsHelper; - public final class FollowViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "FollowViewerFragment"; @@ -51,9 +44,11 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh private final ArrayList followersModels = new ArrayList<>(); private final ArrayList allFollowing = new ArrayList<>(); - private boolean isFollowersList, isCompare = false, loading = false; - private String profileId, username, namePost, type; + private boolean moreAvailable = true, isFollowersList, isCompare = false, loading = false, shouldRefresh = true; + private String profileId, username, namePost, type, endCursor; private Resources resources; + private LinearLayoutManager layoutManager; + private RecyclerLazyLoader lazyLoader; private FollowModel model; private FollowAdapter adapter; private View.OnClickListener clickListener; @@ -61,9 +56,59 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh private AsyncTask currentlyExecuting; private SwipeRefreshLayout root; private FriendshipService friendshipService; - private boolean shouldRefresh = true; private AppCompatActivity fragmentActivity; + final ServiceCallback followingFetchCb = new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoListFetchResponse result) { + if (result != null) { + followingModels.addAll(result.getItems()); + if (!isFollowersList) followModels.addAll(result.getItems()); + if (result.isMoreAvailable()) { + endCursor = result.getNextMaxId(); + friendshipService.getList(false, profileId, endCursor, this); + } else if (followersModels.size() == 0) { + if (!isFollowersList) moreAvailable = false; + friendshipService.getList(true, profileId, null, followingFetchCb); + } else { + if (!isFollowersList) moreAvailable = false; + showCompare(); + } + } else binding.swipeRefreshLayout.setRefreshing(false); + } + + @Override + public void onFailure(final Throwable t) { + binding.swipeRefreshLayout.setRefreshing(false); + Log.e(TAG, "Error fetching list (double, following)", t); + } + }; + final ServiceCallback followersFetchCb = new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoListFetchResponse result) { + if (result != null) { + followersModels.addAll(result.getItems()); + if (isFollowersList) followModels.addAll(result.getItems()); + if (result.isMoreAvailable()) { + endCursor = result.getNextMaxId(); + friendshipService.getList(true, profileId, endCursor, this); + } else if (followingModels.size() == 0) { + if (isFollowersList) moreAvailable = false; + friendshipService.getList(false, profileId, null, followingFetchCb); + } else { + if (isFollowersList) moreAvailable = false; + showCompare(); + } + } + } + + @Override + public void onFailure(final Throwable t) { + binding.swipeRefreshLayout.setRefreshing(false); + Log.e(TAG, "Error fetching list (double, follower)", t); + } + }; + @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -141,13 +186,13 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh public void onRefresh() { if (isCompare) listCompare(); else listFollows(); + endCursor = null; + lazyLoader.resetState(); } private void listFollows() { - loading = true; type = resources.getString(isFollowersList ? R.string.followers_type_followers : R.string.followers_type_following); setSubtitle(type); - followModels.clear(); final ServiceCallback cb = new ServiceCallback() { @Override public void onSuccess(final FriendshipRepoListFetchResponse result) { @@ -156,16 +201,18 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh return; } else { + int oldSize = followModels.size() == 0 ? 0 : followModels.size() - 1; followModels.addAll(result.getItems()); if (result.isMoreAvailable()) { - friendshipService.getList(isFollowersList, profileId, result.getNextMaxId(), this); - } - else { - binding.swipeRefreshLayout.setRefreshing(false); - if (isFollowersList) followersModels.addAll(followModels); - else followingModels.addAll(followModels); - refreshAdapter(followModels, null, null, null); + moreAvailable = true; + endCursor = result.getNextMaxId(); } + else moreAvailable = false; + binding.swipeRefreshLayout.setRefreshing(false); + if (isFollowersList) followersModels.addAll(result.getItems()); + else followingModels.addAll(result.getItems()); + refreshAdapter(followModels, null, null, null); + layoutManager.scrollToPosition(oldSize); } } @@ -175,64 +222,43 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh Log.e(TAG, "Error fetching list (single)", t); } }; - binding.swipeRefreshLayout.setRefreshing(true); - friendshipService.getList(isFollowersList, profileId, null, cb); + layoutManager = new LinearLayoutManager(getContext()); + lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { + if (!TextUtils.isEmpty(endCursor)) { + binding.swipeRefreshLayout.setRefreshing(true); + friendshipService.getList(isFollowersList, profileId, endCursor, cb); + } + endCursor = null; + }); + binding.rvFollow.addOnScrollListener(lazyLoader); + binding.rvFollow.setLayoutManager(layoutManager); + layoutManager.setStackFromEnd(true); + if (moreAvailable) { + binding.swipeRefreshLayout.setRefreshing(true); + friendshipService.getList(isFollowersList, profileId, endCursor, cb); + } + else { + refreshAdapter(followModels, null, null, null); + layoutManager.scrollToPosition(0); + } } private void listCompare() { + layoutManager.setStackFromEnd(false); + binding.rvFollow.clearOnScrollListeners(); loading = true; setSubtitle(R.string.followers_compare); allFollowing.clear(); - followersModels.clear(); - followingModels.clear(); - final ServiceCallback followingFetchCb = new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoListFetchResponse result) { - if (result != null) { - followingModels.addAll(result.getItems()); - - if (result.isMoreAvailable()) { - friendshipService.getList(false, profileId, result.getNextMaxId(), this); - } else { - showCompare(); - } - } else binding.swipeRefreshLayout.setRefreshing(false); - } - - @Override - public void onFailure(final Throwable t) { - binding.swipeRefreshLayout.setRefreshing(false); - Log.e(TAG, "Error fetching list (double, following)", t); - } - }; - final ServiceCallback followersFetchCb = new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoListFetchResponse result) { - if (result != null) { - followersModels.addAll(result.getItems()); - if (result.isMoreAvailable()) { - friendshipService.getList(true, profileId, result.getNextMaxId(), this); - } else if (followingModels.size() == 0) { - friendshipService.getList(false, profileId, null, followingFetchCb); - } else { - showCompare(); - } - } - } - - @Override - public void onFailure(final Throwable t) { - binding.swipeRefreshLayout.setRefreshing(false); - Log.e(TAG, "Error fetching list (double, follower)", t); - } - }; binding.swipeRefreshLayout.setRefreshing(true); - if (followersModels.size() == 0) { - friendshipService.getList(true, profileId, null, followersFetchCb); - } - else if (followingModels.size() == 0) { - friendshipService.getList(false, profileId, null, followingFetchCb); - } + if (moreAvailable) friendshipService.getList(isFollowersList, + profileId, + endCursor, + isFollowersList ? followersFetchCb : followingFetchCb); + else if (followersModels.size() == 0 || followingModels.size() == 0) + friendshipService.getList(!isFollowersList, + profileId, + null, + isFollowersList ? followingFetchCb : followersFetchCb); else showCompare(); } @@ -346,12 +372,12 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh final Context context = getContext(); if (loading) Toast.makeText(context, R.string.follower_wait_to_load, Toast.LENGTH_LONG).show(); else if (isCompare) { - listFollows(); isCompare = !isCompare; + listFollows(); } else { - listCompare(); isCompare = !isCompare; + listCompare(); } return true; } @@ -371,8 +397,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh if (allFollowing != null && allFollowing.size() > 0) groups.add(new ExpandableGroup(resources.getString(R.string.followers_both_following), allFollowing)); } else { - final ExpandableGroup group = new ExpandableGroup(type, followModels); - groups.add(group); + groups.add(new ExpandableGroup(type, followModels)); } adapter = new FollowAdapter(clickListener, groups); adapter.toggleGroup(0); 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 45bcc334..7c2b4843 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -580,7 +580,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileDetailsBinding.favChip.setText(R.string.added_to_favs); favoriteRepository.insertOrUpdateFavorite(new Favorite( result.getId(), - finalUsername, + profileModel.getUsername(), FavoriteType.USER, profileModel.getName(), profileModel.getSdProfilePic(), @@ -619,10 +619,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe @Override public void onDataNotAvailable() { - final String finalUsername = username.startsWith("@") ? username.substring(1) : username; favoriteRepository.insertOrUpdateFavorite(new Favorite( -1, - finalUsername, + profileModel.getUsername(), FavoriteType.USER, profileModel.getName(), profileModel.getSdProfilePic(), diff --git a/app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java new file mode 100644 index 00000000..dcd65d4a --- /dev/null +++ b/app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java @@ -0,0 +1,19 @@ +package awais.instagrabber.viewmodels; + +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import java.util.List; + +import awais.instagrabber.models.FollowModel; + +public class FollowViewModel extends ViewModel { + private MutableLiveData> list; + + public MutableLiveData> getList() { + if (list == null) { + list = new MutableLiveData<>(); + } + return list; + } +} diff --git a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java index a370b7df..a31eb3b6 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java +++ b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java @@ -153,13 +153,12 @@ public class FriendshipService extends BaseService { }); } - // log in required public void getList(final boolean follower, final String targetUserId, final String maxId, final ServiceCallback callback) { final Map queryMap = new HashMap<>(); - queryMap.put("max_id", maxId == null ? "" : maxId); + if (maxId != null) queryMap.put("max_id", maxId); final Call request = repository.getList(Constants.I_USER_AGENT, targetUserId, follower ? "followers" : "following", @@ -173,7 +172,6 @@ public class FriendshipService extends BaseService { } final String body = response.body(); if (TextUtils.isEmpty(body)) { - callback.onSuccess(null); return; } diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index 527d5952..23017654 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -274,7 +274,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="bottom" - app:constraint_referenced_ids="btnTagged, btnSaved, btnLiked, btnFollow, btnDM" /> + app:constraint_referenced_ids="btnSaved, btnLiked, btnFollow, btnDM" />