From 14d3ea5c6c5108788301a98c8a50895488e0f56e Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 6 Aug 2020 12:48:52 -0400 Subject: [PATCH] v17.4 --- app/build.gradle | 4 +- .../java/awais/instagrabber/MainHelper.java | 29 +--- .../activities/CommentsViewer.java | 4 +- .../activities/DirectMessages.java | 5 + .../activities/DirectMessagesUserInbox.java | 89 +++++++++- .../activities/NotificationsViewer.java | 2 +- .../instagrabber/activities/PostViewer.java | 41 +++-- .../instagrabber/activities/StoryViewer.java | 152 ++++++++++++++++-- .../adapters/FeedStoriesAdapter.java | 2 + .../asyncs/FeedStoriesFetcher.java | 3 +- .../asyncs/i/iStoryStatusFetcher.java | 14 +- .../instagrabber/dialogs/SettingsDialog.java | 5 + .../instagrabber/models/BasePostModel.java | 8 - .../instagrabber/models/FeedStoryModel.java | 8 +- .../awais/instagrabber/models/StoryModel.java | 17 +- .../awais/instagrabber/utils/Constants.java | 1 + .../awais/instagrabber/utils/DataBox.java | 2 +- .../instagrabber/utils/SettingsHelper.java | 3 +- .../java/awais/instagrabber/utils/Utils.java | 3 +- app/src/main/res/layout/activity_comments.xml | 3 +- app/src/main/res/layout/activity_dms.xml | 39 ++++- .../main/res/layout/dialog_main_settings.xml | 25 +++ app/src/main/res/values/strings.xml | 5 + fastlane/metadata/android/changelogs/40.txt | 8 + 24 files changed, 376 insertions(+), 96 deletions(-) create mode 100644 fastlane/metadata/android/changelogs/40.txt diff --git a/app/build.gradle b/app/build.gradle index 4dfdaeae..5be8edf2 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { minSdkVersion 16 targetSdkVersion 29 - versionCode 39 - versionName '17.3' + versionCode 40 + versionName '17.4' multiDexEnabled true diff --git a/app/src/main/java/awais/instagrabber/MainHelper.java b/app/src/main/java/awais/instagrabber/MainHelper.java index 9a63ab82..ba325352 100755 --- a/app/src/main/java/awais/instagrabber/MainHelper.java +++ b/app/src/main/java/awais/instagrabber/MainHelper.java @@ -114,38 +114,15 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { main.mainBinding.mainPosts.setVisibility(View.VISIBLE); }); - final String username; - final String postFix; - if (!isHashtag && !isLocation) { - username = "@"+main.profileModel.getUsername(); - postFix = "/" + main.profileModel.getPostCount() + ')'; - } else { - username = null; - postFix = null; - } - if (isHashtag) main.mainBinding.toolbar.toolbar.setTitle(main.userQuery); else if (isLocation) main.mainBinding.toolbar.toolbar.setTitle(main.locationModel.getName()); - else main.mainBinding.toolbar.toolbar.setTitle(username + " (" + main.allItems.size() + postFix); + else main.mainBinding.toolbar.toolbar.setTitle("@"+main.profileModel.getUsername()); final PostModel model = result[result.length - 1]; if (model != null) { endCursor = model.getEndCursor(); - - if (endCursor == null && !isHashtag) { - main.mainBinding.toolbar.toolbar.setTitle(username + " (" + main.profileModel.getPostCount() + postFix); - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - main.mainBinding.toolbar.toolbar.setTitle(username); - handler.removeCallbacks(this); - } - }, 1000); - } - hasNextPage = model.hasNextPage(); if (autoloadPosts && hasNextPage) currentlyExecuting = new PostsFetcher(main.profileModel.getId(), endCursor, this) @@ -273,8 +250,6 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { ); else Toast.makeText(main, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - - } } }); @@ -1254,7 +1229,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener { Long.parseLong(Utils.dataBox.getFavorite(main.userQuery).split("/")[1]), main.locationModel != null ? main.locationModel.getName() : main.userQuery.replaceAll("^@", ""))); onRefresh(); - } else if (!isLoggedIn && v == main.mainBinding.btnFollow) { + } else if (!isLoggedIn && (v == main.mainBinding.btnFollow || v == main.mainBinding.btnFollowTag)) { Utils.dataBox.addFavorite(new DataBox.FavoriteModel(main.userQuery, System.currentTimeMillis(), main.locationModel != null ? main.locationModel.getName() : main.userQuery.replaceAll("^@", ""))); onRefresh(); diff --git a/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java b/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java index 99c6b1cb..ac49e521 100755 --- a/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java +++ b/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java @@ -279,7 +279,6 @@ public final class CommentsViewer extends BaseLanguageActivity implements SwipeR commentsBinding.commentText.clearFocus(); } } - else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); urlConnection.disconnect(); } catch (Throwable ex) { Log.e("austin_debug", action+": " + ex); @@ -296,10 +295,9 @@ public final class CommentsViewer extends BaseLanguageActivity implements SwipeR commentModel = null; focus = null; } - - //imm.hideSoftInputFromWindow(commentsBinding.getView().getRootView().getWindowToken(), 0); onRefresh(); } + else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/activities/DirectMessages.java b/app/src/main/java/awais/instagrabber/activities/DirectMessages.java index 77ae1862..ef9688a0 100755 --- a/app/src/main/java/awais/instagrabber/activities/DirectMessages.java +++ b/app/src/main/java/awais/instagrabber/activities/DirectMessages.java @@ -9,10 +9,12 @@ import androidx.annotation.Nullable; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import android.view.View; import java.util.ArrayList; import java.util.Arrays; +import awais.instagrabber.R; import awais.instagrabber.BuildConfig; import awais.instagrabber.adapters.DirectMessagesAdapter; import awais.instagrabber.asyncs.direct_messages.InboxFetcher; @@ -72,6 +74,9 @@ public final class DirectMessages extends BaseLanguageActivity implements SwipeR setContentView(dmsBinding.getRoot()); dmsBinding.swipeRefreshLayout.setOnRefreshListener(this); + dmsBinding.toolbar.toolbar.setTitle(R.string.action_dms); + dmsBinding.commentText.setVisibility(View.GONE); + dmsBinding.commentSend.setVisibility(View.GONE); final LinearLayoutManager layoutManager = new LinearLayoutManager(this); dmsBinding.rvDirectMessages.setLayoutManager(layoutManager); diff --git a/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java b/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java index 487fd6f6..e31a55fc 100755 --- a/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java +++ b/app/src/main/java/awais/instagrabber/activities/DirectMessagesUserInbox.java @@ -13,15 +13,19 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import java.io.DataOutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.UUID; import awais.instagrabber.R; import awais.instagrabber.adapters.MessageItemsAdapter; import awais.instagrabber.asyncs.direct_messages.UserInboxFetcher; -import awais.instagrabber.asyncs.UsernameFetcher; import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.ActivityDmsBinding; import awais.instagrabber.interfaces.FetchListener; @@ -29,22 +33,22 @@ import awais.instagrabber.models.PostModel; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.direct_messages.DirectItemModel; -import awais.instagrabber.models.direct_messages.DirectItemModel.DirectItemMediaModel; -import awais.instagrabber.models.direct_messages.DirectItemModel.DirectItemRavenMediaModel; import awais.instagrabber.models.direct_messages.InboxThreadModel; import awais.instagrabber.models.enums.DirectItemType; import awais.instagrabber.models.enums.DownloadMethod; -import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.enums.UserInboxDirection; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Utils; +import static awais.instagrabber.utils.Utils.settingsHelper; + 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<>(), leftusers = new ArrayList<>(); private final ArrayList directItemModels = new ArrayList<>(); + private String threadid; private final FetchListener fetchListener = new FetchListener() { @Override public void doBefore() { @@ -66,6 +70,14 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { leftusers.clear(); leftusers.addAll(Arrays.asList(result.getLeftUsers())); + threadid = result.getThreadId(); + dmsBinding.toolbar.toolbar.setTitle(result.getThreadTitle()); + String[] users = new String[result.getUsers().length]; + for (int i = 0; i < users.length; ++i) { + users[i] = result.getUsers()[i].getUsername(); + } + dmsBinding.toolbar.toolbar.setSubtitle(String.join(", ", users)); + final int oldSize = directItemModels.size(); final List itemModels = Arrays.asList(result.getItems()); directItemModels.addAll(itemModels); @@ -94,6 +106,9 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { } dmsBinding.swipeRefreshLayout.setEnabled(false); + dmsBinding.commentText.setVisibility(View.VISIBLE); + dmsBinding.commentSend.setVisibility(View.VISIBLE); + dmsBinding.commentSend.setOnClickListener(newCommentListener); final LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, true); dmsBinding.rvDirectMessages.setLayoutManager(layoutManager); @@ -138,7 +153,9 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { directItemModel.getReelShare().getMedia().getVideoUrl(), directItemModel.getReelShare().getMedia().getMediaType(), directItemModel.getTimestamp(), - directItemModel.getReelShare().getReelOwnerName() + directItemModel.getReelShare().getReelOwnerName(), + String.valueOf(directItemModel.getReelShare().getReelOwnerId()), + false ); sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl()); StoryModel[] sms = {sm}; @@ -196,4 +213,66 @@ public final class DirectMessagesUserInbox extends AppCompatActivity { startActivity(intent); } } + + private final View.OnClickListener newCommentListener = v -> { + if (Utils.isEmpty(dmsBinding.commentText.getText().toString()) && v == dmsBinding.commentSend) + Toast.makeText(getApplicationContext(), R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show(); + else if (v == dmsBinding.commentSend) new CommentAction().execute(); + }; + + class CommentAction extends AsyncTask { + boolean ok = false; + + protected Void doInBackground(Void... lmao) { + final String url = "https://i.instagram.com/api/v1/direct_v2/create_group_thread/"; + final String cookie = settingsHelper.getString(Constants.COOKIE); + try { + final String url2 = "https://i.instagram.com/api/v1/direct_v2/threads/broadcast/text/"; + final HttpURLConnection urlConnection2 = (HttpURLConnection) new URL(url2).openConnection(); + urlConnection2.setRequestMethod("POST"); + urlConnection2.setRequestProperty("User-Agent", Constants.I_USER_AGENT); + urlConnection2.setUseCaches(false); + final String commentText = URLEncoder.encode(dmsBinding.commentText.getText().toString(), "UTF-8") + .replaceAll("\\+", "%20").replaceAll("\\%21", "!").replaceAll("\\%27", "'") + .replaceAll("\\%28", "(").replaceAll("\\%29", ")").replaceAll("\\%7E", "~"); + final String cc = UUID.randomUUID().toString(); + final String urlParameters2 = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] + +"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie) + +"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) + +"\",\"client_context\":\"" + cc + +"\",\"mutation_token\":\"" + cc + +"\",\"text\":\"" + commentText + +"\",\"thread_ids\":\"["+threadid + +"]\",\"action\":\"send_item\"}"); + urlConnection2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + urlConnection2.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters2.getBytes().length)); + urlConnection2.setDoOutput(true); + DataOutputStream wr2 = new DataOutputStream(urlConnection2.getOutputStream()); + wr2.writeBytes(urlParameters2); + wr2.flush(); + wr2.close(); + urlConnection2.connect(); + Log.d("austin_debug", urlConnection2.getResponseCode() + " " + urlParameters2 + " " + cookie); + if (urlConnection2.getResponseCode() == HttpURLConnection.HTTP_OK) { + ok = true; + } + urlConnection2.disconnect(); + } catch (Throwable ex) { + Log.e("austin_debug", "dm send: " + ex); + } + return null; + } + + @Override + protected void onPostExecute(Void result) { + if (!ok) Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + else { + dmsBinding.commentText.setText(""); + dmsBinding.commentText.clearFocus(); + directItemModels.clear(); + messageItemsAdapter.notifyDataSetChanged(); + new UserInboxFetcher(threadid, UserInboxDirection.OLDER, null, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java b/app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java index b731f366..17204d8e 100755 --- a/app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java +++ b/app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java @@ -158,7 +158,6 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { ok = true; } - else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); urlConnection.disconnect(); } catch (Throwable ex) { Log.e("austin_debug", action+": " + ex); @@ -171,6 +170,7 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S if (ok == true) { onRefresh(); } + else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/activities/PostViewer.java b/app/src/main/java/awais/instagrabber/activities/PostViewer.java index bbdbe72b..dafb8e7e 100755 --- a/app/src/main/java/awais/instagrabber/activities/PostViewer.java +++ b/app/src/main/java/awais/instagrabber/activities/PostViewer.java @@ -88,7 +88,7 @@ public final class PostViewer extends BaseLanguageActivity { private SwipeEvent swipeEvent; private CharSequence postCaption = null, postShortCode, postUserId; private Resources resources; - private boolean session = false, isFromShare; + private boolean session = false, isFromShare, liked, saved, ok = false; private int slidePos = 0, lastSlidePos = 0; private ItemGetType itemGetType; @SuppressLint("ClickableViewAccessibility") @@ -237,6 +237,8 @@ public final class PostViewer extends BaseLanguageActivity { viewerBinding.bottomPanel.commentsCount.setText(String.valueOf(commentsCount)); viewerBinding.bottomPanel.btnComments.setVisibility(View.VISIBLE); + postShortCode = postModel.getShortCode(); + viewerBinding.bottomPanel.btnComments.setOnClickListener(v -> startActivityForResult(new Intent(this, CommentsViewer.class) .putExtra(Constants.EXTRAS_SHORTCODE, postShortCode) @@ -250,8 +252,10 @@ public final class PostViewer extends BaseLanguageActivity { postModel.setPostId(viewerPostModel.getPostId()); postModel.setTimestamp(viewerPostModel.getTimestamp()); postModel.setPostCaption(viewerPostModel.getPostCaption()); - postModel.setLike(viewerPostModel.getLike()); - postModel.setBookmark(viewerPostModel.getBookmark()); + if (!ok) { + liked = viewerPostModel.getLike(); + saved = viewerPostModel.getBookmark(); + } } setupPostInfoBar("@"+viewerPostModel.getUsername(), viewerPostModel.getItemType(), @@ -390,6 +394,7 @@ public final class PostViewer extends BaseLanguageActivity { if (isMainSwipe) { slidePos = 0; + ok = false; Log.d("AWAISKING_APP", "swipe left <<< post[" + position + "]: " + postModel + " -- " + slides); postModel = itemGetterItems.get(position); postModel.setPosition(position); @@ -628,19 +633,19 @@ public final class PostViewer extends BaseLanguageActivity { postModel.setPostId(viewerPostModel.getPostId()); postModel.setTimestamp(viewerPostModel.getTimestamp()); postModel.setPostCaption(viewerPostModel.getPostCaption()); - postModel.setLike(viewerPostModel.getLike()); - postModel.setBookmark(viewerPostModel.getBookmark()); - if (viewerPostModel.getLike() == true) { - viewerBinding.btnLike.setText(resources.getString(R.string.unlike, viewerPostModel.getLikes())); + if (liked == true) { + viewerBinding.btnLike.setText(resources.getString(R.string.unlike, viewerPostModel.getLikes() + + ((ok && viewerPostModel.getLike() != liked) ? (liked ? 1L : -1L) : 0L))); viewerBinding.btnLike.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor( getApplicationContext(), R.color.btn_pink_background))); } else { - viewerBinding.btnLike.setText(resources.getString(R.string.like, viewerPostModel.getLikes())); + viewerBinding.btnLike.setText(resources.getString(R.string.like, viewerPostModel.getLikes() + + ((ok && viewerPostModel.getLike() != liked) ? (liked ? 1L : -1L) : 0L))); viewerBinding.btnLike.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor( getApplicationContext(), R.color.btn_lightpink_background))); } - if (viewerPostModel.getBookmark() == true) { + if (saved == true) { viewerBinding.btnBookmark.setText(R.string.unbookmark); viewerBinding.btnBookmark.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor( getApplicationContext(), R.color.btn_orange_background))); @@ -755,20 +760,14 @@ public final class PostViewer extends BaseLanguageActivity { decorView.setSystemUiVisibility(newUiOptions); } - /* - Recommended for PERSONAL use only - Don't ever think about running a like farm with this - */ - class PostAction extends AsyncTask { - boolean ok = false; String action; protected Void doInBackground(String... rawAction) { action = rawAction[0]; final String url = "https://www.instagram.com/web/"+action+"/"+postModel.getPostId()+"/"+ (action == "save" ? - (postModel.getBookmark() == true ? "unsave/" : "save/") : - (postModel.getLike() == true ? "unlike/" : "like/")); + (saved ? "unsave/" : "save/") : + (liked ? "unlike/" : "like/")); try { final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection.setRequestMethod("POST"); @@ -780,7 +779,6 @@ public final class PostViewer extends BaseLanguageActivity { if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { ok = true; } - else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); urlConnection.disconnect(); } catch (Throwable ex) { Log.e("austin_debug", action+": " + ex); @@ -791,15 +789,14 @@ public final class PostViewer extends BaseLanguageActivity { @Override protected void onPostExecute(Void result) { if (ok == true && action == "likes") { - postModel.setLike(!viewerPostModel.getLike()); - viewerPostModel.setManualLike(!viewerPostModel.getLike()); + liked = !liked; refreshPost(); } else if (ok == true && action == "save") { - viewerPostModel.setBookmark(!viewerPostModel.getBookmark()); - postModel.setBookmark(!viewerPostModel.getBookmark()); + saved = !saved; refreshPost(); } + else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/activities/StoryViewer.java b/app/src/main/java/awais/instagrabber/activities/StoryViewer.java index 1c1b419e..f31e2cad 100755 --- a/app/src/main/java/awais/instagrabber/activities/StoryViewer.java +++ b/app/src/main/java/awais/instagrabber/activities/StoryViewer.java @@ -47,6 +47,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; +import java.util.Date; import java.util.UUID; import org.json.JSONObject; @@ -74,6 +75,7 @@ import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_ import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD; import static awais.instagrabber.utils.Constants.FOLDER_PATH; import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO; +import static awais.instagrabber.utils.Constants.MARK_AS_SEEN; import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -94,7 +96,7 @@ public final class StoryViewer extends BaseLanguageActivity { private GestureDetectorCompat gestureDetector; private SimpleExoPlayer player; private SwipeEvent swipeEvent; - private MenuItem menuDownload; + private MenuItem menuDownload, menuDm; private PollModel poll; private QuestionModel question; private String[] mentions; @@ -149,11 +151,11 @@ public final class StoryViewer extends BaseLanguageActivity { if ((isRightSwipe == true && index == 0) || (isRightSwipe == false && index == storyFeed.length - 1)) Toast.makeText(getApplicationContext(), R.string.no_more_stories, Toast.LENGTH_SHORT).show(); else { + boolean fetching = false; final FeedStoryModel feedStoryModel = isRightSwipe ? (index == 0 ? null : storyFeed[index - 1]) : (storyFeed.length == index + 1 ? null : storyFeed[index + 1]); if (feedStoryModel != null) { - boolean fetching = false; if (fetching) { Toast.makeText(getApplicationContext(), R.string.be_patient, Toast.LENGTH_SHORT).show(); } else { @@ -179,7 +181,6 @@ public final class StoryViewer extends BaseLanguageActivity { if (--slidePos <= 0) slidePos = 0; } else if (++slidePos >= storiesLen) slidePos = storiesLen - 1; currentStory = storyModels[slidePos]; - //slidePos = currentStory.getPosition(); refreshStory(); } } @@ -197,6 +198,7 @@ public final class StoryViewer extends BaseLanguageActivity { storiesAdapter.setData(null); if (menuDownload != null) menuDownload.setVisible(false); + if (menuDm != null) menuDm.setVisible(false); storyViewerBinding.playerView.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event)); storyViewerBinding.imageViewer.setOnSingleFlingListener((e1, e2, velocityX, velocityY) -> { @@ -318,12 +320,14 @@ public final class StoryViewer extends BaseLanguageActivity { @Override public void onLoadCompleted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) { if (menuDownload != null) menuDownload.setVisible(true); + if (currentStory.canReply() && menuDm != null) menuDm.setVisible(true); storyViewerBinding.progressView.setVisibility(View.GONE); } @Override public void onLoadStarted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) { if (menuDownload != null) menuDownload.setVisible(true); + if (currentStory.canReply() && menuDm != null) menuDm.setVisible(true); storyViewerBinding.progressView.setVisibility(View.VISIBLE); } @@ -335,6 +339,7 @@ public final class StoryViewer extends BaseLanguageActivity { @Override public void onLoadError(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData, final IOException error, final boolean wasCanceled) { if (menuDownload != null) menuDownload.setVisible(false); + if (menuDm != null) menuDm.setVisible(false); storyViewerBinding.progressView.setVisibility(View.GONE); } }); @@ -368,6 +373,7 @@ public final class StoryViewer extends BaseLanguageActivity { @Override public boolean onResourceReady(final Drawable resource, final Object model, final Target target, final DataSource dataSource, final boolean isFirstResource) { if (menuDownload != null) menuDownload.setVisible(true); + if (currentStory.canReply() && menuDm != null) menuDm.setVisible(true); storyViewerBinding.progressView.setVisibility(View.GONE); return false; } @@ -382,7 +388,9 @@ public final class StoryViewer extends BaseLanguageActivity { menu.findItem(R.id.action_search).setVisible(false); menuDownload = menu.findItem(R.id.action_download); + menuDm = menu.findItem(R.id.action_dms); menuDownload.setVisible(true); + menuDm.setVisible(false); menuDownload.setOnMenuItemClickListener(item -> { if (ContextCompat.checkSelfPermission(this, Utils.PERMS[0]) == PackageManager.PERMISSION_GRANTED) downloadStory(); @@ -390,6 +398,18 @@ public final class StoryViewer extends BaseLanguageActivity { ActivityCompat.requestPermissions(this, Utils.PERMS, 8020); return true; }); + menuDm.setOnMenuItemClickListener(item -> { + final EditText input = new EditText(this); + input.setHint(R.string.reply_hint); + new AlertDialog.Builder(this).setTitle(R.string.reply_story) + .setView(input) + .setPositiveButton(R.string.ok, (d,w) -> { + new CommentAction().execute(input.getText().toString()); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + return true; + }); return true; } @@ -488,6 +508,8 @@ public final class StoryViewer extends BaseLanguageActivity { storyViewerBinding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE); storyViewerBinding.quiz.setTag(quiz); + storyViewerBinding.toolbar.toolbar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L))); + releasePlayer(); final Intent intent = getIntent(); if (intent.getBooleanExtra(Constants.EXTRAS_HASHTAG, false)) { @@ -498,6 +520,8 @@ public final class StoryViewer extends BaseLanguageActivity { } if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo(); else setupImage(); + + if (settingsHelper.getBoolean(MARK_AS_SEEN)) new SeenAction().execute(); } private void searchUsername(final String text) { @@ -535,7 +559,7 @@ public final class StoryViewer extends BaseLanguageActivity { protected Void doInBackground(Integer... rawchoice) { int choice = rawchoice[0]; - final String url = "https://www.instagram.com/media/"+currentStory.getStoryMediaId()+"/"+poll.getId()+"/story_poll_vote/"; + final String url = "https://www.instagram.com/media/"+currentStory.getStoryMediaId().split("_")[0]+"/"+poll.getId()+"/story_poll_vote/"; try { final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection.setRequestMethod("POST"); @@ -554,7 +578,6 @@ public final class StoryViewer extends BaseLanguageActivity { if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { ok = choice; } - else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); urlConnection.disconnect(); } catch (Throwable ex) { Log.e("austin_debug", "vote: " + ex); @@ -568,6 +591,7 @@ public final class StoryViewer extends BaseLanguageActivity { poll.setMyChoice(ok); Toast.makeText(getApplicationContext(), R.string.votef_story_poll, Toast.LENGTH_SHORT).show(); } + else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } } @@ -578,7 +602,7 @@ public final class StoryViewer extends BaseLanguageActivity { protected Void doInBackground(Integer... rawchoice) { int choice = rawchoice[0]; final String cookie = settingsHelper.getString(Constants.COOKIE); - final String url = "https://i.instagram.com/api/v1/media/"+currentStory.getStoryMediaId()+"/"+quiz.getId()+"/story_quiz_answer/"; + final String url = "https://i.instagram.com/api/v1/media/"+currentStory.getStoryMediaId().split("_")[0]+"/"+quiz.getId()+"/story_quiz_answer/"; try { JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString() +"\",\"mutation_token\":\"" + UUID.randomUUID().toString() @@ -604,7 +628,6 @@ public final class StoryViewer extends BaseLanguageActivity { if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { ok = choice; } - else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); urlConnection.disconnect(); } catch (Throwable ex) { Log.e("austin_debug", "quiz: " + ex); @@ -618,6 +641,7 @@ public final class StoryViewer extends BaseLanguageActivity { quiz.setMyChoice(ok); Toast.makeText(getApplicationContext(), R.string.answered_story, Toast.LENGTH_SHORT).show(); } + else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } } @@ -628,7 +652,7 @@ public final class StoryViewer extends BaseLanguageActivity { protected Void doInBackground(String... rawchoice) { final String cookie = settingsHelper.getString(Constants.COOKIE); final String url = "https://i.instagram.com/api/v1/media/" - +currentStory.getStoryMediaId()+"/"+question.getId()+"/story_question_response/"; + +currentStory.getStoryMediaId().split("_")[0]+"/"+question.getId()+"/story_question_response/"; try { JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString() +"\",\"mutation_token\":\"" + UUID.randomUUID().toString() @@ -654,7 +678,6 @@ public final class StoryViewer extends BaseLanguageActivity { if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { ok = true; } - else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); urlConnection.disconnect(); } catch (Throwable ex) { Log.e("austin_debug", "respond: " + ex); @@ -667,6 +690,117 @@ public final class StoryViewer extends BaseLanguageActivity { if (ok) { Toast.makeText(getApplicationContext(), R.string.answered_story, Toast.LENGTH_SHORT).show(); } + else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + } + } + + class SeenAction extends AsyncTask { + protected Void doInBackground(Void... lmao) { + final String cookie = settingsHelper.getString(Constants.COOKIE); + final String url = "https://www.instagram.com/stories/reel/seen"; + try { + String urlParameters = "reelMediaId="+currentStory.getStoryMediaId().split("_")[0] + +"&reelMediaOwnerId="+currentStory.getUserId() + +"&reelId="+currentStory.getUserId() + +"&reelMediaTakenAt="+String.valueOf(currentStory.getTimestamp()) + +"&viewSeenAt="+String.valueOf(currentStory.getTimestamp()); + final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); + urlConnection.setRequestMethod("POST"); + urlConnection.setUseCaches(false); + urlConnection.setRequestProperty("x-csrftoken", + settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]); + urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); + urlConnection.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); + wr.writeBytes(urlParameters); + wr.flush(); + wr.close(); + urlConnection.connect(); + urlConnection.disconnect(); + } catch (Throwable ex) { + Log.e("austin_debug", "seen: " + ex); + } + return null; + } + } + + class CommentAction extends AsyncTask { + boolean ok = false; + + protected Void doInBackground(String... rawAction) { + final String action = rawAction[0]; + final String url = "https://i.instagram.com/api/v1/direct_v2/create_group_thread/"; + final String cookie = settingsHelper.getString(Constants.COOKIE); + try { + final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); + urlConnection.setRequestMethod("POST"); + urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); + urlConnection.setUseCaches(false); + final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] + +"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie) + +"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) + +"\",\"recipient_users\":\"["+currentStory.getUserId() // <- string of array of number (not joking) + +"]\"}"); + urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + urlConnection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length)); + urlConnection.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); + wr.writeBytes(urlParameters); + wr.flush(); + wr.close(); + urlConnection.connect(); + if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { + try { + final String threadid = new JSONObject(Utils.readFromConnection(urlConnection)).getString("thread_id"); + final String url2 = "https://i.instagram.com/api/v1/direct_v2/threads/broadcast/reel_share/"; + final HttpURLConnection urlConnection2 = (HttpURLConnection) new URL(url2).openConnection(); + urlConnection2.setRequestMethod("POST"); + urlConnection2.setRequestProperty("User-Agent", Constants.I_USER_AGENT); + urlConnection2.setUseCaches(false); + final String commentText = URLEncoder.encode(action, "UTF-8") + .replaceAll("\\+", "%20").replaceAll("\\%21", "!").replaceAll("\\%27", "'") + .replaceAll("\\%28", "(").replaceAll("\\%29", ")").replaceAll("\\%7E", "~"); + final String cc = UUID.randomUUID().toString(); + final String urlParameters2 = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] + +"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie) + +"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) + +"\",\"client_context\":\"" + cc + +"\",\"mutation_token\":\"" + cc + +"\",\"text\":\"" + commentText + +"\",\"media_id\":\"" + currentStory.getStoryMediaId() + +"\",\"reel_id\":\"" + currentStory.getUserId() + +"\",\"thread_ids\":\"["+threadid + +"]\",\"action\":\"send_item\",\"entry\":\"reel\"}"); + urlConnection2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + urlConnection2.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters2.getBytes().length)); + urlConnection2.setDoOutput(true); + DataOutputStream wr2 = new DataOutputStream(urlConnection2.getOutputStream()); + wr2.writeBytes(urlParameters2); + wr2.flush(); + wr2.close(); + urlConnection2.connect(); + Log.d("austin_debug", urlConnection2.getResponseCode() + " " + urlParameters2 + " " + cookie); + if (urlConnection2.getResponseCode() == HttpURLConnection.HTTP_OK) { + ok = true; + } + urlConnection2.disconnect(); + } catch (Throwable ex) { + Log.e("austin_debug", "reply (B): " + ex); + } + } + + urlConnection.disconnect(); + } catch (Throwable ex) { + Log.e("austin_debug", "reply (CT): " + ex); + } + return null; + } + + @Override + protected void onPostExecute(Void result) { + Toast.makeText(getApplicationContext(), + ok ? R.string.answered_story : R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/adapters/FeedStoriesAdapter.java b/app/src/main/java/awais/instagrabber/adapters/FeedStoriesAdapter.java index f28bfeb3..05769834 100755 --- a/app/src/main/java/awais/instagrabber/adapters/FeedStoriesAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/FeedStoriesAdapter.java @@ -42,6 +42,8 @@ public final class FeedStoriesAdapter extends RecyclerView.Adapter 0 && @@ -65,11 +62,12 @@ public final class iStoryStatusFetcher extends AsyncTask + tools:context=".activities.CommentsViewer"> + + + android:layout_height="match_parent"> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_main_settings.xml b/app/src/main/res/layout/dialog_main_settings.xml index 68117ac0..e04a35e8 100755 --- a/app/src/main/res/layout/dialog_main_settings.xml +++ b/app/src/main/res/layout/dialog_main_settings.xml @@ -259,6 +259,31 @@ android:textSize="16sp" /> + + + + + + + Settings (v%s) Settings Download + Mark as Seen GitHub F-Droid Search username… @@ -37,6 +38,7 @@ Show toolbar at bottom Download posts to username folder in Downloads Auto-load all posts from user + Mark stories as seen after viewing\n(Story author will know you viewed it) Error loading profile!\nTry logging in and search again. Error creating Download folder(s). Show user feed (Works only when user is logged in) @@ -71,6 +73,8 @@ Respond Answer... Answer successful! + Reply to story + Reply... Quiz You have already answered! Mentions @@ -189,6 +193,7 @@ Successfully loaded cookies!\nIf you still can\'t open private pages/posts, re-login! Write a new comment... + Write a new message... Liked your post Commented on your post: diff --git a/fastlane/metadata/android/changelogs/40.txt b/fastlane/metadata/android/changelogs/40.txt new file mode 100644 index 00000000..2a61824c --- /dev/null +++ b/fastlane/metadata/android/changelogs/40.txt @@ -0,0 +1,8 @@ +* You can now send text DMs +* You can now reply DM to stories +* DM title and (some) members are now shown on DM screen +* Seen stories (API) are now displayed transparently +* Story creation date is now shown on the story screen +* A new setting allows you to mark stories as seen (Default disabled) +* Fixed a bug related to the favourite button on profile +* Fixed a bug where liked/saved status does not carry over across slides \ No newline at end of file