diff --git a/app/src/main/java/awais/instagrabber/MainHelper.java b/app/src/main/java/awais/instagrabber/MainHelper.java index 20de5793..82eccc85 100755 --- a/app/src/main/java/awais/instagrabber/MainHelper.java +++ b/app/src/main/java/awais/instagrabber/MainHelper.java @@ -20,6 +20,8 @@ import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -61,6 +63,7 @@ import awais.instagrabber.asyncs.LocationFetcher; import awais.instagrabber.asyncs.PostsFetcher; import awais.instagrabber.asyncs.ProfileFetcher; import awais.instagrabber.asyncs.i.iStoryStatusFetcher; +import awais.instagrabber.asyncs.i.iTopicFetcher; import awais.instagrabber.customviews.MouseDrawer; import awais.instagrabber.customviews.RamboTextView; import awais.instagrabber.customviews.helpers.GridAutofitLayoutManager; @@ -71,6 +74,7 @@ import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.interfaces.MentionClickListener; import awais.instagrabber.models.BasePostModel; import awais.instagrabber.models.DiscoverItemModel; +import awais.instagrabber.models.DiscoverTopicModel; import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.HashtagModel; @@ -94,7 +98,8 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { private final boolean autoloadPosts; private FeedStoryModel[] stories; private boolean hasNextPage = false, feedHasNextPage = false, discoverHasMore = false; - private String endCursor = null, feedEndCursor = null, discoverEndMaxId = null; + private String endCursor = null, feedEndCursor = null, discoverEndMaxId = null, topic = null; + private String[] topicIds = null; private final FetchListener postsFetchListener = new FetchListener() { @Override public void onResult(final PostModel[] result) { @@ -194,7 +199,10 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { @Override public void onResult(final DiscoverItemModel[] result) { - if (result != null) { + if (result.length == 0) { + Toast.makeText(main, R.string.discover_empty, Toast.LENGTH_SHORT).show(); + } + else if (result != null) { final int oldSize = main.discoverItems.size(); main.discoverItems.addAll(Arrays.asList(result)); discoverAdapter.notifyItemRangeInserted(oldSize, result.length); @@ -210,6 +218,20 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { main.mainBinding.discoverSwipeRefreshLayout.setRefreshing(false); } }; + private final FetchListener topicFetchListener = new FetchListener() { + @Override + public void doBefore() {} + + @Override + public void onResult(final DiscoverTopicModel result) { + if (result != null) { + topicIds = result.getIds(); + ArrayAdapter spinnerArrayAdapter = new ArrayAdapter( + main, android.R.layout.simple_spinner_dropdown_item, result.getNames() ); + main.mainBinding.discoverType.setAdapter(spinnerArrayAdapter); + } + } + }; private final FetchListener feedStoriesListener = new FetchListener() { @Override public void doBefore() { @@ -533,11 +555,30 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { main.mainBinding.discoverPosts.setLayoutManager(layoutManager); main.mainBinding.discoverPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4))); + new iTopicFetcher(topicFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + main.mainBinding.discoverType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int pos, long id) { + if (topicIds != null) { + topic = topicIds[pos]; + main.mainBinding.discoverSwipeRefreshLayout.setRefreshing(true); + if (discoverLazyLoader != null) discoverLazyLoader.resetState(); + main.discoverItems.clear(); + if (discoverAdapter != null) discoverAdapter.notifyDataSetChanged(); + new DiscoverFetcher(topic, null, discoverFetchListener, false).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + main.mainBinding.discoverSwipeRefreshLayout.setOnRefreshListener(() -> { if (discoverLazyLoader != null) discoverLazyLoader.resetState(); main.discoverItems.clear(); if (discoverAdapter != null) discoverAdapter.notifyDataSetChanged(); - new DiscoverFetcher(null, discoverFetchListener, false).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new DiscoverFetcher(topic, null, discoverFetchListener, false).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }); main.mainBinding.discoverPosts.setAdapter(discoverAdapter = new DiscoverAdapter(main.discoverItems, v -> { @@ -563,12 +604,12 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { main.mainBinding.discoverPosts.addOnScrollListener(discoverLazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { if (discoverHasMore) { main.mainBinding.discoverSwipeRefreshLayout.setRefreshing(true); - new DiscoverFetcher(discoverEndMaxId, discoverFetchListener, false).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new DiscoverFetcher(topic, discoverEndMaxId, discoverFetchListener, false).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); discoverEndMaxId = null; } })); - new DiscoverFetcher(null, discoverFetchListener, true).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new DiscoverFetcher(topic, null, discoverFetchListener, true).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } public void onIntent(final Intent intent) { diff --git a/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java b/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java index 0f85399e..487fd6f6 100755 --- a/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java +++ b/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java @@ -43,7 +43,7 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { private DirectItemModel directItemModel; private final ProfileModel myProfileHolder = new ProfileModel(false, false, false, null, null, null, null, null, null, null, 0, 0, 0, false, false, false, false); - private final ArrayList users = new ArrayList<>(); + private final ArrayList users = new ArrayList<>(), leftusers = new ArrayList<>(); private final ArrayList directItemModels = new ArrayList<>(); private final FetchListener fetchListener = new FetchListener() { @Override @@ -63,6 +63,9 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { users.clear(); users.addAll(Arrays.asList(result.getUsers())); + leftusers.clear(); + leftusers.addAll(Arrays.asList(result.getLeftUsers())); + final int oldSize = directItemModels.size(); final List itemModels = Arrays.asList(result.getItems()); directItemModels.addAll(itemModels); @@ -102,7 +105,7 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { } })); - messageItemsAdapter = new MessageItemsAdapter(directItemModels, users, v -> { + messageItemsAdapter = new MessageItemsAdapter(directItemModels, users, leftusers, v -> { Object tag = v.getTag(); if (tag instanceof DirectItemModel) { directItemModel = (DirectItemModel) tag; @@ -129,21 +132,28 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { Toast.makeText(v.getContext(), R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show(); break; case STORY_SHARE: - StoryModel sm = new StoryModel( - directItemModel.getReelShare().getReelId(), - directItemModel.getReelShare().getMedia().getVideoUrl(), - directItemModel.getReelShare().getMedia().getMediaType(), - directItemModel.getTimestamp(), - directItemModel.getReelShare().getReelOwnerName() - - ); - sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl()); - StoryModel[] sms = {sm}; - if (directItemModel.getReelShare() != null) + if (directItemModel.getReelShare() != null) { + StoryModel sm = new StoryModel( + directItemModel.getReelShare().getReelId(), + directItemModel.getReelShare().getMedia().getVideoUrl(), + directItemModel.getReelShare().getMedia().getMediaType(), + directItemModel.getTimestamp(), + directItemModel.getReelShare().getReelOwnerName() + ); + sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl()); + StoryModel[] sms = {sm}; startActivity(new Intent(this, StoryViewer.class) .putExtra(Constants.EXTRAS_USERNAME, directItemModel.getReelShare().getReelOwnerName()) .putExtra(Constants.EXTRAS_STORIES, sms) ); + } + else if (directItemModel.getText() != null) { + searchUsername(directItemModel.getText().toString().split("@")[1].split(" ")[0]); + } + break; + case PLACEHOLDER: + if (directItemModel.getText().toString().contains("@")) + searchUsername(directItemModel.getText().toString().split("@")[1].split(" ")[0]); break; default: Log.d("austin_debug", "unsupported type "+itemType); @@ -163,10 +173,18 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { @Nullable private ProfileModel getUser(final long userId) { - for (final ProfileModel user : users) { - if (Long.toString(userId).equals(user.getId())) return user; + if (users != null) { + ProfileModel result = myProfileHolder; + for (final ProfileModel user : users) { + if (Long.toString(userId).equals(user.getId())) result = user; + } + if (leftusers != null) + for (final ProfileModel leftuser : leftusers) { + if (Long.toString(userId).equals(leftuser.getId())) result = leftuser; + } + return result; } - return myProfileHolder; + return null; } private void searchUsername(final String text) { diff --git a/app/src/main/java/awais/instagrabber/adapters/DirectMessagesAdapter.java b/app/src/main/java/awais/instagrabber/adapters/DirectMessagesAdapter.java index 9a1a1536..9f5b45f5 100755 --- a/app/src/main/java/awais/instagrabber/adapters/DirectMessagesAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/DirectMessagesAdapter.java @@ -77,36 +77,45 @@ public final class DirectMessagesAdapter extends RecyclerView.Adapter { private static final int MESSAGE_INCOMING = 69, MESSAGE_OUTGOING = 420; private final ProfileModel myProfileHolder = - new ProfileModel(false, false, false, null, null, null, null, null, null, null, 0, 0, 0, false, false, false, false); + new ProfileModel(false, false, false, + Utils.getUserIdFromCookie(Utils.settingsHelper.getString(Constants.COOKIE)), + null, null, null, null, null, null, 0, 0, 0, false, false, false, false); private final ArrayList directItemModels; - private final ArrayList users; + private final ArrayList users, leftusers; private final View.OnClickListener onClickListener; private final MentionClickListener mentionClickListener; private final View.OnClickListener openProfileClickListener = v -> { @@ -93,8 +95,10 @@ public final class MessageItemsAdapter extends RecyclerView.Adapter directItemModels, final ArrayList users, - final View.OnClickListener onClickListener, final MentionClickListener mentionClickListener) { + final ArrayList leftusers, final View.OnClickListener onClickListener, + final MentionClickListener mentionClickListener) { this.users = users; + this.leftusers = leftusers; this.directItemModels = directItemModels; this.onClickListener = onClickListener; this.mentionClickListener = mentionClickListener; @@ -392,10 +396,15 @@ public final class MessageItemsAdapter extends RecyclerView.Adapter { - private final String maxId; + private final String cluster, maxId; private final FetchListener fetchListener; private int lastId = 0; private boolean isFirst, moreAvailable; private String nextMaxId; - public DiscoverFetcher(final String maxId, final FetchListener fetchListener, final boolean isFirst) { + public DiscoverFetcher(final String cluster, final String maxId, + final FetchListener fetchListener, final boolean isFirst) { + this.cluster = cluster == null ? "explore_all%3A0" : cluster.replace(":", "%3A"); this.maxId = maxId == null ? "" : "&max_id=" + maxId; this.fetchListener = fetchListener; this.isFirst = isFirst; @@ -54,7 +56,7 @@ public final class DiscoverFetcher extends AsyncTask 0) { final DiscoverItemModel lastModel = result[result.length - 1]; - if (lastModel != null) lastModel.setMore(moreAvailable, nextMaxId); + if (lastModel != null && nextMaxId != null) lastModel.setMore(moreAvailable, nextMaxId); } } @@ -64,7 +66,7 @@ public final class DiscoverFetcher extends AsyncTask fetchItems(ArrayList discoverItemModels, final String maxId) { try { final String url = "https://www.instagram.com/explore/grid/?is_prefetch=false&omit_cover_media=true&module=explore_popular" + - "&use_sectional_payload=false&cluster_id=explore_all%3A0&include_fixed_destinations=true" + maxId; + "&use_sectional_payload=false&cluster_id="+cluster+"&include_fixed_destinations=true" + maxId; final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); @@ -75,7 +77,7 @@ public final class DiscoverFetcher extends AsyncTask(sectionalItems.length() * 2); diff --git a/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java index 0d185bcf..f0255178 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/direct_messages/InboxFetcher.java @@ -39,7 +39,7 @@ public final class InboxFetcher extends AsyncTask { final String url = "https://i.instagram.com/api/v1/direct_v2/inbox/" + endCursor; try { final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); - conn.setRequestProperty("User-Agent", Constants.USER_AGENT); + conn.setRequestProperty("User-Agent", Constants.I_USER_AGENT); conn.setRequestProperty("Accept-Language", LocaleUtils.getCurrentLocale().getLanguage() + ",en-US;q=0.8"); conn.setUseCaches(false); diff --git a/app/src/main/java/awais/instagrabber/asyncs/direct_messages/UserInboxFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/direct_messages/UserInboxFetcher.java index 8134aab2..d38a9301 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/direct_messages/UserInboxFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/direct_messages/UserInboxFetcher.java @@ -15,6 +15,7 @@ import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.direct_messages.InboxThreadModel; import awais.instagrabber.models.enums.UserInboxDirection; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.Utils; import static awais.instagrabber.utils.Utils.logCollector; @@ -45,7 +46,8 @@ public final class UserInboxFetcher extends AsyncTask { + private final FetchListener fetchListener; + + public iTopicFetcher(final FetchListener fetchListener) { + this.fetchListener = fetchListener; + } + + @Override + protected DiscoverTopicModel doInBackground(final Void... voids) { + final String url = "https://i.instagram.com/api/v1/discover/topical_explore/"; + + DiscoverTopicModel result = null; + try { + final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setUseCaches(false); + conn.setRequestProperty("User-Agent", Constants.I_USER_AGENT); + conn.setRequestProperty("Accept-Language", LocaleUtils.getCurrentLocale().getLanguage() + ",en-US;q=0.8"); + conn.connect(); + + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + final JSONObject body = new JSONObject(Utils.readFromConnection(conn)); + + final JSONArray edges = body.getJSONArray("clusters"); + String[] names = new String[edges.length()], ids = new String[edges.length()]; + for (int i = 0; i < names.length; ++i) { + final JSONObject mediaNode = edges.getJSONObject(i); + ids[i] = mediaNode.getString("id"); + names[i] = mediaNode.getString("title"); + } + + result = new DiscoverTopicModel(ids, names); + } + + conn.disconnect(); + } catch (Exception e) { + if (logCollector != null) + logCollector.appendException(e, LogCollector.LogFile.ASYNC_DISCOVER_TOPICS_FETCHER, "doInBackground"); + if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); + } + + return result; + } + + @Override + protected void onPostExecute(final DiscoverTopicModel discoverTopicModel) { + if (fetchListener != null) fetchListener.onResult(discoverTopicModel); + } +} diff --git a/app/src/main/java/awais/instagrabber/models/DiscoverTopicModel.java b/app/src/main/java/awais/instagrabber/models/DiscoverTopicModel.java new file mode 100755 index 00000000..fa35ec4d --- /dev/null +++ b/app/src/main/java/awais/instagrabber/models/DiscoverTopicModel.java @@ -0,0 +1,20 @@ +package awais.instagrabber.models; + +import java.io.Serializable; + +public final class DiscoverTopicModel implements Serializable { + private final String[] id, name; + + public DiscoverTopicModel(final String[] id, final String[] name) { + this.id = id; + this.name = name; + } + + public String[] getIds() { + return id; + } + + public String[] getNames() { + return name; + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index f16ab40d..c14289e1 100755 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -487,6 +487,8 @@ public final class Utils { final JSONArray users = data.getJSONArray("users"); final int usersLen = users.length(); + final JSONArray leftusers = data.getJSONArray("left_users"); + final int leftusersLen = leftusers.length(); final ProfileModel[] userModels = new ProfileModel[usersLen]; for (int j = 0; j < usersLen; ++j) { @@ -502,6 +504,20 @@ public final class Utils { null, 0, 0, 0, false, false, false, false); } + final ProfileModel[] leftuserModels = new ProfileModel[leftusersLen]; + for (int j = 0; j < leftusersLen; ++j) { + final JSONObject userObject = leftusers.getJSONObject(j); + leftuserModels[j] = new ProfileModel(userObject.getBoolean("is_private"), + false, + userObject.optBoolean("is_verified"), + String.valueOf(userObject.get("pk")), + userObject.getString("username"), + userObject.getString("full_name"), + null, null, + userObject.getString("profile_pic_url"), + null, 0, 0, 0, false, false, false, false); + } + final JSONArray items = data.getJSONArray("items"); final int itemsLen = items.length(); @@ -737,8 +753,7 @@ public final class Utils { return new InboxThreadModel(readState, threadId, threadV2Id, threadType, threadTitle, threadNewestCursor, threadOldestCursor, threadNextCursor, threadPrevCursor, null, // todo - userModels, - null, // todo + userModels, leftuserModels, itemModels.toArray(new DirectItemModel[0]), muted, isPin, named, canonical, pending, threadHasOlder, threadHasNewer, isSpam, isGroup, archived, lastActivityAt); diff --git a/app/src/main/java/awaisomereport/LogCollector.java b/app/src/main/java/awaisomereport/LogCollector.java index 6ba7c7f2..b36db537 100755 --- a/app/src/main/java/awaisomereport/LogCollector.java +++ b/app/src/main/java/awaisomereport/LogCollector.java @@ -104,6 +104,7 @@ public final class LogCollector { //////////////////////// ASYNC_DOWNLOADER("async-download.txt"), ASYNC_MAIN_POSTS_FETCHER("async-main-posts-fetcher.txt"), + ASYNC_DISCOVER_TOPICS_FETCHER("async-discover-topics-fetcher.txt"), ASYNC_POST_FETCHER("async-single-post-fetcher.txt"), ASYNC_FEED_FETCHER("async-feed-fetcher.txt"), ASYNC_HASHTAG_FETCHER("async-hashtag-fetcher.txt"), diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a10b43c6..26350f2f 100755 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -525,21 +525,39 @@ - - - + android:layout_height="wrap_content" + android:entries="@array/discover_placeholder" + android:paddingTop="4dp" + android:paddingBottom="4dp" /> + + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index c4154ef2..ef179601 100755 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -26,6 +26,9 @@ \| - + + Loading... + dd-MM-yyyy dd/MM/yyyy diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ceaf822..95a7de0a 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -201,6 +201,8 @@ Share this public post to... This is a private post! Share to those who can view them! + This category is somehow empty... + An update is available! (%s) Reminder: If you downloaded from F-Droid, you must update from it! Same applies for GitHub. Thank you for updating InstaGrabber!