diff --git a/app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java b/app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java new file mode 100755 index 00000000..5592ee6d --- /dev/null +++ b/app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java @@ -0,0 +1,45 @@ +package awais.instagrabber.adapters; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import awais.instagrabber.adapters.viewholder.FollowsViewHolder; +import awais.instagrabber.databinding.ItemFollowBinding; +import awais.instagrabber.models.ProfileModel; + +public final class LikesAdapter extends RecyclerView.Adapter { + private final List profileModels; + private final View.OnClickListener onClickListener; + + public LikesAdapter(final List profileModels, + final View.OnClickListener onClickListener) { + this.profileModels = profileModels; + this.onClickListener = onClickListener; + } + + @NonNull + @Override + public FollowsViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { + final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + final ItemFollowBinding binding = ItemFollowBinding.inflate(layoutInflater, parent, false); + return new FollowsViewHolder(binding); + } + + @Override + public void onBindViewHolder(@NonNull final FollowsViewHolder holder, final int position) { + final ProfileModel model = profileModels.get(position); + holder.bind(model, null, onClickListener); + } + + @Override + public int getItemCount() { + return profileModels.size(); + } +} \ No newline at end of file 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 a9b09de0..6396d4b2 100755 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java @@ -1,5 +1,6 @@ package awais.instagrabber.adapters.viewholder; +import android.util.Log; import android.view.View; import androidx.recyclerview.widget.RecyclerView; @@ -22,6 +23,7 @@ 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/LikesViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/LikesViewerFragment.java new file mode 100644 index 00000000..40174383 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/LikesViewerFragment.java @@ -0,0 +1,118 @@ +package awais.instagrabber.fragments; + +import android.content.Context; +import android.content.res.Resources; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.LinearLayoutCompat; +import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavDirections; +import androidx.navigation.fragment.NavHostFragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + +import java.util.Collections; +import java.util.List; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.R; +import awais.instagrabber.adapters.LikesAdapter; +import awais.instagrabber.databinding.FragmentLikesBinding; +import awais.instagrabber.models.ProfileModel; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.Utils; +import awais.instagrabber.webservices.MediaService; +import awais.instagrabber.webservices.ServiceCallback; + +public final class LikesViewerFragment extends BottomSheetDialogFragment implements SwipeRefreshLayout.OnRefreshListener { + private static final String TAG = "LikesViewerFragment"; + + private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); + + private LikesAdapter likesAdapter; + private FragmentLikesBinding binding; + private LinearLayoutManager layoutManager; + private Resources resources; + private AppCompatActivity fragmentActivity; + private LinearLayoutCompat root; + private MediaService mediaService; + private String postId; + + private final ServiceCallback> cb = new ServiceCallback>() { + @Override + public void onSuccess(final List result) { + final LikesAdapter likesAdapter = new LikesAdapter(result, v -> { + final Object tag = v.getTag(); + if (tag instanceof ProfileModel) { + ProfileModel model = (ProfileModel) tag; + final Bundle bundle = new Bundle(); + bundle.putString("username", "@" + model.getUsername()); + NavHostFragment.findNavController(LikesViewerFragment.this).navigate(R.id.action_global_profileFragment, bundle); + } + }); + binding.rvLikes.setAdapter(likesAdapter); + binding.rvLikes.setLayoutManager(new LinearLayoutManager(getContext())); + binding.swipeRefreshLayout.setRefreshing(false); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error", t); + try { + final Context context = getContext(); + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } + catch (Exception e) {} + } + }; + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fragmentActivity = (AppCompatActivity) getActivity(); + mediaService = MediaService.getInstance(); + // setHasOptionsMenu(true); + } + + @NonNull + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { + binding = FragmentLikesBinding.inflate(getLayoutInflater()); + binding.swipeRefreshLayout.setEnabled(false); + binding.swipeRefreshLayout.setNestedScrollingEnabled(false); + root = binding.getRoot(); + return root; + } + + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + init(); + } + + @Override + public void onRefresh() { + mediaService.fetchLikes(postId, cb); + } + + private void init() { + if (getArguments() == null) return; + final LikesViewerFragmentArgs fragmentArgs = LikesViewerFragmentArgs.fromBundle(getArguments()); + postId = fragmentArgs.getPostId(); + binding.swipeRefreshLayout.setOnRefreshListener(this); + binding.swipeRefreshLayout.setRefreshing(true); + resources = getResources(); + onRefresh(); + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index ad1fd41d..84fea98e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -535,7 +535,12 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { } }); binding.like.setOnLongClickListener(v -> { - Utils.displayToastAboveView(context, v, getString(R.string.like_without_count)); + final NavController navController = getNavController(); + if (navController != null) { + final Bundle bundle = new Bundle(); + bundle.putString("postId", feedModel.getPostId()); + navController.navigate(R.id.action_global_likesViewerFragment, bundle); + } return true; }); } diff --git a/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java b/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java index 048df6ca..f8e42a21 100644 --- a/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java @@ -5,11 +5,15 @@ import java.util.Map; 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; public interface MediaRepository { + @GET("/api/v1/media/{mediaId}/likers/") + Call fetchLikes(@Header("User-Agent") final String userAgent, + @Path("mediaId") final String mediaId); @FormUrlEncoded @POST("/api/v1/media/{mediaId}/{action}/") diff --git a/app/src/main/java/awais/instagrabber/webservices/MediaService.java b/app/src/main/java/awais/instagrabber/webservices/MediaService.java index decbc85f..f41c14cd 100644 --- a/app/src/main/java/awais/instagrabber/webservices/MediaService.java +++ b/app/src/main/java/awais/instagrabber/webservices/MediaService.java @@ -5,15 +5,18 @@ 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.UUID; +import awais.instagrabber.models.ProfileModel; import awais.instagrabber.repositories.MediaRepository; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Utils; @@ -277,4 +280,48 @@ public class MediaService extends BaseService { } }); } + + public void fetchLikes(final String mediaId, + @NonNull final ServiceCallback> callback) { + final Call likesRequest = repository.fetchLikes(Constants.I_USER_AGENT, mediaId); + likesRequest.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final String body = response.body(); + if (body == null) { + Log.e(TAG, "Error occurred while fetching likes of "+mediaId); + callback.onSuccess(null); + return; + } + try { + final JSONObject data = new JSONObject(body); + final JSONArray users = data.getJSONArray("users"); + final int usersLen = users.length(); + final List userModels = new ArrayList<>(); + for (int j = 0; j < usersLen; ++j) { + final JSONObject userObject = users.getJSONObject(j); + userModels.add(new ProfileModel(userObject.optBoolean("is_private"), + false, + userObject.optBoolean("is_verified"), + String.valueOf(userObject.get("pk")), + userObject.getString("username"), + userObject.optString("full_name"), + null, null, + userObject.getString("profile_pic_url"), + null, 0, 0, 0, false, false, false, false, false)); + } + callback.onSuccess(userModels); + } catch (JSONException e) { + // Log.e(TAG, "Error parsing body", e); + callback.onFailure(e); + } + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + Log.e(TAG, "Error getting likes", t); + callback.onFailure(t); + } + }); + } } diff --git a/app/src/main/res/layout/fragment_likes.xml b/app/src/main/res/layout/fragment_likes.xml new file mode 100644 index 00000000..15d2763d --- /dev/null +++ b/app/src/main/res/layout/fragment_likes.xml @@ -0,0 +1,21 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/direct_messages_nav_graph.xml b/app/src/main/res/navigation/direct_messages_nav_graph.xml index 5ce1b064..87686c3d 100644 --- a/app/src/main/res/navigation/direct_messages_nav_graph.xml +++ b/app/src/main/res/navigation/direct_messages_nav_graph.xml @@ -63,6 +63,17 @@ app:nullable="false" /> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/navigation/likes_nav_graph.xml b/app/src/main/res/navigation/likes_nav_graph.xml new file mode 100644 index 00000000..bd5a2de5 --- /dev/null +++ b/app/src/main/res/navigation/likes_nav_graph.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/location_nav_graph.xml b/app/src/main/res/navigation/location_nav_graph.xml index b787f9eb..100760b3 100644 --- a/app/src/main/res/navigation/location_nav_graph.xml +++ b/app/src/main/res/navigation/location_nav_graph.xml @@ -24,6 +24,17 @@ app:nullable="false" /> + + + + + + diff --git a/app/src/main/res/navigation/more_nav_graph.xml b/app/src/main/res/navigation/more_nav_graph.xml index 50d9cf54..1df73665 100644 --- a/app/src/main/res/navigation/more_nav_graph.xml +++ b/app/src/main/res/navigation/more_nav_graph.xml @@ -8,6 +8,7 @@ + + + + + + + + +