mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-26 00:27:30 +00:00
activity: support for app inbox #114, better onclick, etc
This commit is contained in:
parent
d5161ac2ea
commit
49ba524305
@ -76,16 +76,23 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
|
|||||||
private List<NotificationModel> sort(final List<NotificationModel> list) {
|
private List<NotificationModel> sort(final List<NotificationModel> list) {
|
||||||
final List<NotificationModel> listCopy = new ArrayList<>(list);
|
final List<NotificationModel> listCopy = new ArrayList<>(list);
|
||||||
Collections.sort(listCopy, (o1, o2) -> {
|
Collections.sort(listCopy, (o1, o2) -> {
|
||||||
if (o1.getType() == o2.getType()) return 0;
|
|
||||||
// keep requests at top
|
// keep requests at top
|
||||||
if (o1.getType() == NotificationType.REQUEST) return -1;
|
if (o1.getType() == o2.getType()
|
||||||
if (o2.getType() == NotificationType.REQUEST) return 1;
|
&& o1.getType() == NotificationType.REQUEST
|
||||||
return 0;
|
&& o2.getType() == NotificationType.REQUEST) return 0;
|
||||||
|
else if (o1.getType() == NotificationType.REQUEST) return -1;
|
||||||
|
else if (o2.getType() == NotificationType.REQUEST) return 1;
|
||||||
|
// timestamp
|
||||||
|
return o1.getTimestamp() > o2.getTimestamp() ? -1 : (o1.getTimestamp() == o2.getTimestamp() ? 0 : 1);
|
||||||
});
|
});
|
||||||
return listCopy;
|
return listCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface OnNotificationClickListener {
|
public interface OnNotificationClickListener {
|
||||||
void onNotificationClick(final NotificationModel model);
|
void onNotificationClick(final NotificationModel model);
|
||||||
|
|
||||||
|
void onProfileClick(final String username);
|
||||||
|
|
||||||
|
void onPreviewClick(final NotificationModel model);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,10 +24,6 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
|||||||
public void bind(final NotificationModel model,
|
public void bind(final NotificationModel model,
|
||||||
final OnNotificationClickListener notificationClickListener) {
|
final OnNotificationClickListener notificationClickListener) {
|
||||||
if (model == null) return;
|
if (model == null) return;
|
||||||
itemView.setOnClickListener(v -> {
|
|
||||||
if (notificationClickListener == null) return;
|
|
||||||
notificationClickListener.onNotificationClick(model);
|
|
||||||
});
|
|
||||||
int text = -1;
|
int text = -1;
|
||||||
CharSequence subtext = null;
|
CharSequence subtext = null;
|
||||||
switch (model.getType()) {
|
switch (model.getType()) {
|
||||||
@ -52,20 +48,47 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
|||||||
text = R.string.request_notif;
|
text = R.string.request_notif;
|
||||||
subtext = model.getText();
|
subtext = model.getText();
|
||||||
break;
|
break;
|
||||||
|
case COMMENT_LIKE:
|
||||||
|
case TAGGED_COMMENT:
|
||||||
|
case RESPONDED_STORY:
|
||||||
|
subtext = model.getText();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
binding.tvUsername.setText(model.getUsername());
|
if (text == -1 && subtext != null) {
|
||||||
binding.tvComment.setText(text);
|
binding.tvComment.setText(subtext);
|
||||||
binding.tvSubComment.setText(subtext, subtext instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL);
|
binding.tvSubComment.setVisibility(View.GONE);
|
||||||
// binding.tvSubComment.setMentionClickListener(mentionClickListener);
|
}
|
||||||
|
else if (text != -1) {
|
||||||
|
binding.tvComment.setText(text);
|
||||||
|
binding.tvSubComment.setText(subtext);
|
||||||
|
binding.tvSubComment.setVisibility(subtext == null ? View.GONE : View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
if (model.getType() != NotificationType.REQUEST) {
|
if (model.getType() != NotificationType.REQUEST) {
|
||||||
binding.tvDate.setText(model.getDateTime());
|
binding.tvDate.setText(model.getDateTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.tvUsername.setText(model.getUsername());
|
||||||
binding.ivProfilePic.setImageURI(model.getProfilePic());
|
binding.ivProfilePic.setImageURI(model.getProfilePic());
|
||||||
|
binding.ivProfilePic.setOnClickListener(v -> {
|
||||||
|
if (notificationClickListener == null) return;
|
||||||
|
notificationClickListener.onProfileClick(model.getUsername());
|
||||||
|
});
|
||||||
|
|
||||||
if (TextUtils.isEmpty(model.getPreviewPic())) {
|
if (TextUtils.isEmpty(model.getPreviewPic())) {
|
||||||
binding.ivPreviewPic.setVisibility(View.GONE);
|
binding.ivPreviewPic.setVisibility(View.INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
||||||
binding.ivPreviewPic.setImageURI(model.getPreviewPic());
|
binding.ivPreviewPic.setImageURI(model.getPreviewPic());
|
||||||
|
binding.ivPreviewPic.setOnClickListener(v -> {
|
||||||
|
if (notificationClickListener == null) return;
|
||||||
|
notificationClickListener.onPreviewClick(model);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemView.setOnClickListener(v -> {
|
||||||
|
if (notificationClickListener == null) return;
|
||||||
|
notificationClickListener.onNotificationClick(model);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,12 +16,21 @@ import awais.instagrabber.utils.TextUtils;
|
|||||||
public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> {
|
public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> {
|
||||||
private static final String TAG = "GetActivityAsyncTask";
|
private static final String TAG = "GetActivityAsyncTask";
|
||||||
|
|
||||||
private OnTaskCompleteListener onTaskCompleteListener;
|
private final OnTaskCompleteListener onTaskCompleteListener;
|
||||||
|
|
||||||
public GetActivityAsyncTask(final OnTaskCompleteListener onTaskCompleteListener) {
|
public GetActivityAsyncTask(final OnTaskCompleteListener onTaskCompleteListener) {
|
||||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This needs to be redone to fetch i inbox instead
|
||||||
|
Within inbox, data is (body JSON => counts)
|
||||||
|
Then we have these counts:
|
||||||
|
new_posts, activity_feed_dot_badge, relationships, campaign_notification
|
||||||
|
usertags, likes, comment_likes, shopping_notification, comments
|
||||||
|
photos_of_you (not sure about difference to usertags), requests
|
||||||
|
*/
|
||||||
|
|
||||||
protected NotificationCounts doInBackground(final String... cookiesArray) {
|
protected NotificationCounts doInBackground(final String... cookiesArray) {
|
||||||
if (cookiesArray == null) return null;
|
if (cookiesArray == null) return null;
|
||||||
final String cookie = cookiesArray[0];
|
final String cookie = cookiesArray[0];
|
||||||
@ -70,11 +79,11 @@ public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsy
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class NotificationCounts {
|
public static class NotificationCounts {
|
||||||
private int relationshipsCount;
|
private final int relationshipsCount;
|
||||||
private int userTagsCount;
|
private final int userTagsCount;
|
||||||
private int commentsCount;
|
private final int commentsCount;
|
||||||
private int commentLikesCount;
|
private final int commentLikesCount;
|
||||||
private int likesCount;
|
private final int likesCount;
|
||||||
|
|
||||||
public NotificationCounts(final int relationshipsCount,
|
public NotificationCounts(final int relationshipsCount,
|
||||||
final int userTagsCount,
|
final int userTagsCount,
|
||||||
|
@ -3,21 +3,14 @@ package awais.instagrabber.asyncs;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.interfaces.FetchListener;
|
import awais.instagrabber.interfaces.FetchListener;
|
||||||
import awais.instagrabber.models.NotificationModel;
|
import awais.instagrabber.models.NotificationModel;
|
||||||
import awais.instagrabber.models.enums.NotificationType;
|
import awais.instagrabber.webservices.NewsService;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.utils.LocaleUtils;
|
|
||||||
import awais.instagrabber.utils.NetworkUtils;
|
|
||||||
import awaisomereport.LogCollector;
|
import awaisomereport.LogCollector;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.logCollector;
|
import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
@ -26,89 +19,48 @@ public final class NotificationsFetcher extends AsyncTask<Void, Void, List<Notif
|
|||||||
private static final String TAG = "NotificationsFetcher";
|
private static final String TAG = "NotificationsFetcher";
|
||||||
|
|
||||||
private final FetchListener<List<NotificationModel>> fetchListener;
|
private final FetchListener<List<NotificationModel>> fetchListener;
|
||||||
|
private final NewsService newsService;
|
||||||
|
private final boolean markAsSeen;
|
||||||
|
private boolean fetchedWeb = false;
|
||||||
|
|
||||||
public NotificationsFetcher(final FetchListener<List<NotificationModel>> fetchListener) {
|
public NotificationsFetcher(final boolean markAsSeen,
|
||||||
|
final FetchListener<List<NotificationModel>> fetchListener) {
|
||||||
|
this.markAsSeen = markAsSeen;
|
||||||
this.fetchListener = fetchListener;
|
this.fetchListener = fetchListener;
|
||||||
|
newsService = NewsService.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<NotificationModel> doInBackground(final Void... voids) {
|
protected List<NotificationModel> doInBackground(final Void... voids) {
|
||||||
List<NotificationModel> result = new ArrayList<>();
|
List<NotificationModel> notificationModels = new ArrayList<>();
|
||||||
final String url = "https://www.instagram.com/accounts/activity/?__a=1";
|
|
||||||
try {
|
|
||||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
|
||||||
conn.setInstanceFollowRedirects(false);
|
|
||||||
conn.setUseCaches(false);
|
|
||||||
conn.setRequestProperty("Accept-Language", LocaleUtils.getCurrentLocale().getLanguage() + ",en-US;q=0.8");
|
|
||||||
conn.connect();
|
|
||||||
|
|
||||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
newsService.fetchAppInbox(markAsSeen, new ServiceCallback<List<NotificationModel>>() {
|
||||||
final JSONObject page = new JSONObject(NetworkUtils.readFromConnection(conn))
|
@Override
|
||||||
.getJSONObject("graphql")
|
public void onSuccess(final List<NotificationModel> result) {
|
||||||
.getJSONObject("user");
|
if (result == null) return;
|
||||||
final JSONObject ewaf = page.getJSONObject("activity_feed")
|
notificationModels.addAll(result);
|
||||||
.optJSONObject("edge_web_activity_feed");
|
if (fetchedWeb) {
|
||||||
final JSONObject efr = page.optJSONObject("edge_follow_requests");
|
fetchListener.onResult(notificationModels);
|
||||||
JSONObject data;
|
|
||||||
JSONArray media;
|
|
||||||
if (ewaf != null
|
|
||||||
&& (media = ewaf.optJSONArray("edges")) != null
|
|
||||||
&& media.length() > 0
|
|
||||||
&& media.optJSONObject(0).optJSONObject("node") != null) {
|
|
||||||
for (int i = 0; i < media.length(); ++i) {
|
|
||||||
data = media.optJSONObject(i).optJSONObject("node");
|
|
||||||
if (data == null) continue;
|
|
||||||
final String type = data.getString("__typename");
|
|
||||||
final NotificationType notificationType = NotificationType.valueOfType(type);
|
|
||||||
if (notificationType == null) continue;
|
|
||||||
final JSONObject user = data.getJSONObject("user");
|
|
||||||
result.add(new NotificationModel(
|
|
||||||
data.getString(Constants.EXTRAS_ID),
|
|
||||||
data.optString("text"), // comments or mentions
|
|
||||||
data.getLong("timestamp"),
|
|
||||||
user.getString("id"),
|
|
||||||
user.getString("username"),
|
|
||||||
user.getString("profile_pic_url"),
|
|
||||||
!data.isNull("media") ? data.getJSONObject("media").getString("shortcode") : null,
|
|
||||||
!data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, notificationType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if (efr != null
|
fetchedWeb = true;
|
||||||
&& (media = efr.optJSONArray("edges")) != null
|
newsService.fetchWebInbox(markAsSeen, this);
|
||||||
&& media.length() > 0
|
|
||||||
&& media.optJSONObject(0).optJSONObject("node") != null) {
|
|
||||||
for (int i = 0; i < media.length(); ++i) {
|
|
||||||
data = media.optJSONObject(i).optJSONObject("node");
|
|
||||||
if (data == null) continue;
|
|
||||||
result.add(new NotificationModel(
|
|
||||||
data.getString(Constants.EXTRAS_ID),
|
|
||||||
data.optString("full_name"),
|
|
||||||
0L,
|
|
||||||
data.getString(Constants.EXTRAS_ID),
|
|
||||||
data.getString("username"),
|
|
||||||
data.getString("profile_pic_url"),
|
|
||||||
null,
|
|
||||||
null, NotificationType.REQUEST));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn.disconnect();
|
|
||||||
} catch (final Exception e) {
|
@Override
|
||||||
if (logCollector != null)
|
public void onFailure(final Throwable t) {
|
||||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_NOTIFICATION_FETCHER, "doInBackground");
|
// Log.e(TAG, "onFailure: ", t);
|
||||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
if (fetchListener != null) {
|
||||||
}
|
fetchListener.onFailure(t);
|
||||||
return result;
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return notificationModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
if (fetchListener != null) fetchListener.doBefore();
|
if (fetchListener != null) fetchListener.doBefore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(final List<NotificationModel> result) {
|
|
||||||
if (fetchListener != null) fetchListener.onResult(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -18,6 +18,8 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.navigation.NavDirections;
|
import androidx.navigation.NavDirections;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
@ -30,8 +32,11 @@ import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListe
|
|||||||
import awais.instagrabber.asyncs.NotificationsFetcher;
|
import awais.instagrabber.asyncs.NotificationsFetcher;
|
||||||
import awais.instagrabber.asyncs.PostFetcher;
|
import awais.instagrabber.asyncs.PostFetcher;
|
||||||
import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
|
import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
|
||||||
|
import awais.instagrabber.dialogs.ProfilePicDialogFragment;
|
||||||
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
||||||
import awais.instagrabber.interfaces.MentionClickListener;
|
import awais.instagrabber.interfaces.MentionClickListener;
|
||||||
|
import awais.instagrabber.models.FeedModel;
|
||||||
|
import awais.instagrabber.models.NotificationModel;
|
||||||
import awais.instagrabber.models.enums.NotificationType;
|
import awais.instagrabber.models.enums.NotificationType;
|
||||||
import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse;
|
import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
@ -40,8 +45,10 @@ import awais.instagrabber.utils.TextUtils;
|
|||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.viewmodels.NotificationViewModel;
|
import awais.instagrabber.viewmodels.NotificationViewModel;
|
||||||
import awais.instagrabber.webservices.FriendshipService;
|
import awais.instagrabber.webservices.FriendshipService;
|
||||||
|
import awais.instagrabber.webservices.MediaService;
|
||||||
import awais.instagrabber.webservices.NewsService;
|
import awais.instagrabber.webservices.NewsService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
|
import awais.instagrabber.webservices.StoriesService;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
@ -53,96 +60,153 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
private boolean shouldRefresh = true;
|
private boolean shouldRefresh = true;
|
||||||
private NotificationViewModel notificationViewModel;
|
private NotificationViewModel notificationViewModel;
|
||||||
private FriendshipService friendshipService;
|
private FriendshipService friendshipService;
|
||||||
|
private MediaService mediaService;
|
||||||
|
private StoriesService storiesService;
|
||||||
private String userId;
|
private String userId;
|
||||||
private String csrfToken;
|
private String csrfToken;
|
||||||
private NewsService newsService;
|
private NewsService newsService;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
private final OnNotificationClickListener clickListener = model -> {
|
private final OnNotificationClickListener clickListener = new OnNotificationClickListener() {
|
||||||
if (model == null) return;
|
@Override
|
||||||
final String username = model.getUsername();
|
public void onProfileClick(final String username) {
|
||||||
final SpannableString title = new SpannableString(username + (TextUtils.isEmpty(model.getText()) ? "" : (":\n" + model.getText())));
|
openProfile(username);
|
||||||
title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
|
||||||
|
|
||||||
String[] commentDialogList;
|
|
||||||
if (model.getShortCode() != null) {
|
|
||||||
commentDialogList = new String[]{
|
|
||||||
getString(R.string.open_profile),
|
|
||||||
getString(R.string.view_post)
|
|
||||||
};
|
|
||||||
} else if (model.getType() == NotificationType.REQUEST) {
|
|
||||||
commentDialogList = new String[]{
|
|
||||||
getString(R.string.open_profile),
|
|
||||||
getString(R.string.request_approve),
|
|
||||||
getString(R.string.request_reject)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
commentDialogList = new String[]{getString(R.string.open_profile)};
|
|
||||||
}
|
}
|
||||||
final Context context = getContext();
|
|
||||||
if (context == null) return;
|
|
||||||
final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
|
|
||||||
switch (which) {
|
|
||||||
case 0:
|
|
||||||
openProfile(model.getUsername());
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (model.getType() == NotificationType.REQUEST) {
|
|
||||||
friendshipService.approve(userId, model.getUserId(), csrfToken, new ServiceCallback<FriendshipRepoChangeRootResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(final FriendshipRepoChangeRootResponse result) {
|
|
||||||
// Log.d(TAG, "onSuccess: " + result);
|
|
||||||
if (result.getStatus().equals("ok")) {
|
|
||||||
onRefresh();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Log.e(TAG, "approve: status was not ok!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(final Throwable t) {
|
public void onPreviewClick(final NotificationModel model) {
|
||||||
Log.e(TAG, "approve: onFailure: ", t);
|
if (model.getType() == NotificationType.RESPONDED_STORY) {
|
||||||
}
|
showProfilePicDialog(model);
|
||||||
});
|
}
|
||||||
return;
|
else {
|
||||||
}
|
mediaService.fetch(model.getPostId(), new ServiceCallback<FeedModel>() {
|
||||||
final AlertDialog alertDialog = new AlertDialog.Builder(context)
|
@Override
|
||||||
.setCancelable(false)
|
public void onSuccess(final FeedModel feedModel) {
|
||||||
.setView(R.layout.dialog_opening_post)
|
|
||||||
.create();
|
|
||||||
alertDialog.show();
|
|
||||||
new PostFetcher(model.getShortCode(), feedModel -> {
|
|
||||||
final PostViewV2Fragment fragment = PostViewV2Fragment
|
final PostViewV2Fragment fragment = PostViewV2Fragment
|
||||||
.builder(feedModel)
|
.builder(feedModel)
|
||||||
.build();
|
.build();
|
||||||
fragment.setOnShowListener(dialog1 -> alertDialog.dismiss());
|
|
||||||
fragment.show(getChildFragmentManager(), "post_view");
|
fragment.show(getChildFragmentManager(), "post_view");
|
||||||
}).execute();
|
}
|
||||||
break;
|
|
||||||
case 2:
|
@Override
|
||||||
friendshipService.ignore(userId, model.getUserId(), csrfToken, new ServiceCallback<FriendshipRepoChangeRootResponse>() {
|
public void onFailure(final Throwable t) {
|
||||||
@Override
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
public void onSuccess(final FriendshipRepoChangeRootResponse result) {
|
}
|
||||||
// Log.d(TAG, "onSuccess: " + result);
|
});
|
||||||
if (result.getStatus().equals("ok")) {
|
}
|
||||||
onRefresh();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotificationClick(final NotificationModel model) {
|
||||||
|
if (model == null) return;
|
||||||
|
final String username = model.getUsername();
|
||||||
|
if (model.getType() == NotificationType.FOLLOW) {
|
||||||
|
openProfile(username);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final SpannableString title = new SpannableString(username + (TextUtils.isEmpty(model.getText()) ? "" : (":\n" + model.getText())));
|
||||||
|
title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||||
|
|
||||||
|
String[] commentDialogList;
|
||||||
|
if (model.getType() == NotificationType.RESPONDED_STORY) {
|
||||||
|
commentDialogList = new String[]{
|
||||||
|
getString(R.string.open_profile),
|
||||||
|
getString(R.string.view_story)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (model.getPostId() != null) {
|
||||||
|
commentDialogList = new String[]{
|
||||||
|
getString(R.string.open_profile),
|
||||||
|
getString(R.string.view_post)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (model.getType() == NotificationType.REQUEST) {
|
||||||
|
commentDialogList = new String[]{
|
||||||
|
getString(R.string.open_profile),
|
||||||
|
getString(R.string.request_approve),
|
||||||
|
getString(R.string.request_reject)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else commentDialogList = null; // shouldn't happen
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
|
||||||
|
switch (which) {
|
||||||
|
case 0:
|
||||||
|
openProfile(username);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (model.getType() == NotificationType.REQUEST) {
|
||||||
|
friendshipService.approve(userId, model.getUserId(), csrfToken, new ServiceCallback<FriendshipRepoChangeRootResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final FriendshipRepoChangeRootResponse result) {
|
||||||
|
// Log.d(TAG, "onSuccess: " + result);
|
||||||
|
if (result.getStatus().equals("ok")) {
|
||||||
|
onRefresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.e(TAG, "approve: status was not ok!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(final Throwable t) {
|
||||||
|
Log.e(TAG, "approve: onFailure: ", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.e(TAG, "ignore: status was not ok!");
|
else if (model.getType() == NotificationType.RESPONDED_STORY) {
|
||||||
}
|
showProfilePicDialog(model);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final AlertDialog alertDialog = new AlertDialog.Builder(context)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setView(R.layout.dialog_opening_post)
|
||||||
|
.create();
|
||||||
|
alertDialog.show();
|
||||||
|
mediaService.fetch(model.getPostId(), new ServiceCallback<FeedModel>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final FeedModel feedModel) {
|
||||||
|
final PostViewV2Fragment fragment = PostViewV2Fragment
|
||||||
|
.builder(feedModel)
|
||||||
|
.build();
|
||||||
|
fragment.setOnShowListener(dialog1 -> alertDialog.dismiss());
|
||||||
|
fragment.show(getChildFragmentManager(), "post_view");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(final Throwable t) {
|
public void onFailure(final Throwable t) {
|
||||||
Log.e(TAG, "ignore: onFailure: ", t);
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
friendshipService.ignore(userId, model.getUserId(), csrfToken, new ServiceCallback<FriendshipRepoChangeRootResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final FriendshipRepoChangeRootResponse result) {
|
||||||
|
// Log.d(TAG, "onSuccess: " + result);
|
||||||
|
if (result.getStatus().equals("ok")) {
|
||||||
|
onRefresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.e(TAG, "ignore: status was not ok!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(final Throwable t) {
|
||||||
|
Log.e(TAG, "ignore: onFailure: ", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new AlertDialog.Builder(context)
|
||||||
|
.setTitle(title)
|
||||||
|
.setItems(commentDialogList, profileDialogListener)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
new AlertDialog.Builder(context)
|
|
||||||
.setTitle(title)
|
|
||||||
.setItems(commentDialogList, profileDialogListener)
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
};
|
};
|
||||||
private final MentionClickListener mentionClickListener = (view, text, isHashtag, isLocation) -> {
|
private final MentionClickListener mentionClickListener = (view, text, isHashtag, isLocation) -> {
|
||||||
if (getContext() == null) return;
|
if (getContext() == null) return;
|
||||||
@ -158,7 +222,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final Context context = getContext();
|
context = getContext();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
NotificationManagerCompat.from(context.getApplicationContext()).cancel(Constants.ACTIVITY_NOTIFICATION_ID);
|
NotificationManagerCompat.from(context.getApplicationContext()).cancel(Constants.ACTIVITY_NOTIFICATION_ID);
|
||||||
final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
||||||
@ -167,6 +231,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
}
|
}
|
||||||
friendshipService = FriendshipService.getInstance();
|
friendshipService = FriendshipService.getInstance();
|
||||||
newsService = NewsService.getInstance();
|
newsService = NewsService.getInstance();
|
||||||
|
mediaService = MediaService.getInstance();
|
||||||
userId = CookieUtils.getUserIdFromCookie(cookie);
|
userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||||
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||||
}
|
}
|
||||||
@ -205,22 +270,9 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
@Override
|
@Override
|
||||||
public void onRefresh() {
|
public void onRefresh() {
|
||||||
binding.swipeRefreshLayout.setRefreshing(true);
|
binding.swipeRefreshLayout.setRefreshing(true);
|
||||||
new NotificationsFetcher(notificationModels -> {
|
new NotificationsFetcher(true, notificationModels -> {
|
||||||
binding.swipeRefreshLayout.setRefreshing(false);
|
binding.swipeRefreshLayout.setRefreshing(false);
|
||||||
notificationViewModel.getList().postValue(notificationModels);
|
notificationViewModel.getList().postValue(notificationModels);
|
||||||
final String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
|
||||||
newsService.markChecked(timestamp, csrfToken, new ServiceCallback<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@NonNull final Boolean result) {
|
|
||||||
// Log.d(TAG, "onResponse: body: " + result);
|
|
||||||
if (!result) Log.e(TAG, "onSuccess: Error marking activity checked, response is false");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(final Throwable t) {
|
|
||||||
Log.e(TAG, "onFailure: Error marking activity checked", t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,4 +281,15 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
|||||||
.actionGlobalProfileFragment("@" + username);
|
.actionGlobalProfileFragment("@" + username);
|
||||||
NavHostFragment.findNavController(this).navigate(action);
|
NavHostFragment.findNavController(this).navigate(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showProfilePicDialog(final NotificationModel model) {
|
||||||
|
final FragmentManager fragmentManager = getParentFragmentManager();
|
||||||
|
final ProfilePicDialogFragment fragment = new ProfilePicDialogFragment(model.getPostId(),
|
||||||
|
model.getUsername(),
|
||||||
|
model.getPreviewPic());
|
||||||
|
final FragmentTransaction ft = fragmentManager.beginTransaction();
|
||||||
|
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
||||||
|
.add(fragment, "profilePicDialog")
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ public final class NotificationModel {
|
|||||||
private final String userId;
|
private final String userId;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String profilePicUrl;
|
private final String profilePicUrl;
|
||||||
private final String shortCode;
|
private final String postId;
|
||||||
private final String previewUrl;
|
private final String previewUrl;
|
||||||
private final NotificationType type;
|
private final NotificationType type;
|
||||||
private final CharSequence text;
|
private final CharSequence text;
|
||||||
@ -25,7 +25,7 @@ public final class NotificationModel {
|
|||||||
final String userId,
|
final String userId,
|
||||||
final String username,
|
final String username,
|
||||||
final String profilePicUrl,
|
final String profilePicUrl,
|
||||||
final String shortCode,
|
final String postId,
|
||||||
final String previewUrl,
|
final String previewUrl,
|
||||||
final NotificationType type) {
|
final NotificationType type) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -34,7 +34,7 @@ public final class NotificationModel {
|
|||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.profilePicUrl = profilePicUrl;
|
this.profilePicUrl = profilePicUrl;
|
||||||
this.shortCode = shortCode;
|
this.postId = postId;
|
||||||
this.previewUrl = previewUrl;
|
this.previewUrl = previewUrl;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
@ -47,6 +47,10 @@ public final class NotificationModel {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getDateTime() {
|
public String getDateTime() {
|
||||||
return Utils.datetimeParser.format(new Date(timestamp * 1000L));
|
return Utils.datetimeParser.format(new Date(timestamp * 1000L));
|
||||||
@ -64,8 +68,8 @@ public final class NotificationModel {
|
|||||||
return profilePicUrl;
|
return profilePicUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getShortCode() {
|
public String getPostId() {
|
||||||
return shortCode;
|
return postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPreviewPic() {
|
public String getPreviewPic() {
|
||||||
|
@ -5,11 +5,17 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public enum NotificationType implements Serializable {
|
public enum NotificationType implements Serializable {
|
||||||
|
// web
|
||||||
LIKE("GraphLikeAggregatedStory"),
|
LIKE("GraphLikeAggregatedStory"),
|
||||||
FOLLOW("GraphFollowAggregatedStory"),
|
FOLLOW("GraphFollowAggregatedStory"),
|
||||||
COMMENT("GraphCommentMediaStory"),
|
COMMENT("GraphCommentMediaStory"),
|
||||||
MENTION("GraphMentionStory"),
|
MENTION("GraphMentionStory"),
|
||||||
TAGGED("GraphUserTaggedStory"),
|
TAGGED("GraphUserTaggedStory"),
|
||||||
|
// app story_type
|
||||||
|
COMMENT_LIKE("13"),
|
||||||
|
TAGGED_COMMENT("14"),
|
||||||
|
RESPONDED_STORY("213"),
|
||||||
|
// efr
|
||||||
REQUEST("REQUEST");
|
REQUEST("REQUEST");
|
||||||
|
|
||||||
private final String itemType;
|
private final String itemType;
|
||||||
|
@ -12,6 +12,9 @@ import retrofit2.http.Path;
|
|||||||
import retrofit2.http.QueryMap;
|
import retrofit2.http.QueryMap;
|
||||||
|
|
||||||
public interface MediaRepository {
|
public interface MediaRepository {
|
||||||
|
@GET("/api/v1/media/{mediaId}/info/")
|
||||||
|
Call<String> fetch(@Path("mediaId") final String mediaId);
|
||||||
|
|
||||||
@GET("/api/v1/media/{mediaId}/likers/")
|
@GET("/api/v1/media/{mediaId}/likers/")
|
||||||
Call<String> fetchLikes(@Path("mediaId") final String mediaId);
|
Call<String> fetchLikes(@Path("mediaId") final String mediaId);
|
||||||
|
|
||||||
|
@ -6,16 +6,19 @@ import awais.instagrabber.utils.Constants;
|
|||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.FieldMap;
|
import retrofit2.http.FieldMap;
|
||||||
import retrofit2.http.FormUrlEncoded;
|
import retrofit2.http.FormUrlEncoded;
|
||||||
|
import retrofit2.http.GET;
|
||||||
import retrofit2.http.Header;
|
import retrofit2.http.Header;
|
||||||
import retrofit2.http.Headers;
|
import retrofit2.http.Headers;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
public interface NewsRepository {
|
public interface NewsRepository {
|
||||||
|
|
||||||
Call<String> inbox();
|
|
||||||
|
|
||||||
@FormUrlEncoded
|
|
||||||
@Headers("User-Agent: " + Constants.USER_AGENT)
|
@Headers("User-Agent: " + Constants.USER_AGENT)
|
||||||
@POST("https://www.instagram.com/web/activity/mark_checked/")
|
@GET("https://www.instagram.com/accounts/activity/?__a=1")
|
||||||
Call<String> markChecked(@Header("x-csrftoken") String csrfToken, @FieldMap Map<String, String> map);
|
Call<String> webInbox();
|
||||||
|
|
||||||
|
@Headers("User-Agent: " + Constants.I_USER_AGENT)
|
||||||
|
@GET("/api/v1/news/inbox/")
|
||||||
|
Call<String> appInbox(@Query(value = "mark_as_seen", encoded = true) boolean markAsSeen);
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import awais.instagrabber.models.FeedModel;
|
||||||
import awais.instagrabber.models.ProfileModel;
|
import awais.instagrabber.models.ProfileModel;
|
||||||
import awais.instagrabber.repositories.MediaRepository;
|
import awais.instagrabber.repositories.MediaRepository;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
@ -46,6 +48,37 @@ public class MediaService extends BaseService {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fetch(final String mediaId,
|
||||||
|
final ServiceCallback<FeedModel> callback) {
|
||||||
|
final Call<String> request = repository.fetch(mediaId);
|
||||||
|
request.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<String> call,
|
||||||
|
@NonNull final Response<String> response) {
|
||||||
|
if (callback == null) return;
|
||||||
|
final String body = response.body();
|
||||||
|
if (body == null) {
|
||||||
|
callback.onSuccess(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final JSONObject itemJson = new JSONObject(body).getJSONArray("items").getJSONObject(0);
|
||||||
|
callback.onSuccess(ResponseBodyUtils.parseItem(itemJson));
|
||||||
|
} catch (JSONException e) {
|
||||||
|
callback.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<String> call,
|
||||||
|
@NonNull final Throwable t) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void like(final String mediaId,
|
public void like(final String mediaId,
|
||||||
final String userId,
|
final String userId,
|
||||||
final String csrfToken,
|
final String csrfToken,
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
package awais.instagrabber.webservices;
|
package awais.instagrabber.webservices;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import awais.instagrabber.models.NotificationModel;
|
||||||
|
import awais.instagrabber.models.enums.NotificationType;
|
||||||
import awais.instagrabber.repositories.NewsRepository;
|
import awais.instagrabber.repositories.NewsRepository;
|
||||||
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.NetworkUtils;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
@ -35,25 +46,34 @@ public class NewsService extends BaseService {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markChecked(final String timestamp,
|
public void fetchAppInbox(final boolean markAsSeen,
|
||||||
final String csrfToken,
|
final ServiceCallback<List<NotificationModel>> callback) {
|
||||||
final ServiceCallback<Boolean> callback) {
|
final List<NotificationModel> result = new ArrayList<>();
|
||||||
final Map<String, String> map = new HashMap<>();
|
final Call<String> request = repository.appInbox(markAsSeen);
|
||||||
map.put("timestamp", timestamp);
|
|
||||||
final Call<String> request = repository.markChecked(csrfToken, map);
|
|
||||||
request.enqueue(new Callback<String>() {
|
request.enqueue(new Callback<String>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||||
final String body = response.body();
|
final String body = response.body();
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
callback.onSuccess(false);
|
callback.onSuccess(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final JSONObject jsonObject = new JSONObject(body);
|
final JSONObject jsonObject = new JSONObject(body);
|
||||||
final String status = jsonObject.optString("status");
|
final JSONArray oldStories = jsonObject.getJSONArray("old_stories"),
|
||||||
callback.onSuccess(status.equals("ok"));
|
newStories = jsonObject.getJSONArray("new_stories");
|
||||||
|
|
||||||
|
for (int j = 0; j < newStories.length(); ++j) {
|
||||||
|
final NotificationModel newsItem = parseNewsItem(newStories.getJSONObject(j));
|
||||||
|
if (newsItem != null) result.add(newsItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < oldStories.length(); ++i) {
|
||||||
|
final NotificationModel newsItem = parseNewsItem(oldStories.getJSONObject(i));
|
||||||
|
if (newsItem != null) result.add(newsItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.onSuccess(result);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
callback.onFailure(e);
|
callback.onFailure(e);
|
||||||
}
|
}
|
||||||
@ -66,4 +86,112 @@ public class NewsService extends BaseService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fetchWebInbox(final boolean markAsSeen,
|
||||||
|
final ServiceCallback<List<NotificationModel>> callback) {
|
||||||
|
final List<NotificationModel> result = new ArrayList<>();
|
||||||
|
final Call<String> request = repository.webInbox();
|
||||||
|
request.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||||
|
final String body = response.body();
|
||||||
|
if (body == null) {
|
||||||
|
callback.onSuccess(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final JSONObject page = new JSONObject(body)
|
||||||
|
.getJSONObject("graphql")
|
||||||
|
.getJSONObject("user");
|
||||||
|
final JSONObject ewaf = page.getJSONObject("activity_feed")
|
||||||
|
.optJSONObject("edge_web_activity_feed");
|
||||||
|
final JSONObject efr = page.optJSONObject("edge_follow_requests");
|
||||||
|
JSONObject data;
|
||||||
|
JSONArray media;
|
||||||
|
if (ewaf != null
|
||||||
|
&& (media = ewaf.optJSONArray("edges")) != null
|
||||||
|
&& media.length() > 0
|
||||||
|
&& media.optJSONObject(0).optJSONObject("node") != null) {
|
||||||
|
for (int i = 0; i < media.length(); ++i) {
|
||||||
|
data = media.optJSONObject(i).optJSONObject("node");
|
||||||
|
if (data == null) continue;
|
||||||
|
final String type = data.getString("__typename");
|
||||||
|
final NotificationType notificationType = NotificationType.valueOfType(type);
|
||||||
|
if (notificationType == null) continue;
|
||||||
|
final JSONObject user = data.getJSONObject("user");
|
||||||
|
result.add(new NotificationModel(
|
||||||
|
data.getString(Constants.EXTRAS_ID),
|
||||||
|
data.optString("text"), // comments or mentions
|
||||||
|
data.getLong("timestamp"),
|
||||||
|
user.getString("id"),
|
||||||
|
user.getString("username"),
|
||||||
|
user.getString("profile_pic_url"),
|
||||||
|
!data.isNull("media") ? data.getJSONObject("media").getString("id") : null,
|
||||||
|
!data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, notificationType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (efr != null
|
||||||
|
&& (media = efr.optJSONArray("edges")) != null
|
||||||
|
&& media.length() > 0
|
||||||
|
&& media.optJSONObject(0).optJSONObject("node") != null) {
|
||||||
|
for (int i = 0; i < media.length(); ++i) {
|
||||||
|
data = media.optJSONObject(i).optJSONObject("node");
|
||||||
|
if (data == null) continue;
|
||||||
|
result.add(new NotificationModel(
|
||||||
|
data.getString(Constants.EXTRAS_ID),
|
||||||
|
data.optString("full_name"),
|
||||||
|
0L,
|
||||||
|
data.getString(Constants.EXTRAS_ID),
|
||||||
|
data.getString("username"),
|
||||||
|
data.getString("profile_pic_url"),
|
||||||
|
null,
|
||||||
|
null, NotificationType.REQUEST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback.onSuccess(result);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
callback.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||||
|
callback.onFailure(t);
|
||||||
|
// Log.e(TAG, "onFailure: ", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private NotificationModel parseNewsItem(final JSONObject itemJson) throws JSONException {
|
||||||
|
if (itemJson == null) return null;
|
||||||
|
final String type = itemJson.getString("story_type");
|
||||||
|
final NotificationType notificationType = NotificationType.valueOfType(type);
|
||||||
|
if (notificationType == null) {
|
||||||
|
Log.d("austin_debug", "unhandled news type: "+itemJson);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final JSONObject data = itemJson.getJSONObject("args");
|
||||||
|
return new NotificationModel(
|
||||||
|
data.getString("tuuid"),
|
||||||
|
data.has("text") ? data.getString("text") : cleanRichText(data.optString("rich_text", "")),
|
||||||
|
data.getLong("timestamp"),
|
||||||
|
data.getString("profile_id"),
|
||||||
|
data.getString("profile_name"),
|
||||||
|
data.getString("profile_image"),
|
||||||
|
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("id") : null,
|
||||||
|
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("image") : null,
|
||||||
|
notificationType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cleanRichText(final String raw) {
|
||||||
|
final Matcher matcher = Pattern.compile("\\{[\\p{L}\\d._]+\\|000000\\|1\\|user\\?id=\\d+\\}").matcher(raw);
|
||||||
|
String result = raw;
|
||||||
|
while (matcher.find()) {
|
||||||
|
final String richObject = raw.substring(matcher.start(), matcher.end());
|
||||||
|
final String username = richObject.split("\\|")[0].substring(1);
|
||||||
|
result = result.replace(richObject, username);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,13 +105,13 @@
|
|||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
android:paddingLeft="8dp"
|
android:paddingLeft="8dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="4dp"
|
||||||
android:paddingRight="16dp"
|
android:paddingRight="16dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||||
android:textStyle="italic"
|
android:textStyle="italic"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/ivPreviewPic"
|
||||||
app:layout_constraintStart_toEndOf="@id/ivProfilePic"
|
app:layout_constraintStart_toEndOf="@id/ivProfilePic"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvSubComment"
|
app:layout_constraintTop_toBottomOf="@id/tvSubComment"
|
||||||
tools:text="some long long long long long date" />
|
tools:text="some long long long long long date" />
|
||||||
|
@ -145,6 +145,7 @@
|
|||||||
<string name="quick_access_cannot_delete_curr">Cannot delete currently in use account</string>
|
<string name="quick_access_cannot_delete_curr">Cannot delete currently in use account</string>
|
||||||
<string name="quick_access_confirm_delete">Are you sure you want to delete \'%s\'?</string>
|
<string name="quick_access_confirm_delete">Are you sure you want to delete \'%s\'?</string>
|
||||||
<string name="open_profile">Open profile</string>
|
<string name="open_profile">Open profile</string>
|
||||||
|
<string name="view_story">View story</string>
|
||||||
<string name="view_pfp">View profile picture</string>
|
<string name="view_pfp">View profile picture</string>
|
||||||
<string name="direct_messages_you">You</string>
|
<string name="direct_messages_you">You</string>
|
||||||
<string name="direct_messages_sent_link">Shared a link</string>
|
<string name="direct_messages_sent_link">Shared a link</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user