From 8105462acb228f823295b32077650fbffcf7a4dd Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 5 Mar 2021 14:06:27 -0500 Subject: [PATCH] add suggestion chaining --- .../viewholder/NotificationViewHolder.java | 8 ++- .../instagrabber/asyncs/CommentsFetcher.java | 8 +-- .../NotificationsViewerFragment.java | 54 ++++++++++++------- .../fragments/main/ProfileFragment.java | 43 +++++++++++---- .../settings/MorePreferencesFragment.java | 4 +- .../repositories/NewsRepository.java | 4 ++ .../responses/NotificationArgs.java | 9 +++- .../repositories/responses/User.java | 9 +++- .../instagrabber/utils/ResponseBodyUtils.java | 3 +- .../webservices/GraphQLService.java | 2 + .../instagrabber/webservices/NewsService.java | 52 ++++++++++++++++-- .../webservices/StoriesService.java | 2 + app/src/main/res/layout/item_notification.xml | 15 ++++++ app/src/main/res/menu/profile_menu.xml | 6 +++ .../navigation/direct_messages_nav_graph.xml | 3 ++ .../res/navigation/discover_nav_graph.xml | 3 ++ .../main/res/navigation/feed_nav_graph.xml | 3 ++ .../main/res/navigation/more_nav_graph.xml | 3 ++ .../notification_viewer_nav_graph.xml | 3 ++ .../main/res/navigation/profile_nav_graph.xml | 3 ++ .../main/res/navigation/saved_nav_graph.xml | 9 ---- 21 files changed, 194 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java index 0d03f9c0..79e84be5 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java @@ -59,8 +59,10 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder { } binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? args.getText() : subtext); if (text == -1 && subtext != null) { - binding.tvComment.setText(subtext); - binding.tvComment.setVisibility(TextUtils.isEmpty(subtext) ? View.GONE : View.VISIBLE); + binding.tvComment.setText(args.getText()); + binding.tvComment.setVisibility(TextUtils.isEmpty(args.getText()) || args.getText().equals(args.getFullName()) + ? View.GONE : View.VISIBLE); + binding.tvSubComment.setText(subtext); binding.tvSubComment.setVisibility(model.getType() == NotificationType.AYML ? View.VISIBLE : View.GONE); } else if (text != -1) { binding.tvComment.setText(text); @@ -72,6 +74,8 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder { binding.tvDate.setText(args.getDateTime()); } + binding.isVerified.setVisibility(args.isVerified() ? View.VISIBLE : View.GONE); + binding.tvUsername.setText(args.getUsername()); binding.ivProfilePic.setImageURI(args.getProfilePic()); binding.ivProfilePic.setOnClickListener(v -> { diff --git a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java index b5ba3d27..48dcc401 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java @@ -115,7 +115,8 @@ public final class CommentsFetcher extends AsyncTask> cb = new ServiceCallback>() { + @Override + public void onSuccess(final List notificationModels) { + binding.swipeRefreshLayout.setRefreshing(false); + notificationViewModel.getList().postValue(notificationModels); + } + + @Override + public void onFailure(final Throwable t) { + try { + binding.swipeRefreshLayout.setRefreshing(false); + Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); + } + catch(Throwable e) {} + } + }; + private final OnNotificationClickListener clickListener = new OnNotificationClickListener() { @Override public void onProfileClick(final String username) { @@ -181,6 +203,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + fragmentActivity = (AppCompatActivity) requireActivity(); context = getContext(); if (context == null) return; NotificationManagerCompat.from(context.getApplicationContext()).cancel(Constants.ACTIVITY_NOTIFICATION_ID); @@ -190,9 +213,10 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe } mediaService = MediaService.getInstance(null, null, 0); final long userId = CookieUtils.getUserIdFromCookie(cookie); - final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); + deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId); + newsService = NewsService.getInstance(); } @NonNull @@ -217,6 +241,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe private void init() { final NotificationsViewerFragmentArgs fragmentArgs = NotificationsViewerFragmentArgs.fromBundle(getArguments()); type = fragmentArgs.getType(); + targetId = fragmentArgs.getTargetId(); final Context context = getContext(); CookieUtils.setupCookies(settingsHelper.getString(Constants.COOKIE)); binding.swipeRefreshLayout.setOnRefreshListener(this); @@ -231,8 +256,10 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe @Override public void onRefresh() { binding.swipeRefreshLayout.setRefreshing(true); + final ActionBar actionBar = fragmentActivity.getSupportActionBar(); switch (type) { case "notif": + if (actionBar != null) actionBar.setTitle(R.string.action_notif); new NotificationsFetcher(true, new FetchListener>() { @Override public void onResult(final List notificationModels) { @@ -251,23 +278,12 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; case "ayml": - final NewsService newsService = NewsService.getInstance(); - newsService.fetchSuggestions(csrfToken, new ServiceCallback>() { - @Override - public void onSuccess(final List notificationModels) { - binding.swipeRefreshLayout.setRefreshing(false); - notificationViewModel.getList().postValue(notificationModels); - } - - @Override - public void onFailure(final Throwable t) { - try { - binding.swipeRefreshLayout.setRefreshing(false); - Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(Throwable e) {} - } - }); + if (actionBar != null) actionBar.setTitle(R.string.action_ayml); + newsService.fetchSuggestions(csrfToken, deviceUuid, cb); + break; + case "chaining": + if (actionBar != null) actionBar.setTitle(R.string.action_ayml); + newsService.fetchChaining(targetId, cb); break; } } 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 86b1504a..a90bac90 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -56,7 +56,6 @@ import awais.instagrabber.R; import awais.instagrabber.activities.MainActivity; import awais.instagrabber.adapters.FeedAdapterV2; import awais.instagrabber.adapters.HighlightsAdapter; -import awais.instagrabber.asyncs.CreateThreadAction; import awais.instagrabber.asyncs.ProfileFetcher; import awais.instagrabber.asyncs.ProfilePostFetchService; import awais.instagrabber.asyncs.UsernameFetcher; @@ -125,6 +124,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private HighlightsViewModel highlightsViewModel; private MenuItem blockMenuItem; private MenuItem restrictMenuItem; + private MenuItem chainingMenuItem; private boolean highlightsFetching; private boolean postsSetupDone = false; private Set selectedFeedModels; @@ -364,11 +364,31 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe inflater.inflate(R.menu.profile_menu, menu); blockMenuItem = menu.findItem(R.id.block); if (blockMenuItem != null) { - blockMenuItem.setVisible(false); + if (profileModel != null) { + blockMenuItem.setVisible(!Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie))); + blockMenuItem.setTitle(profileModel.getFriendshipStatus().isBlocking() ? R.string.unblock : R.string.block); + } else { + blockMenuItem.setVisible(false); + } } restrictMenuItem = menu.findItem(R.id.restrict); if (restrictMenuItem != null) { - restrictMenuItem.setVisible(false); + if (profileModel != null) { + restrictMenuItem.setVisible(!Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie))); + restrictMenuItem.setTitle(profileModel.getFriendshipStatus().isRestricted() ? R.string.unrestrict : R.string.restrict); + } + else { + restrictMenuItem.setVisible(false); + } + } + chainingMenuItem = menu.findItem(R.id.chaining); + if (chainingMenuItem != null) { + if (profileModel != null) { + chainingMenuItem.setVisible(!Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie))); + } + else { + chainingMenuItem.setVisible(false); + } } } @@ -433,6 +453,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe }); return true; } + if (item.getItemId() == R.id.chaining) { + if (!isLoggedIn) return false; + final NavDirections navDirections = ProfileFragmentDirections.actionGlobalNotificationsViewerFragment("chaining", profileModel.getPk()); + NavHostFragment.findNavController(this).navigate(navDirections); + return true; + } return super.onOptionsItemSelected(item); } @@ -884,15 +910,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe blockMenuItem.setTitle(R.string.block); } } - return; - } - if (!isReallyPrivate() && restrictMenuItem != null) { - restrictMenuItem.setVisible(true); - if (profileModel.getFriendshipStatus().isRestricted()) { - restrictMenuItem.setTitle(R.string.unrestrict); - } else { - restrictMenuItem.setTitle(R.string.restrict); + if (chainingMenuItem != null && !Objects.equals(profileId, myId)) { + chainingMenuItem.setVisible(true); } + return; } } diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 55088c8b..fce752e1 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -134,12 +134,12 @@ public class MorePreferencesFragment extends BasePreferencesFragment { screen.addPreference(getDivider(context)); if (isLoggedIn) { screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> { - final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif"); + final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif", 0l); NavHostFragment.findNavController(this).navigate(navDirections); return true; })); screen.addPreference(getPreference(R.string.action_ayml, R.drawable.ic_suggested_users, preference -> { - final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml"); + final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml", 0l); NavHostFragment.findNavController(this).navigate(navDirections); return true; })); diff --git a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java index cd9ec396..0cc89739 100644 --- a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java @@ -4,6 +4,7 @@ import java.util.Map; import awais.instagrabber.repositories.responses.AymlResponse; import awais.instagrabber.repositories.responses.NewsInboxResponse; +import awais.instagrabber.repositories.responses.UserSearchResponse; import retrofit2.Call; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; @@ -23,4 +24,7 @@ public interface NewsRepository { @FormUrlEncoded @POST("/api/v1/discover/ayml/") Call getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map form); + + @GET("/api/v1/discover/chaining/") + Call getChaining(@Header("User-Agent") String userAgent, @Query(value = "target_id") long targetId); } diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java index f66361fa..87116896 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java @@ -20,6 +20,7 @@ public class NotificationArgs { private final double timestamp; private final String profileName; private final String fullName; // for AYML, not naturally generated + private final boolean isVerified; // mostly for AYML, not sure about notif public NotificationArgs(final String text, final String richText, // for AYML, this is the algorithm @@ -28,7 +29,8 @@ public class NotificationArgs { final List media, final double timestamp, final String profileName, - final String fullName) { + final String fullName, + final boolean isVerified) { this.text = text; this.richText = richText; this.profileId = profileId; @@ -37,6 +39,7 @@ public class NotificationArgs { this.timestamp = timestamp; this.profileName = profileName; this.fullName = fullName; + this.isVerified = isVerified; } public String getText() { @@ -67,6 +70,10 @@ public class NotificationArgs { return timestamp; } + public boolean isVerified() { + return isVerified; + } + @NonNull public String getDateTime() { return Utils.datetimeParser.format(new Date(Math.round(timestamp * 1000))); diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/User.java b/app/src/main/java/awais/instagrabber/repositories/responses/User.java index 12f23fdd..3d19077e 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/User.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/User.java @@ -30,6 +30,7 @@ public class User implements Serializable { private final HdProfilePicUrlInfo hdProfilePicUrlInfo; private final String profileContext; private final List profileContextLinksWithUserIds; + private final String socialContext; public User(final long pk, final String username, @@ -55,7 +56,8 @@ public class User implements Serializable { final String publicEmail, final HdProfilePicUrlInfo hdProfilePicUrlInfo, final String profileContext, - final List profileContextLinksWithUserIds) { + final List profileContextLinksWithUserIds, + final String socialContext) { this.pk = pk; this.username = username; this.fullName = fullName; @@ -81,6 +83,7 @@ public class User implements Serializable { this.hdProfilePicUrlInfo = hdProfilePicUrlInfo; this.profileContext = profileContext; this.profileContextLinksWithUserIds = profileContextLinksWithUserIds; + this.socialContext = socialContext; } public long getPk() { @@ -183,6 +186,10 @@ public class User implements Serializable { return profileContext; } + public String getSocialContext() { + return socialContext; + } + public List getProfileContextLinks() { return profileContextLinksWithUserIds; } diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index 30d5ed21..f1281d76 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -782,7 +782,8 @@ public final class ResponseBodyUtils { null, friendshipStatus, owner.optBoolean("is_verified"), - false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, null, null); + false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, + null, null, null); } final String id = feedItem.getString(Constants.EXTRAS_ID); final ImageVersions2 imageVersions2 = new ImageVersions2( diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index aa6a29bd..2af7738c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -245,6 +245,7 @@ public class GraphQLService extends BaseService { null, null, null, + null, null )); // userModels.add(new ProfileModel(userObject.optBoolean("is_private"), @@ -338,6 +339,7 @@ public class GraphQLService extends BaseService { null, null, null, + null, null)); } catch (JSONException e) { Log.e(TAG, "onResponse", e); diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index b450312c..a03ca36d 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -21,6 +21,7 @@ import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.NewsRepository; import awais.instagrabber.repositories.responses.AymlResponse; import awais.instagrabber.repositories.responses.AymlUser; +import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.repositories.responses.NewsInboxResponse; import awais.instagrabber.repositories.responses.Notification; import awais.instagrabber.repositories.responses.NotificationArgs; @@ -126,7 +127,8 @@ public class NewsService extends BaseService { )), data.getLong("timestamp"), user.getString("username"), - null + null, + false ), type, data.getString(Constants.EXTRAS_ID) @@ -150,7 +152,8 @@ public class NewsService extends BaseService { null, 0L, data.getString("username"), - data.optString("full_name") + data.optString("full_name"), + data.optBoolean("is_verified") ), "REQUEST", data.getString(Constants.EXTRAS_ID) @@ -172,6 +175,7 @@ public class NewsService extends BaseService { } public void fetchSuggestions(final String csrfToken, + final String deviceUuid, final ServiceCallback> callback) { final Map form = new HashMap<>(); form.put("_uuid", UUID.randomUUID().toString()); @@ -205,7 +209,8 @@ public class NewsService extends BaseService { null, 0L, u.getUsername(), - u.getFullName() + u.getFullName(), + u.isVerified() ), "AYML", i.getUuid() @@ -222,4 +227,45 @@ public class NewsService extends BaseService { } }); } + + public void fetchChaining(final long targetId, final ServiceCallback> callback) { + final Call request = repository.getChaining(appUa, targetId); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final UserSearchResponse body = response.body(); + if (body == null) { + callback.onSuccess(null); + return; + } + + final List newsItems = body.getUsers().stream() + .map(u -> { + return new Notification( + new NotificationArgs( + u.getSocialContext(), + null, + u.getPk(), + u.getProfilePicUrl(), + null, + 0L, + u.getUsername(), + u.getFullName(), + u.isVerified() + ), + "AYML", + u.getProfilePicId() // placeholder + ); + }) + .collect(Collectors.toList()); + callback.onSuccess(newsItems); + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + callback.onFailure(t); + // Log.e(TAG, "onFailure: ", t); + } + }); + } } diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index faf00f6c..96e6866f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -174,6 +174,7 @@ public class StoriesService extends BaseService { null, null, null, + null, null ); final String id = node.getString("id"); @@ -235,6 +236,7 @@ public class StoriesService extends BaseService { null, null, null, + null, null ); final String id = node.getString("id"); diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml index f17f2c6c..d12c365b 100644 --- a/app/src/main/res/layout/item_notification.xml +++ b/app/src/main/res/layout/item_notification.xml @@ -45,6 +45,21 @@ app:layout_constraintTop_toTopOf="parent" tools:text="username" /> + + + + \ 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 d616f202..a324ff1a 100644 --- a/app/src/main/res/navigation/direct_messages_nav_graph.xml +++ b/app/src/main/res/navigation/direct_messages_nav_graph.xml @@ -41,6 +41,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + diff --git a/app/src/main/res/navigation/discover_nav_graph.xml b/app/src/main/res/navigation/discover_nav_graph.xml index 7b8b83e3..3a2f8483 100644 --- a/app/src/main/res/navigation/discover_nav_graph.xml +++ b/app/src/main/res/navigation/discover_nav_graph.xml @@ -89,6 +89,9 @@ android:name="type" app:argType="string" 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 dd199b6f..f4861fc3 100644 --- a/app/src/main/res/navigation/more_nav_graph.xml +++ b/app/src/main/res/navigation/more_nav_graph.xml @@ -54,6 +54,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + + diff --git a/app/src/main/res/navigation/profile_nav_graph.xml b/app/src/main/res/navigation/profile_nav_graph.xml index e26b966e..f84af5f5 100644 --- a/app/src/main/res/navigation/profile_nav_graph.xml +++ b/app/src/main/res/navigation/profile_nav_graph.xml @@ -80,6 +80,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + diff --git a/app/src/main/res/navigation/saved_nav_graph.xml b/app/src/main/res/navigation/saved_nav_graph.xml index 6813d98c..805a06e5 100644 --- a/app/src/main/res/navigation/saved_nav_graph.xml +++ b/app/src/main/res/navigation/saved_nav_graph.xml @@ -64,15 +64,6 @@ app:nullable="false" /> - - - -