mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-31 03:25:34 +00:00 
			
		
		
		
	Merge branch 'master' into master
This commit is contained in:
		
						commit
						dde740aedf
					
				| @ -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); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -628,9 +628,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe | ||||
|                 return true; | ||||
|             }); | ||||
|         } | ||||
|         if (!profileModel.isReallyPrivate()) { | ||||
|             profileDetailsBinding.mainFollowing.setClickable(true); | ||||
|             profileDetailsBinding.mainFollowers.setClickable(true); | ||||
|         if (!profileModel.isReallyPrivate() && isLoggedIn) { | ||||
|             binding.mainFollowing.setClickable(true); | ||||
|             binding.mainFollowers.setClickable(true); | ||||
| 
 | ||||
|             if (isLoggedIn) { | ||||
|                 final View.OnClickListener followClickListener = v -> { | ||||
|  | ||||
| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user