redo follower/ing viewer
Follower/ing viewer now uses the i endpoint (which returns more users at once) as well as caching (less requests needed) so its response time has decreased significantly (to 1/3 in my case)
This commit is contained in:
parent
519d46858b
commit
bf24f56843
@ -1,111 +0,0 @@
|
||||
// package awais.instagrabber.adapters;
|
||||
//
|
||||
// import android.content.Context;
|
||||
// import android.view.LayoutInflater;
|
||||
// import android.view.View;
|
||||
// import android.view.ViewGroup;
|
||||
//
|
||||
// import androidx.annotation.NonNull;
|
||||
// import androidx.recyclerview.widget.DiffUtil;
|
||||
// import androidx.recyclerview.widget.ListAdapter;
|
||||
//
|
||||
// import awais.instagrabber.adapters.viewholder.feed.FeedItemViewHolder;
|
||||
// import awais.instagrabber.adapters.viewholder.feed.FeedPhotoViewHolder;
|
||||
// import awais.instagrabber.adapters.viewholder.feed.FeedSliderViewHolder;
|
||||
// import awais.instagrabber.adapters.viewholder.feed.FeedVideoViewHolder;
|
||||
// import awais.instagrabber.customviews.RamboTextView;
|
||||
// import awais.instagrabber.databinding.ItemFeedPhotoBinding;
|
||||
// import awais.instagrabber.databinding.ItemFeedSliderBinding;
|
||||
// import awais.instagrabber.databinding.ItemFeedVideoBinding;
|
||||
// import awais.instagrabber.interfaces.MentionClickListener;
|
||||
// import awais.instagrabber.models.FeedModel;
|
||||
// import awais.instagrabber.models.enums.MediaItemType;
|
||||
// import awais.instagrabber.utils.Utils;
|
||||
//
|
||||
// public final class FeedAdapter extends ListAdapter<FeedModel, FeedItemViewHolder> {
|
||||
// private static final String TAG = "FeedAdapter";
|
||||
// private final View.OnClickListener clickListener;
|
||||
// private final MentionClickListener mentionClickListener;
|
||||
// private final View.OnLongClickListener longClickListener = v -> {
|
||||
// final Object tag;
|
||||
// if (v instanceof RamboTextView && (tag = v.getTag()) instanceof FeedModel)
|
||||
// Utils.copyText(v.getContext(), ((FeedModel) tag).getPostCaption());
|
||||
// return true;
|
||||
// };
|
||||
//
|
||||
// private static final DiffUtil.ItemCallback<FeedModel> diffCallback = new DiffUtil.ItemCallback<FeedModel>() {
|
||||
// @Override
|
||||
// public boolean areItemsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) {
|
||||
// return oldItem.getPostId().equals(newItem.getPostId());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean areContentsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) {
|
||||
// return oldItem.getPostId().equals(newItem.getPostId());
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// public FeedAdapter(final View.OnClickListener clickListener,
|
||||
// final MentionClickListener mentionClickListener) {
|
||||
// super(diffCallback);
|
||||
// // private final static String ellipsize = "… more";
|
||||
// this.clickListener = clickListener;
|
||||
// this.mentionClickListener = mentionClickListener;
|
||||
// }
|
||||
//
|
||||
// @NonNull
|
||||
// @Override
|
||||
// public FeedItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
// final Context context = parent.getContext();
|
||||
// final LayoutInflater layoutInflater = LayoutInflater.from(context);
|
||||
// final MediaItemType type = MediaItemType.valueOf(viewType);
|
||||
// switch (type) {
|
||||
// case MEDIA_TYPE_VIDEO: {
|
||||
// final ItemFeedVideoBinding binding = ItemFeedVideoBinding.inflate(layoutInflater, parent, false);
|
||||
// return new FeedVideoViewHolder(binding, mentionClickListener, clickListener, longClickListener);
|
||||
// }
|
||||
// case MEDIA_TYPE_SLIDER: {
|
||||
// final ItemFeedSliderBinding binding = ItemFeedSliderBinding.inflate(layoutInflater, parent, false);
|
||||
// return new FeedSliderViewHolder(binding, mentionClickListener, clickListener, longClickListener);
|
||||
// }
|
||||
// case MEDIA_TYPE_IMAGE:
|
||||
// default: {
|
||||
// final ItemFeedPhotoBinding binding = ItemFeedPhotoBinding.inflate(layoutInflater, parent, false);
|
||||
// return new FeedPhotoViewHolder(binding, mentionClickListener, clickListener, longClickListener);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onBindViewHolder(@NonNull final FeedItemViewHolder viewHolder, final int position) {
|
||||
// final FeedModel feedModel = getItem(position);
|
||||
// if (feedModel == null) {
|
||||
// return;
|
||||
// }
|
||||
// feedModel.setPosition(position);
|
||||
// viewHolder.bind(feedModel, (feedModel1, view, postImage) -> {});
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getItemViewType(final int position) {
|
||||
// return getItem(position).getItemType().getId();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onViewAttachedToWindow(@NonNull final FeedItemViewHolder holder) {
|
||||
// super.onViewAttachedToWindow(holder);
|
||||
// // Log.d(TAG, "attached holder: " + holder);
|
||||
// if (!(holder instanceof FeedSliderViewHolder)) return;
|
||||
// final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder;
|
||||
// feedSliderViewHolder.startPlayingVideo();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onViewDetachedFromWindow(@NonNull final FeedItemViewHolder holder) {
|
||||
// super.onViewDetachedFromWindow(holder);
|
||||
// // Log.d(TAG, "detached holder: " + holder);
|
||||
// if (!(holder instanceof FeedSliderViewHolder)) return;
|
||||
// final FeedSliderViewHolder feedSliderViewHolder = (FeedSliderViewHolder) holder;
|
||||
// feedSliderViewHolder.stopPlayingVideo();
|
||||
// }
|
||||
// }
|
@ -1,101 +0,0 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class FollowFetcher extends AsyncTask<Void, Void, FollowModel[]> {
|
||||
private final String endCursor, id;
|
||||
private final boolean isFollowers;
|
||||
private final FetchListener<FollowModel[]> fetchListener;
|
||||
|
||||
public FollowFetcher(final String id, final boolean isFollowers, final FetchListener<FollowModel[]> fetchListener) {
|
||||
this.id = id;
|
||||
this.endCursor = "";
|
||||
this.isFollowers = isFollowers;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
public FollowFetcher(final String id, final boolean isFollowers, final String endCursor, final FetchListener<FollowModel[]> fetchListener) {
|
||||
this.id = id;
|
||||
this.endCursor = endCursor == null ? "" : endCursor;
|
||||
this.isFollowers = isFollowers;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
if (fetchListener != null) fetchListener.doBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FollowModel[] doInBackground(final Void... voids) {
|
||||
FollowModel[] result = null;
|
||||
final String url = "https://www.instagram.com/graphql/query/?query_id=" + (isFollowers ? "17851374694183129" : "17874545323001329")
|
||||
+ "&id=" + id + "&first=50&after=" + endCursor;
|
||||
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setInstanceFollowRedirects(false);
|
||||
conn.setUseCaches(false);
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject(Constants.EXTRAS_USER).getJSONObject(isFollowers ? "edge_followed_by" : "edge_follow");
|
||||
|
||||
final String endCursor;
|
||||
final boolean hasNextPage;
|
||||
|
||||
final JSONObject pageInfo = data.getJSONObject("page_info");
|
||||
if (pageInfo.has("has_next_page")) {
|
||||
hasNextPage = pageInfo.getBoolean("has_next_page");
|
||||
endCursor = hasNextPage ? pageInfo.getString("end_cursor") : null;
|
||||
} else {
|
||||
hasNextPage = false;
|
||||
endCursor = null;
|
||||
}
|
||||
|
||||
final JSONArray edges = data.getJSONArray("edges");
|
||||
final FollowModel[] models = new FollowModel[edges.length()];
|
||||
for (int i = 0; i < models.length; ++i) {
|
||||
final JSONObject followNode = edges.getJSONObject(i).getJSONObject("node");
|
||||
models[i] = new FollowModel(followNode.getString(Constants.EXTRAS_ID), followNode.getString(Constants.EXTRAS_USERNAME),
|
||||
followNode.getString("full_name"), followNode.getString("profile_pic_url"));
|
||||
}
|
||||
|
||||
if (models[models.length - 1] != null)
|
||||
models[models.length - 1].setPageCursor(hasNextPage, endCursor);
|
||||
|
||||
result = models;
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_FOLLOW_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final FollowModel[] result) {
|
||||
if (fetchListener != null) fetchListener.onResult(result);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package awais.instagrabber.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
@ -10,6 +11,7 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -26,15 +28,20 @@ import java.util.Arrays;
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.FollowAdapter;
|
||||
import awais.instagrabber.asyncs.FollowFetcher;
|
||||
import awais.instagrabber.databinding.FragmentFollowersViewerBinding;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
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";
|
||||
@ -44,7 +51,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
private final ArrayList<FollowModel> followersModels = new ArrayList<>();
|
||||
private final ArrayList<FollowModel> allFollowing = new ArrayList<>();
|
||||
|
||||
private boolean isFollowersList, isCompare = false;
|
||||
private boolean isFollowersList, isCompare = false, loading = false;
|
||||
private String profileId, username, namePost, type;
|
||||
private Resources resources;
|
||||
private FollowModel model;
|
||||
@ -53,12 +60,14 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
private FragmentFollowersViewerBinding binding;
|
||||
private AsyncTask<Void, Void, FollowModel[]> currentlyExecuting;
|
||||
private SwipeRefreshLayout root;
|
||||
private FriendshipService friendshipService;
|
||||
private boolean shouldRefresh = true;
|
||||
private AppCompatActivity fragmentActivity;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
friendshipService = FriendshipService.getInstance();
|
||||
fragmentActivity = (AppCompatActivity) getActivity();
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
@ -135,102 +144,114 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
}
|
||||
|
||||
private void listFollows() {
|
||||
stopCurrentExecutor();
|
||||
loading = true;
|
||||
type = resources.getString(isFollowersList ? R.string.followers_type_followers : R.string.followers_type_following);
|
||||
setSubtitle(type);
|
||||
followModels.clear();
|
||||
final FetchListener<FollowModel[]> fetchListener = new FetchListener<FollowModel[]>() {
|
||||
final ServiceCallback<FriendshipRepoListFetchResponse> cb = new ServiceCallback<FriendshipRepoListFetchResponse>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final FollowModel[] result) {
|
||||
if (result == null) binding.swipeRefreshLayout.setRefreshing(false);
|
||||
public void onSuccess(final FriendshipRepoListFetchResponse result) {
|
||||
if (result == null) {
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
followModels.addAll(Arrays.asList(result));
|
||||
|
||||
final FollowModel model = result[result.length - 1];
|
||||
if (model != null && model.hasNextPage()) {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(profileId, isFollowersList, model.getEndCursor(), this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
model.setPageCursor(false, null);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
Log.e(TAG, "Error fetching list (single)", t);
|
||||
}
|
||||
};
|
||||
currentlyExecuting = new FollowFetcher(profileId, isFollowersList, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
friendshipService.getList(isFollowersList, profileId, null, cb);
|
||||
}
|
||||
|
||||
private void listCompare() {
|
||||
stopCurrentExecutor();
|
||||
loading = true;
|
||||
setSubtitle(R.string.followers_compare);
|
||||
allFollowing.clear();
|
||||
followersModels.clear();
|
||||
followingModels.clear();
|
||||
final FetchListener<FollowModel[]> followingFetchListener = new FetchListener<FollowModel[]>() {
|
||||
final ServiceCallback<FriendshipRepoListFetchResponse> followingFetchCb = new ServiceCallback<FriendshipRepoListFetchResponse>() {
|
||||
@Override
|
||||
public void onResult(final FollowModel[] result) {
|
||||
public void onSuccess(final FriendshipRepoListFetchResponse result) {
|
||||
if (result != null) {
|
||||
followingModels.addAll(Arrays.asList(result));
|
||||
followingModels.addAll(result.getItems());
|
||||
|
||||
final FollowModel model = result[result.length - 1];
|
||||
if (model != null && model.hasNextPage()) {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(profileId, false, model.getEndCursor(), this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
model.setPageCursor(false, null);
|
||||
if (result.isMoreAvailable()) {
|
||||
friendshipService.getList(false, profileId, result.getNextMaxId(), this);
|
||||
} else {
|
||||
allFollowing.addAll(followersModels);
|
||||
allFollowing.retainAll(followingModels);
|
||||
|
||||
for (final FollowModel followModel : allFollowing) {
|
||||
followersModels.remove(followModel);
|
||||
followingModels.remove(followModel);
|
||||
}
|
||||
|
||||
allFollowing.trimToSize();
|
||||
followersModels.trimToSize();
|
||||
followingModels.trimToSize();
|
||||
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
|
||||
refreshAdapter(null, followingModels, followersModels, allFollowing);
|
||||
showCompare();
|
||||
}
|
||||
} else binding.swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
};
|
||||
final FetchListener<FollowModel[]> followersFetchListener = new FetchListener<FollowModel[]>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final FollowModel[] result) {
|
||||
public void onFailure(final Throwable t) {
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
Log.e(TAG, "Error fetching list (double, following)", t);
|
||||
}
|
||||
};
|
||||
final ServiceCallback<FriendshipRepoListFetchResponse> followersFetchCb = new ServiceCallback<FriendshipRepoListFetchResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final FriendshipRepoListFetchResponse result) {
|
||||
if (result != null) {
|
||||
followersModels.addAll(Arrays.asList(result));
|
||||
final FollowModel model = result[result.length - 1];
|
||||
if (model == null || !model.hasNextPage()) {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(profileId, false, followingFetchListener)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
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 {
|
||||
stopCurrentExecutor();
|
||||
currentlyExecuting = new FollowFetcher(profileId, true, model.getEndCursor(), this)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
model.setPageCursor(false, null);
|
||||
showCompare();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
Log.e(TAG, "Error fetching list (double, follower)", t);
|
||||
}
|
||||
};
|
||||
currentlyExecuting = new FollowFetcher(profileId, true, followersFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
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);
|
||||
}
|
||||
else showCompare();
|
||||
}
|
||||
|
||||
private void showCompare() {
|
||||
allFollowing.addAll(followersModels);
|
||||
allFollowing.retainAll(followingModels);
|
||||
|
||||
for (final FollowModel followModel : allFollowing) {
|
||||
followersModels.remove(followModel);
|
||||
followingModels.remove(followModel);
|
||||
}
|
||||
|
||||
allFollowing.trimToSize();
|
||||
followersModels.trimToSize();
|
||||
followingModels.trimToSize();
|
||||
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
|
||||
refreshAdapter(null, followingModels, followersModels, allFollowing);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -322,9 +343,16 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||
if (item.getItemId() != R.id.action_compare) return super.onOptionsItemSelected(item);
|
||||
binding.rvFollow.setAdapter(null);
|
||||
if (isCompare) listFollows();
|
||||
else listCompare();
|
||||
isCompare = !isCompare;
|
||||
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;
|
||||
}
|
||||
else {
|
||||
listCompare();
|
||||
isCompare = !isCompare;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -332,6 +360,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
final ArrayList<FollowModel> followingModels,
|
||||
final ArrayList<FollowModel> followersModels,
|
||||
final ArrayList<FollowModel> allFollowing) {
|
||||
loading = false;
|
||||
final ArrayList<ExpandableGroup> groups = new ArrayList<>(1);
|
||||
|
||||
if (isCompare) {
|
||||
@ -349,18 +378,4 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
adapter.toggleGroup(0);
|
||||
binding.rvFollow.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public 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(TAG, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -612,7 +612,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (!profileModel.isReallyPrivate()) {
|
||||
if (!profileModel.isReallyPrivate() && isLoggedIn) {
|
||||
binding.mainFollowing.setClickable(true);
|
||||
binding.mainFollowers.setClickable(true);
|
||||
|
||||
|
@ -3,13 +3,16 @@ package awais.instagrabber.repositories;
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse;
|
||||
import awais.instagrabber.repositories.responses.FriendshipRepoListFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.FriendshipRepoRestrictRootResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.FieldMap;
|
||||
import retrofit2.http.FormUrlEncoded;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Header;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
public interface FriendshipRepository {
|
||||
|
||||
@ -25,4 +28,10 @@ public interface FriendshipRepository {
|
||||
Call<FriendshipRepoRestrictRootResponse> toggleRestrict(@Header("User-Agent") String userAgent,
|
||||
@Path("action") String action,
|
||||
@FieldMap Map<String, String> form);
|
||||
|
||||
@GET("/api/v1/friendships/{userId}/{type}/")
|
||||
Call<String> getList(@Header("User-Agent") String userAgent,
|
||||
@Path("userId") String userId,
|
||||
@Path("type") String type, // following or followers
|
||||
@QueryMap(encoded = true) Map<String, String> queryParams);
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class FriendshipRepoListFetchResponse {
|
||||
private String nextMaxId;
|
||||
private String status;
|
||||
private List<FollowModel> items;
|
||||
|
||||
public FriendshipRepoListFetchResponse(final String nextMaxId,
|
||||
final String status,
|
||||
final List<FollowModel> items) {
|
||||
this.nextMaxId = nextMaxId;
|
||||
this.status = status;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public boolean isMoreAvailable() {
|
||||
return !TextUtils.isEmpty(nextMaxId);
|
||||
}
|
||||
|
||||
public String getNextMaxId() {
|
||||
return nextMaxId;
|
||||
}
|
||||
|
||||
public FriendshipRepoListFetchResponse setNextMaxId(final String nextMaxId) {
|
||||
this.nextMaxId = nextMaxId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public FriendshipRepoListFetchResponse setStatus(final String status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<FollowModel> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public FriendshipRepoListFetchResponse setItems(final List<FollowModel> items) {
|
||||
this.items = items;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final FriendshipRepoListFetchResponse that = (FriendshipRepoListFetchResponse) o;
|
||||
return Objects.equals(nextMaxId, that.nextMaxId) &&
|
||||
Objects.equals(status, that.status) &&
|
||||
Objects.equals(items, that.items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(nextMaxId, status, items);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FriendshipRepoListFetchResponse{" +
|
||||
"nextMaxId='" + nextMaxId + '\'' +
|
||||
", status='" + status + '\'' +
|
||||
", items=" + items +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,15 +1,28 @@
|
||||
package awais.instagrabber.webservices;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.repositories.FriendshipRepository;
|
||||
import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse;
|
||||
import awais.instagrabber.repositories.responses.FriendshipRepoListFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.FriendshipRepoRestrictRootResponse;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
@ -139,4 +152,79 @@ public class FriendshipService extends BaseService {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// log in required
|
||||
public void getList(final boolean follower,
|
||||
final String targetUserId,
|
||||
final String maxId,
|
||||
final ServiceCallback<FriendshipRepoListFetchResponse> callback) {
|
||||
final Map<String, String> queryMap = new HashMap<>();
|
||||
queryMap.put("max_id", maxId == null ? "" : maxId);
|
||||
final Call<String> request = repository.getList(Constants.I_USER_AGENT,
|
||||
targetUserId,
|
||||
follower ? "followers" : "following",
|
||||
queryMap);
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
try {
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
final String body = response.body();
|
||||
if (TextUtils.isEmpty(body)) {
|
||||
|
||||
callback.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
final FriendshipRepoListFetchResponse friendshipListFetchResponse = parseListResponse(body);
|
||||
callback.onSuccess(friendshipListFetchResponse);
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "onResponse", e);
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||
if (callback != null) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private FriendshipRepoListFetchResponse parseListResponse(@NonNull final String body) throws JSONException {
|
||||
final JSONObject root = new JSONObject(body);
|
||||
final String nextMaxId = root.optString("next_max_id");
|
||||
final String status = root.optString("status");
|
||||
final JSONArray itemsJson = root.optJSONArray("users");
|
||||
final List<FollowModel> items = parseItems(itemsJson);
|
||||
return new FriendshipRepoListFetchResponse(
|
||||
nextMaxId,
|
||||
status,
|
||||
items
|
||||
);
|
||||
}
|
||||
|
||||
private List<FollowModel> parseItems(final JSONArray items) throws JSONException {
|
||||
if (items == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<FollowModel> followModels = new ArrayList<>();
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
final JSONObject itemJson = items.optJSONObject(i);
|
||||
if (itemJson == null) {
|
||||
continue;
|
||||
}
|
||||
final FollowModel followModel = new FollowModel(itemJson.getString("pk"),
|
||||
itemJson.getString("username"),
|
||||
itemJson.optString("full_name"),
|
||||
itemJson.getString("profile_pic_url"));
|
||||
if (followModel != null) {
|
||||
followModels.add(followModel);
|
||||
}
|
||||
}
|
||||
return followModels;
|
||||
}
|
||||
}
|
||||
|
@ -328,6 +328,7 @@
|
||||
<string name="corners">Corners</string>
|
||||
<string name="show_grid_gap">Show grid gap</string>
|
||||
<string name="disable_animation">Disable animation</string>
|
||||
<string name="follower_wait_to_load">Please wait for the current task to complete first!</string>
|
||||
<plurals name="likes_count">
|
||||
<item quantity="one">%d like</item>
|
||||
<item quantity="other">%d likes</item>
|
||||
|
Loading…
Reference in New Issue
Block a user