unsend messages and activity notification

This commit is contained in:
Austin Huang 2020-08-19 12:51:41 -04:00
parent 376f3e5d5a
commit 4857b3bfa0
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
8 changed files with 167 additions and 36 deletions

View File

@ -10,8 +10,8 @@ android {
minSdkVersion 16
targetSdkVersion 29
versionCode 45
versionName '17.9'
versionCode 46
versionName '18.0'
multiDexEnabled true

View File

@ -1,5 +1,7 @@
package awais.instagrabber.activities;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@ -7,8 +9,10 @@ import android.content.res.Resources;
import android.database.MatrixCursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
import android.provider.BaseColumns;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -20,9 +24,14 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SearchView;
import androidx.core.app.NotificationCompat;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.GridLayoutManager;
import org.json.JSONObject;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Stack;
@ -58,6 +67,8 @@ import awais.instagrabber.utils.DataBox;
import awais.instagrabber.utils.FlavorTown;
import awais.instagrabber.utils.Utils;
import static awais.instagrabber.utils.Utils.CHANNEL_ID;
import static awais.instagrabber.utils.Utils.notificationManager;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class Main extends BaseLanguageActivity {
@ -97,7 +108,7 @@ public final class Main extends BaseLanguageActivity {
public SearchView searchView;
public MenuItem downloadAction, settingsAction, dmsAction, notifAction;
public StoryModel[] storyModels;
public String userQuery = null;
public String userQuery = null, cookie, uid = null;
public MainHelper mainHelper;
public ProfileModel profileModel;
public HashtagModel hashtagModel;
@ -117,8 +128,8 @@ public final class Main extends BaseLanguageActivity {
FlavorTown.updateCheck(this);
FlavorTown.changelogCheck(this);
final String cookie = settingsHelper.getString(Constants.COOKIE);
final String uid = Utils.getUserIdFromCookie(cookie);
cookie = settingsHelper.getString(Constants.COOKIE);
uid = Utils.getUserIdFromCookie(cookie);
Utils.setupCookies(cookie);
MainHelper.stopCurrentExecutor();
@ -246,6 +257,14 @@ public final class Main extends BaseLanguageActivity {
mainHelper.onRefresh();
mainHelper.onIntent(getIntent());
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
new GetActivity().execute();
handler.postDelayed(this, 60000);
}
}, 200);
}
private void downloadSelectedItems() {
@ -536,4 +555,57 @@ public final class Main extends BaseLanguageActivity {
}
return false;
}
class GetActivity extends AsyncTask<Void, Void, Void> {
String ok = null;
protected Void doInBackground(Void... lmao) {
final String url = "https://www.instagram.com/graphql/query/?query_hash=0f318e8cfff9cc9ef09f88479ff571fb"
+ "&variables={\"id\":\""+uid+"\"}";
if (!Utils.isEmpty(cookie)) try {
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
final JSONObject data = new JSONObject(Utils.readFromConnection(urlConnection)).getJSONObject("data")
.getJSONObject("user").getJSONObject("edge_activity_count").getJSONArray("edges").getJSONObject(0)
.getJSONObject("node");
ok = (getString(R.string.activity_count_prefix) + " " + String.join(", ",
data.getInt("relationships") == 0 ? null : getString(R.string.activity_count_relationship, data.getInt("relationships")),
data.getInt("usertags") == 0 ? null : getString(R.string.activity_count_usertags, data.getInt("usertags")),
data.getInt("comments") == 0 ? null : getString(R.string.activity_count_comments, data.getInt("comments")),
data.getInt("comment_likes") == 0 ? null : getString(R.string.activity_count_commentlikes, data.getInt("comment_likes")),
data.getInt("likes") == 0 ? null : getString(R.string.activity_count_likes, data.getInt("likes"))) + ".")
.replaceAll("null, ", "").replaceAll(",,+", ",").replaceAll("(,+|null).", ".");
}
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "getactivity: " + ex);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (ok == null) {
if (!Utils.isEmpty(cookie)) Toast.makeText(Main.this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
else if (!ok.equals(getString(R.string.activity_count_prefix) + " .")) {
final Notification notif = new NotificationCompat.Builder(Main.this, CHANNEL_ID)
.setCategory(NotificationCompat.CATEGORY_STATUS).setSmallIcon(R.drawable.ic_notif)
.setAutoCancel(true).setPriority(NotificationCompat.PRIORITY_MIN).setContentText(ok)
.setContentIntent(
PendingIntent.getActivity(getApplicationContext(), 1738,
new Intent(getApplicationContext(), NotificationsViewer.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
, PendingIntent.FLAG_UPDATE_CURRENT))
.build();
if (notificationManager != null) {
notificationManager.cancel(1800000000);
notificationManager.notify(1800000000, notif);
}
}
}
}
}

View File

@ -35,8 +35,9 @@ import awais.instagrabber.models.ProfileModel;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;
import static awais.instagrabber.utils.Utils.notificationManager;
public final class NotificationsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
private NotificationsAdapter notificationsAdapter;
private NotificationModel notificationModel;
private ActivityNotificationBinding notificationsBinding;
private ArrayAdapter<String> commmentDialogAdapter;
@ -47,26 +48,18 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
notificationManager.cancel(1800000000);
if (Utils.isEmpty(cookie)) {
Toast.makeText(this, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
}
super.onCreate(savedInstanceState);
notificationsBinding = ActivityNotificationBinding.inflate(getLayoutInflater());
setContentView(notificationsBinding.getRoot());
notificationsBinding.swipeRefreshLayout.setOnRefreshListener(this);
notificationsBinding.swipeRefreshLayout.setRefreshing(true);
resources = getResources();
setSupportActionBar(notificationsBinding.toolbar.toolbar);
notificationsBinding.toolbar.toolbar.setTitle(R.string.action_notif);
resources = getResources();
new NotificationsFetcher(new FetchListener<NotificationModel[]>() {
@Override
public void onResult(final NotificationModel[] notificationModels) {
notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener);
notificationsBinding.rvComments.setAdapter(notificationsAdapter);
notificationsBinding.swipeRefreshLayout.setRefreshing(false);
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
onRefresh();
}
@Override
@ -75,11 +68,9 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
new NotificationsFetcher(new FetchListener<NotificationModel[]>() {
@Override
public void onResult(final NotificationModel[] notificationModels) {
notificationsBinding.rvComments.setAdapter(new NotificationsAdapter(notificationModels, clickListener, mentionClickListener));
notificationsBinding.swipeRefreshLayout.setRefreshing(false);
notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener);
notificationsBinding.rvComments.setAdapter(notificationsAdapter);
new SeenAction().execute();
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@ -150,7 +141,8 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
urlConnection.setRequestProperty("x-csrftoken",
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);urlConnection.connect();
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
ok = true;
}
@ -169,4 +161,23 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
}
class SeenAction extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... lmao) {
try {
final HttpURLConnection urlConnection =
(HttpURLConnection) new URL("https://www.instagram.com/web/activity/mark_checked/").openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
urlConnection.setRequestProperty("x-csrftoken",
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "seen: " + ex);
}
return null;
}
}
}

View File

@ -19,6 +19,7 @@ import awais.instagrabber.utils.Utils;
import awaisomereport.LogCollector;
import static awais.instagrabber.utils.Utils.logCollector;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class NotificationsFetcher extends AsyncTask<Void, Void, NotificationModel[]> {
private final FetchListener<NotificationModel[]> fetchListener;
@ -31,6 +32,7 @@ public final class NotificationsFetcher extends AsyncTask<Void, Void, Notificati
protected NotificationModel[] doInBackground(final Void... voids) {
NotificationModel[] result = null;
final String url = "https://www.instagram.com/accounts/activity/?__a=1";
Utils.setupCookies(settingsHelper.getString(Constants.COOKIE));
try {
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();

View File

@ -31,17 +31,20 @@ import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import awais.instagrabber.R;
import awais.instagrabber.activities.PostViewer;
@ -80,7 +83,7 @@ public class DirectMessageThreadFragment extends Fragment {
private DirectItemModelListViewModel listViewModel;
private DirectItemModel directItemModel;
private RecyclerView messageList;
private boolean hasSentSomething;
private boolean hasSentSomething, hasDeletedSomething;
private boolean hasOlder = true;
private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel();
@ -137,15 +140,16 @@ public class DirectMessageThreadFragment extends Fragment {
List<DirectItemModel> list = listViewModel.getList().getValue();
final List<DirectItemModel> newList = Arrays.asList(result.getItems());
list = list != null ? new LinkedList<>(list) : new LinkedList<>();
if (hasSentSomething) {
if (hasSentSomething || hasDeletedSomething) {
list = newList;
hasSentSomething = false;
final Handler handler = new Handler();
handler.postDelayed(() -> {
if (hasSentSomething) handler.postDelayed(() -> {
if (messageList != null) {
messageList.smoothScrollToPosition(0);
}
}, 200);
hasSentSomething = false;
hasDeletedSomething = false;
} else {
list.addAll(newList);
}
@ -244,9 +248,7 @@ public class DirectMessageThreadFragment extends Fragment {
sendText(null, directItemModel.getItemId(), directItemModel.isLiked());
}
else if (w == 2) {
if (String.valueOf(directItemModel.getUserId()).equals(myId)) {
// unsend: https://www.instagram.com/direct_v2/web/threads/340282366841710300949128288687654467119/items/29473546990090204551245070881259520/delete/
}
if (String.valueOf(directItemModel.getUserId()).equals(myId)) new Unsend().execute();
else searchUsername(getUser(directItemModel.getUserId()).getUsername());
}
};
@ -430,4 +432,41 @@ public class DirectMessageThreadFragment extends Fragment {
return list;
}
}
class Unsend extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... lmao) {
final String url = "https://i.instagram.com/api/v1/direct_v2/threads/"+threadId+"/items/"+directItemModel.getItemId()+"/delete/";
try {
String urlParameters = "_csrftoken=" + cookie.split("csrftoken=")[1].split(";")[0]
+"&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID);
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
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) {
hasDeletedSomething = true;
}
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "unsend: " + ex);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (hasDeletedSomething) {
directItemModel = null;
new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
}

View File

@ -33,9 +33,9 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
conn.connect();
final int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP && !BuildConfig.DEBUG) {
version = conn.getHeaderField("Location").split("/v")[1];
return Float.parseFloat(version) > Float.parseFloat(BuildConfig.VERSION_NAME);
return version != BuildConfig.VERSION_NAME;
}
conn.disconnect();

View File

@ -175,8 +175,8 @@ public final class Utils {
clipString = clipString.substring((isHttps ? 22 : 21) + wwwDel);
final char firstChar = clipString.charAt(0);
if (clipString.startsWith("p/") || clipString.startsWith("reel/")) {
clipString = clipString.substring(clipString.startsWith("p/") ? 2 : 5);
if (clipString.startsWith("p/") || clipString.startsWith("reel/") || clipString.startsWith("tv/")) {
clipString = clipString.substring(clipString.startsWith("p/") ? 2 : (clipString.startsWith("tv/") ? 3 : 5));
type = IntentModelType.POST;
} else if (clipString.startsWith("explore/tags/")) {
clipString = clipString.substring(13);

View File

@ -222,4 +222,11 @@
<string name="license" translatable="false">InstaGrabber\nCopyright (C) 2019 AWAiS\nCopyright (C) 2020 Austin Huang, Ammar Githam\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See https://www.gnu.org/licenses/.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR \'\'AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSee project page for third-party attributions.</string>
<string name="select_picture">Select Picture</string>
<string name="uploading">Uploading...</string>
<string name="activity_count_prefix">You have:</string>
<string name="activity_count_relationship">%s follows</string>
<string name="activity_count_comments">%s comments</string>
<string name="activity_count_commentlikes">%s comment likes</string>
<string name="activity_count_usertags">%s usertags</string>
<string name="activity_count_likes">%s likes</string>
<string name="activity_notloggedin">You logged out before clicking this notification?!</string>
</resources>