() {
@Override
public void onSuccess(final Account result) {
- final FragmentActivity activity = getActivity();
- if (activity == null) return;
- activity.recreate();
+ // final FragmentActivity activity = getActivity();
+ // if (activity == null) return;
+ // activity.recreate();
+ AppExecutors.getInstance().mainThread().execute(() -> {
+ final Context context = getContext();
+ if (context == null) return;
+ ProcessPhoenix.triggerRebirth(context);
+ }, 200);
}
@Override
diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java
index 3482cf7f..5287a1a5 100644
--- a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java
+++ b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java
@@ -6,4 +6,5 @@ public final class PreferenceKeys {
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT = "enable_dm_auto_refresh_freq_unit";
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number";
public static final String PREF_ENABLE_SENTRY = "enable_sentry";
+ public static final String PREF_TAB_ORDER = "tab_order";
}
diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java
index 8337f7c3..99eee7c7 100644
--- a/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java
+++ b/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java
@@ -37,6 +37,14 @@ public class StoriesPreferencesFragment extends BasePreferencesFragment {
return preference;
}
+ private Preference getHideMutedReelsPreference(@NonNull final Context context) {
+ final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
+ preference.setKey(Constants.HIDE_MUTED_REELS);
+ preference.setTitle(R.string.hide_muted_reels_setting);
+ preference.setIconSpaceReserved(false);
+ return preference;
+ }
+
private Preference getMarkStoriesSeenPreference(@NonNull final Context context) {
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
preference.setKey(Constants.MARK_AS_SEEN);
diff --git a/app/src/main/java/awais/instagrabber/models/Tab.java b/app/src/main/java/awais/instagrabber/models/Tab.java
new file mode 100644
index 00000000..e4e608be
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/models/Tab.java
@@ -0,0 +1,110 @@
+package awais.instagrabber.models;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.IdRes;
+import androidx.annotation.NavigationRes;
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+public class Tab {
+ private final int iconResId;
+ private final String title;
+ private final boolean removable;
+
+ /**
+ * This is name part of the navigation resource
+ * eg: @navigation/graphName
+ */
+ private final String graphName;
+
+ /**
+ * This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId)
+ */
+ private final int navigationResId;
+
+ /**
+ * This is the resource id of the root navigation tag of the navigation resource.
+ * eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph.
+ *
So this field would equal to the value of R.id.direct_messages_nav_graph
+ */
+ private final int navigationRootId;
+
+ /**
+ * This is the start destination of the nav graph
+ */
+ private final int startDestinationFragmentId;
+
+ public Tab(@DrawableRes final int iconResId,
+ @NonNull final String title,
+ final boolean removable,
+ @NonNull final String graphName,
+ @NavigationRes final int navigationResId,
+ @IdRes final int navigationRootId,
+ @IdRes final int startDestinationFragmentId) {
+ this.iconResId = iconResId;
+ this.title = title;
+ this.removable = removable;
+ this.graphName = graphName;
+ this.navigationResId = navigationResId;
+ this.navigationRootId = navigationRootId;
+ this.startDestinationFragmentId = startDestinationFragmentId;
+ }
+
+ public int getIconResId() {
+ return iconResId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public boolean isRemovable() {
+ return removable;
+ }
+
+ public String getGraphName() {
+ return graphName;
+ }
+
+ public int getNavigationResId() {
+ return navigationResId;
+ }
+
+ public int getNavigationRootId() {
+ return navigationRootId;
+ }
+
+ public int getStartDestinationFragmentId() {
+ return startDestinationFragmentId;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final Tab tab = (Tab) o;
+ return iconResId == tab.iconResId &&
+ removable == tab.removable &&
+ navigationResId == tab.navigationResId &&
+ navigationRootId == tab.navigationRootId &&
+ startDestinationFragmentId == tab.startDestinationFragmentId &&
+ Objects.equals(title, tab.title) &&
+ Objects.equals(graphName, tab.graphName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId, startDestinationFragmentId);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "Tab{" +
+ "title='" + title + '\'' +
+ ", removable=" + removable +
+ ", graphName='" + graphName + '\'' +
+ '}';
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java b/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java
index 7dda390d..148e8f43 100644
--- a/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java
+++ b/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java
@@ -3,7 +3,6 @@ package awais.instagrabber.repositories;
import java.util.Map;
import awais.instagrabber.repositories.responses.search.SearchResponse;
-
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.QueryMap;
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java
index 10074f70..dfad97e0 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java
@@ -1,7 +1,5 @@
package awais.instagrabber.repositories.responses.notification;
-import androidx.annotation.NonNull;
-
public class NotificationCounts {
private final int commentLikes;
private final int usertags;
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchResponse.java
index 04db0286..d3f0e143 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchResponse.java
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchResponse.java
@@ -2,8 +2,6 @@ package awais.instagrabber.repositories.responses.search;
import java.util.List;
-import awais.instagrabber.repositories.responses.User;
-
public class SearchResponse {
// app
private final List list;
diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java
index 969f5d6a..a2a5fd13 100644
--- a/app/src/main/java/awais/instagrabber/utils/Constants.java
+++ b/app/src/main/java/awais/instagrabber/utils/Constants.java
@@ -20,6 +20,7 @@ public final class Constants {
// boolean prefs
public static final String DOWNLOAD_USER_FOLDER = "download_user_folder";
public static final String TOGGLE_KEYWORD_FILTER = "toggle_keyword_filter";
+ public static final String DOWNLOAD_PREPEND_USER_NAME = "download_user_name";
// deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar";
public static final String FOLDER_SAVE_TO = "saved_to";
public static final String AUTOPLAY_VIDEOS = "autoplay_videos";
@@ -28,6 +29,7 @@ public final class Constants {
public static final String CUSTOM_DATE_TIME_FORMAT_ENABLED = "data_time_custom_enabled";
public static final String SWAP_DATE_TIME_FORMAT_ENABLED = "swap_date_time_enabled";
public static final String MARK_AS_SEEN = "mark_as_seen";
+ public static final String HIDE_MUTED_REELS = "hide_muted_reels";
public static final String DM_MARK_AS_SEEN = "dm_mark_as_seen";
// deprecated: public static final String INSTADP = "instadp";
// deprecated: public static final String STORIESIG = "storiesig";
@@ -79,7 +81,6 @@ public final class Constants {
// public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc";
public static final String BREADCRUMB_KEY = "iN4$aGr0m";
public static final int LOGIN_RESULT_CODE = 5000;
- public static final String FDROID_SHA1_FINGERPRINT = "C1661EB8FD09F618307E687786D5E5056F65084D";
public static final String SKIPPED_VERSION = "skipped_version";
public static final String DEFAULT_TAB = "default_tab";
public static final String PREF_DARK_THEME = "dark_theme";
@@ -113,6 +114,7 @@ public final class Constants {
public static final int SHOW_ACTIVITY_REQUEST_CODE = 1738;
public static final int SHOW_DM_THREAD = 2000;
public static final int DM_SYNC_SERVICE_REQUEST_CODE = 3000;
+ public static final int GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE = 7777;
public static final String ACTION_SHOW_ACTIVITY = "show_activity";
public static final String ACTION_SHOW_DM_THREAD = "show_dm_thread";
diff --git a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
index 1110e58a..b44c7d3f 100755
--- a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
@@ -157,12 +157,21 @@ public final class ExportImportUtils {
query,
favoriteType,
favsObject.optString("s"),
- favoriteType == FavoriteType.HASHTAG ? null
- : favsObject.optString("pic_url"),
+ favoriteType == FavoriteType.USER ? favsObject.optString("pic_url") : null,
new Date(favsObject.getLong("d")));
// Log.d(TAG, "importJson: favoriteModel: " + favoriteModel);
- FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context))
- .insertOrUpdateFavorite(favorite, null);
+ final FavoriteRepository favRepo = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context));
+ favRepo.getFavorite(query, favoriteType, new RepositoryCallback() {
+ @Override
+ public void onSuccess(final Favorite result) {
+ // local has priority since it's more frequently updated
+ }
+
+ @Override
+ public void onDataNotAvailable() {
+ favRepo.insertOrUpdateFavorite(favorite, null);
+ }
+ });
}
}
diff --git a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java
index ee859700..8f06eb8b 100755
--- a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java
+++ b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java
@@ -1,104 +1,72 @@
package awais.instagrabber.utils;
-import android.annotation.SuppressLint;
-import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
-
-import javax.security.cert.CertificateException;
-import javax.security.cert.X509Certificate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.R;
-import awais.instagrabber.databinding.DialogUpdateBinding;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class FlavorTown {
private static final String TAG = "FlavorTown";
- private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
- private static AlertDialog dialog;
+ private static final UpdateChecker UPDATE_CHECKER = UpdateChecker.getInstance();
+ private static final Pattern VERSION_NAME_PATTERN = Pattern.compile("v?(\\d+\\.\\d+\\.\\d+)(?:_?)(\\w*)(?:-?)(\\w*)");
+
+ private static boolean checking = false;
public static void updateCheck(@NonNull final AppCompatActivity context) {
updateCheck(context, false);
}
- @SuppressLint("PackageManagerGetSignatures")
- public static void updateCheck(@NonNull final AppCompatActivity context, final boolean force) {
- boolean isInstalledFromFdroid = false;
- final PackageInfo packageInfo;
- try {
- packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
- for (Signature signature : packageInfo.signatures) {
- final X509Certificate cert = X509Certificate.getInstance(signature.toByteArray());
- final String fingerprint = bytesToHex(MessageDigest.getInstance("SHA-1").digest(cert.getEncoded()));
- isInstalledFromFdroid = fingerprint.equals(Constants.FDROID_SHA1_FINGERPRINT);
- // Log.d(TAG, "fingerprint:" + fingerprint);
- }
- } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException | CertificateException e) {
- Log.e(TAG, "Error", e);
- }
- if (isInstalledFromFdroid) return;
- final DialogUpdateBinding binding = DialogUpdateBinding.inflate(context.getLayoutInflater(), null, false);
- binding.skipUpdate.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (dialog == null) return;
- dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked);
- });
- Resources res = context.getResources();
- new UpdateChecker(version -> {
- if (force && version.equals(BuildConfig.VERSION_NAME)) {
- Toast.makeText(context, "You're already on the latest version", Toast.LENGTH_SHORT).show();
+ public static void updateCheck(@NonNull final AppCompatActivity context,
+ final boolean force) {
+ if (checking) return;
+ checking = true;
+ AppExecutors.getInstance().networkIO().execute(() -> {
+ final String onlineVersionName = UPDATE_CHECKER.getLatestVersion();
+ if (onlineVersionName == null) return;
+ final String onlineVersion = getVersion(onlineVersionName);
+ final String localVersion = getVersion(BuildConfig.VERSION_NAME);
+ if (Objects.equals(onlineVersion, localVersion)) {
+ if (force) {
+ AppExecutors.getInstance().mainThread().execute(() -> {
+ final Context applicationContext = context.getApplicationContext();
+ // Check if app was closed or crashed before reaching here
+ if (applicationContext == null) return;
+ // Show toast if version number preference was tapped
+ Toast.makeText(applicationContext, R.string.on_latest_version, Toast.LENGTH_SHORT).show();
+ });
+ }
return;
}
- final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION);
- final boolean shouldShowDialog = force || (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG && !skippedVersion
- .equals(version));
+ final boolean shouldShowDialog = UpdateCheckCommon.shouldShowUpdateDialog(force, onlineVersionName);
if (!shouldShowDialog) return;
- dialog = new AlertDialog.Builder(context)
- .setTitle(res.getString(R.string.update_available, version))
- .setView(binding.getRoot())
- .setNeutralButton(R.string.cancel, (dialog, which) -> {
- if (binding.skipUpdate.isChecked()) {
- settingsHelper.putString(Constants.SKIPPED_VERSION, version);
- }
- dialog.dismiss();
- })
- .setPositiveButton(R.string.action_github, (dialog1, which) -> {
- try {
- context.startActivity(new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("https://github.com/austinhuang0131/instagrabber/releases/latest")));
- } catch (final ActivityNotFoundException e) {
- // do nothing
- }
- })
- // if we don't show dialog for fdroid users, is the below required?
- .setNegativeButton(R.string.action_fdroid, (dialog, which) -> {
- try {
- context.startActivity(new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("https://f-droid.org/packages/me.austinhuang.instagrabber/")));
- } catch (final ActivityNotFoundException e) {
- // do nothing
- }
- })
- .show();
- }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ UpdateCheckCommon.showUpdateDialog(context, onlineVersionName, (dialog, which) -> {
+ UPDATE_CHECKER.onDownload(context);
+ dialog.dismiss();
+ });
+ });
+ }
+
+ private static String getVersion(@NonNull final String versionName) {
+ final Matcher matcher = VERSION_NAME_PATTERN.matcher(versionName);
+ if (!matcher.matches()) return versionName;
+ try {
+ return matcher.group(1);
+ } catch (Exception e) {
+ Log.e(TAG, "getVersion: ", e);
+ }
+ return versionName;
}
public static void changelogCheck(@NonNull final Context context) {
@@ -121,14 +89,4 @@ public final class FlavorTown {
settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE);
}
}
-
- public static String bytesToHex(byte[] bytes) {
- char[] hexChars = new char[bytes.length * 2];
- for (int j = 0; j < bytes.length; j++) {
- int v = bytes[j] & 0xFF;
- hexChars[j * 2] = HEX_ARRAY[v >>> 4];
- hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
- }
- return new String(hexChars);
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/utils/MediaUploader.java b/app/src/main/java/awais/instagrabber/utils/MediaUploader.java
index 30570663..e5bacd98 100644
--- a/app/src/main/java/awais/instagrabber/utils/MediaUploader.java
+++ b/app/src/main/java/awais/instagrabber/utils/MediaUploader.java
@@ -16,7 +16,7 @@ import java.util.Map;
import awais.instagrabber.models.UploadPhotoOptions;
import awais.instagrabber.models.UploadVideoOptions;
-import awais.instagrabber.webservices.AddCookiesInterceptor;
+import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.MediaType;
diff --git a/app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java b/app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java
new file mode 100644
index 00000000..5dcc6e19
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/utils/ProcessPhoenix.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 Jake Wharton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package awais.instagrabber.utils;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+/**
+ * Process Phoenix facilitates restarting your application process. This should only be used for
+ * things like fundamental state changes in your debug builds (e.g., changing from staging to
+ * production).
+ *
+ * Trigger process recreation by calling {@link #triggerRebirth} with a {@link Context} instance.
+ */
+public final class ProcessPhoenix extends Activity {
+ private static final String KEY_RESTART_INTENTS = "phoenix_restart_intents";
+
+ /**
+ * Call to restart the application process using the {@linkplain Intent#CATEGORY_DEFAULT default}
+ * activity as an intent.
+ *
+ * Behavior of the current process after invoking this method is undefined.
+ */
+ public static void triggerRebirth(Context context) {
+ triggerRebirth(context, getRestartIntent(context));
+ }
+
+ /**
+ * Call to restart the application process using the specified intents.
+ *
+ * Behavior of the current process after invoking this method is undefined.
+ */
+ public static void triggerRebirth(Context context, Intent... nextIntents) {
+ Intent intent = new Intent(context, ProcessPhoenix.class);
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK); // In case we are called with non-Activity context.
+ intent.putParcelableArrayListExtra(KEY_RESTART_INTENTS, new ArrayList<>(Arrays.asList(nextIntents)));
+ context.startActivity(intent);
+ if (context instanceof Activity) {
+ ((Activity) context).finish();
+ }
+ Runtime.getRuntime().exit(0); // Kill kill kill!
+ }
+
+ private static Intent getRestartIntent(Context context) {
+ String packageName = context.getPackageName();
+ Intent defaultIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
+ if (defaultIntent != null) {
+ defaultIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+ return defaultIntent;
+ }
+
+ throw new IllegalStateException("Unable to determine default activity for "
+ + packageName
+ + ". Does an activity specify the DEFAULT category in its intent filter?");
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ArrayList intents = getIntent().getParcelableArrayListExtra(KEY_RESTART_INTENTS);
+ startActivities(intents.toArray(new Intent[intents.size()]));
+ finish();
+ Runtime.getRuntime().exit(0); // Kill kill kill!
+ }
+
+ /**
+ * Checks if the current process is a temporary Phoenix Process.
+ * This can be used to avoid initialisation of unused resources or to prevent running code that
+ * is not multi-process ready.
+ *
+ * @return true if the current process is a temporary Phoenix Process
+ */
+ public static boolean isPhoenixProcess(Context context) {
+ int currentPid = Process.myPid();
+ ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List runningProcesses = manager.getRunningAppProcesses();
+ if (runningProcesses != null) {
+ for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
+ if (processInfo.pid == currentPid && processInfo.processName.endsWith(":phoenix")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
index 906d3945..a4bb68bc 100644
--- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java
@@ -1089,12 +1089,19 @@ public final class ResponseBodyUtils {
if (imageVersions2 == null) return null;
final List candidates = imageVersions2.getCandidates();
if (candidates == null || candidates.isEmpty()) return null;
- final List sortedCandidates = candidates
- .stream()
+ final boolean isSquare = Integer.compare(media.getOriginalWidth(), media.getOriginalHeight()) == 0;
+ final List sortedCandidates = candidates.stream()
.sorted((c1, c2) -> Integer.compare(c2.getWidth(), c1.getWidth()))
- // .filter(c -> c.getWidth() < type.getValue())
.collect(Collectors.toList());
- final MediaCandidate candidate = sortedCandidates.get(0);
+ if (sortedCandidates.size() == 1) return sortedCandidates.get(0).getUrl();
+ final List filteredCandidates = sortedCandidates.stream()
+ .filter(c ->
+ c.getWidth() <= media.getOriginalWidth()
+ && c.getWidth() <= type.getValue()
+ && (isSquare || Integer.compare(c.getWidth(), c.getHeight()) != 0)
+ )
+ .collect(Collectors.toList());
+ final MediaCandidate candidate = filteredCandidates.get(0);
if (candidate == null) return null;
return candidate.getUrl();
}
diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
index 1ff49767..fc568d9e 100755
--- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
+++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
@@ -16,6 +16,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT;
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS;
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY;
+import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_TAB_ORDER;
import static awais.instagrabber.utils.Constants.APP_LANGUAGE;
import static awais.instagrabber.utils.Constants.APP_THEME;
import static awais.instagrabber.utils.Constants.APP_UA;
@@ -33,16 +34,18 @@ import static awais.instagrabber.utils.Constants.DATE_TIME_SELECTION;
import static awais.instagrabber.utils.Constants.DEFAULT_TAB;
import static awais.instagrabber.utils.Constants.DEVICE_UUID;
import static awais.instagrabber.utils.Constants.DM_MARK_AS_SEEN;
+import static awais.instagrabber.utils.Constants.DOWNLOAD_PREPEND_USER_NAME;
import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER;
import static awais.instagrabber.utils.Constants.FLAG_SECURE;
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
+import static awais.instagrabber.utils.Constants.HIDE_MUTED_REELS;
+import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS;
import static awais.instagrabber.utils.Constants.MARK_AS_SEEN;
import static awais.instagrabber.utils.Constants.MUTED_VIDEOS;
import static awais.instagrabber.utils.Constants.PREF_DARK_THEME;
import static awais.instagrabber.utils.Constants.PREF_EMOJI_VARIANTS;
import static awais.instagrabber.utils.Constants.PREF_HASHTAG_POSTS_LAYOUT;
-import static awais.instagrabber.utils.Constants.KEYWORD_FILTERS;
import static awais.instagrabber.utils.Constants.PREF_LIGHT_THEME;
import static awais.instagrabber.utils.Constants.PREF_LIKED_POSTS_LAYOUT;
import static awais.instagrabber.utils.Constants.PREF_LOCATION_POSTS_LAYOUT;
@@ -155,13 +158,13 @@ public final class SettingsHelper {
CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME,
PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT,
PREF_LOCATION_POSTS_LAYOUT, PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT,
- STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT})
+ STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT, PREF_TAB_ORDER})
public @interface StringSettings {}
- @StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
+ @StringDef({DOWNLOAD_USER_FOLDER, DOWNLOAD_PREPEND_USER_NAME, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY,
CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH,
- FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY})
+ FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS})
public @interface BooleanSettings {}
@StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER})
diff --git a/app/src/main/java/awais/instagrabber/utils/TextUtils.java b/app/src/main/java/awais/instagrabber/utils/TextUtils.java
index 64eddd22..448c2a90 100644
--- a/app/src/main/java/awais/instagrabber/utils/TextUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/TextUtils.java
@@ -2,8 +2,6 @@ package awais.instagrabber.utils;
import android.content.Context;
import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.style.URLSpan;
@@ -11,17 +9,12 @@ import android.util.Patterns;
import androidx.annotation.NonNull;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import awais.instagrabber.customviews.CommentMentionClickSpan;
public final class TextUtils {
// extracted from String class
diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java b/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java
new file mode 100644
index 00000000..285fbb13
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java
@@ -0,0 +1,38 @@
+package awais.instagrabber.utils;
+
+import android.content.Context;
+import android.content.DialogInterface;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
+import awais.instagrabber.BuildConfig;
+import awais.instagrabber.R;
+
+import static awais.instagrabber.utils.Utils.settingsHelper;
+
+public final class UpdateCheckCommon {
+
+ public static boolean shouldShowUpdateDialog(final boolean force,
+ @NonNull final String version) {
+ final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION);
+ return force || (!BuildConfig.DEBUG && !skippedVersion.equals(version));
+ }
+
+ public static void showUpdateDialog(@NonNull final Context context,
+ @NonNull final String version,
+ @NonNull final DialogInterface.OnClickListener onDownloadClickListener) {
+ AppExecutors.getInstance().mainThread().execute(() -> {
+ new MaterialAlertDialogBuilder(context)
+ .setTitle(context.getString(R.string.update_available, version))
+ .setNeutralButton(R.string.skip_update, (dialog, which) -> {
+ settingsHelper.putString(Constants.SKIPPED_VERSION, version);
+ dialog.dismiss();
+ })
+ .setPositiveButton(R.string.action_download, onDownloadClickListener)
+ .setNegativeButton(R.string.cancel, null)
+ .show();
+ });
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java b/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java
deleted file mode 100755
index 3ea67ba1..00000000
--- a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package awais.instagrabber.utils;
-
-import android.os.AsyncTask;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import org.json.JSONObject;
-
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-import awais.instagrabber.BuildConfig;
-import awais.instagrabber.interfaces.FetchListener;
-
-public final class UpdateChecker extends AsyncTask {
- private final FetchListener fetchListener;
- private String version;
-
- public UpdateChecker(final FetchListener fetchListener) {
- this.fetchListener = fetchListener;
- }
-
- @NonNull
- @Override
- protected Boolean doInBackground(final Void... voids) {
- try {
- version = "";
-
- HttpURLConnection conn =
- (HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection();
- conn.setUseCaches(false);
- conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me");
- conn.connect();
-
- final int responseCode = conn.getResponseCode();
- if (responseCode == HttpURLConnection.HTTP_OK) {
- final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(conn));
- if (BuildConfig.VERSION_CODE < data.getInt("suggestedVersionCode")) {
- version = data.getJSONArray("packages").getJSONObject(0).getString("versionName");
- return true;
- }
- }
-
- conn.disconnect();
- } catch (final Exception e) {
- if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
- }
-
- return false;
- }
-
- @Override
- protected void onPostExecute(final Boolean result) {
- if (result != null && result && fetchListener != null)
- fetchListener.onResult("v"+version);
- }
-}
diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java
index 789133b8..b7c8e429 100644
--- a/app/src/main/java/awais/instagrabber/utils/Utils.java
+++ b/app/src/main/java/awais/instagrabber/utils/Utils.java
@@ -8,6 +8,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -44,6 +45,8 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
import com.google.common.io.Files;
import org.json.JSONObject;
@@ -53,18 +56,25 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import awais.instagrabber.R;
+import awais.instagrabber.fragments.settings.PreferenceKeys;
import awais.instagrabber.models.PostsLayoutPreferences;
+import awais.instagrabber.models.Tab;
import awais.instagrabber.models.enums.FavoriteType;
public final class Utils {
private static final String TAG = "Utils";
private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024;
- // public static LogCollector logCollector;
+ // public static LogCollector logCollector;
public static SettingsHelper settingsHelper;
public static boolean sessionVolumeFull = false;
public static final MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
@@ -76,6 +86,7 @@ public final class Utils {
private static int actionBarHeight;
public static Handler applicationHandler;
public static String cacheDir;
+ public static String tabOrderString;
private static int defaultStatusBarColor;
private static Object[] volumes;
@@ -375,6 +386,123 @@ public final class Utils {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
+ public static void moveItem(int sourceIndex, int targetIndex, List list) {
+ if (sourceIndex <= targetIndex) {
+ Collections.rotate(list.subList(sourceIndex, targetIndex + 1), -1);
+ } else {
+ Collections.rotate(list.subList(targetIndex, sourceIndex + 1), 1);
+ }
+ }
+
+ private static final List NON_REMOVABLE_NAV_ROOT_IDS = ImmutableList.of(R.id.profile_nav_graph, R.id.more_nav_graph);
+
+ @NonNull
+ public static Pair, List> getNavTabList(@NonNull final Context context) {
+ final Resources resources = context.getResources();
+ final String[] titleArray = resources.getStringArray(R.array.main_nav_titles);
+
+ TypedArray typedArray = resources.obtainTypedArray(R.array.main_nav_graphs);
+ int length = typedArray.length();
+ final String[] navGraphNames = new String[length];
+ final int[] navigationResIds = new int[length];
+ for (int i = 0; i < length; i++) {
+ final int resourceId = typedArray.getResourceId(i, 0);
+ if (resourceId == 0) continue;
+ navigationResIds[i] = resourceId;
+ navGraphNames[i] = resources.getResourceEntryName(resourceId);
+ }
+ typedArray.recycle();
+
+ typedArray = resources.obtainTypedArray(R.array.main_nav_graph_root_ids);
+ length = typedArray.length();
+ final int[] navRootIds = new int[length];
+ for (int i = 0; i < length; i++) {
+ final int resourceId = typedArray.getResourceId(i, 0);
+ if (resourceId == 0) continue;
+ navRootIds[i] = resourceId;
+ }
+ typedArray.recycle();
+
+ typedArray = resources.obtainTypedArray(R.array.main_nav_drawables);
+ length = typedArray.length();
+ final int[] iconIds = new int[length];
+ for (int i = 0; i < length; i++) {
+ final int resourceId = typedArray.getResourceId(i, 0);
+ if (resourceId == 0) continue;
+ iconIds[i] = resourceId;
+ }
+ typedArray.recycle();
+
+ typedArray = resources.obtainTypedArray(R.array.main_nav_start_dest_frag_ids);
+ length = typedArray.length();
+ final int[] startDestFragIds = new int[length];
+ for (int i = 0; i < length; i++) {
+ final int resourceId = typedArray.getResourceId(i, 0);
+ if (resourceId == 0) continue;
+ startDestFragIds[i] = resourceId;
+ }
+ typedArray.recycle();
+
+ final List currentOrderGraphNames = getCurrentOrderOfGraphNamesFromPref(navGraphNames);
+
+ if (titleArray.length != iconIds.length || titleArray.length != navGraphNames.length) {
+ throw new RuntimeException(String.format("Array lengths don't match!: titleArray%s, navGraphNames: %s, iconIds: %s",
+ Arrays.toString(titleArray), Arrays.toString(navGraphNames), Arrays.toString(iconIds)));
+ }
+ final List tabs = new ArrayList<>();
+ final List otherTabs = new ArrayList<>(); // Will contain tabs not in current list
+ for (int i = 0; i < length; i++) {
+ final String navGraphName = navGraphNames[i];
+ final int navRootId = navRootIds[i];
+ final Tab tab = new Tab(iconIds[i],
+ titleArray[i],
+ !NON_REMOVABLE_NAV_ROOT_IDS.contains(navRootId),
+ navGraphName,
+ navigationResIds[i],
+ navRootId,
+ startDestFragIds[i]);
+ if (!currentOrderGraphNames.contains(navGraphName)) {
+ otherTabs.add(tab);
+ continue;
+ }
+ tabs.add(tab);
+ }
+ Collections.sort(tabs, Ordering.explicit(currentOrderGraphNames).onResultOf(tab -> {
+ if (tab == null) return null;
+ return tab.getGraphName();
+ }));
+ return new Pair<>(tabs, otherTabs);
+ }
+
+ @NonNull
+ private static List getCurrentOrderOfGraphNamesFromPref(@NonNull final String[] navGraphNames) {
+ tabOrderString = settingsHelper.getString(PreferenceKeys.PREF_TAB_ORDER);
+ final List navGraphNameList = Arrays.asList(navGraphNames);
+ if (TextUtils.isEmpty(tabOrderString)) {
+ // Use top 5 entries for default list
+ final List top5navGraphNames = navGraphNameList.subList(0, 5);
+ final String newOrderString = android.text.TextUtils.join(",", top5navGraphNames);
+ Utils.settingsHelper.putString(PreferenceKeys.PREF_TAB_ORDER, newOrderString);
+ tabOrderString = newOrderString;
+ return top5navGraphNames;
+ }
+ // Make sure that the list from preference does not contain any invalid values
+ final List orderGraphNames = Arrays.stream(tabOrderString.split(","))
+ .filter(s -> !TextUtils.isEmpty(s))
+ .filter(navGraphNameList::contains)
+ .collect(Collectors.toList());
+ if (orderGraphNames.isEmpty()) {
+ // Use top 5 entries for default list
+ return navGraphNameList.subList(0, 5);
+ }
+ return orderGraphNames;
+ }
+
+ public static boolean isNavRootInCurrentTabs(final String navRootString) {
+ if (navRootString == null || tabOrderString == null) return false;
+ return tabOrderString.contains(navRootString);
+ }
+
public static void scanDocumentFile(@NonNull final Context context,
@NonNull final DocumentFile documentFile,
@NonNull final OnScanCompletedListener callback) {
diff --git a/app/src/main/java/awais/instagrabber/webservices/BaseService.java b/app/src/main/java/awais/instagrabber/webservices/BaseService.java
index e30aa992..a6cdf060 100644
--- a/app/src/main/java/awais/instagrabber/webservices/BaseService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/BaseService.java
@@ -1,50 +1,8 @@
package awais.instagrabber.webservices;
-import com.google.gson.FieldNamingPolicy;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-import java.io.File;
-
-import awais.instagrabber.BuildConfig;
-import awais.instagrabber.repositories.responses.Caption;
-import awais.instagrabber.utils.Utils;
-import okhttp3.Cache;
-import okhttp3.OkHttpClient;
-import retrofit2.Retrofit;
-import retrofit2.converter.gson.GsonConverterFactory;
-import retrofit2.converter.scalars.ScalarsConverterFactory;
-
public abstract class BaseService {
private static final String TAG = "BaseService";
- private Retrofit.Builder builder;
- private final int cacheSize = 10 * 1024 * 1024; // 10 MB
- private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize);
-
- Retrofit.Builder getRetrofitBuilder() {
- if (builder == null) {
- final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
- .addInterceptor(new AddCookiesInterceptor())
- .followRedirects(false)
- .followSslRedirects(false)
- .cache(cache);
- if (BuildConfig.DEBUG) {
- // clientBuilder.addInterceptor(new LoggingInterceptor());
- }
- final Gson gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer())
- .setLenient()
- .create();
- builder = new Retrofit.Builder()
- .addConverterFactory(ScalarsConverterFactory.create())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .client(clientBuilder.build());
- }
- return builder;
- }
-
// protected String userBreadcrumb(final int size) {
// final long term = (random(2, 4) * 1000) + size + (random(15, 21) * 1000);
// final float div = (float) size / random(2, 4);
diff --git a/app/src/main/java/awais/instagrabber/webservices/CollectionService.java b/app/src/main/java/awais/instagrabber/webservices/CollectionService.java
index faafb6d0..e0c50dc2 100644
--- a/app/src/main/java/awais/instagrabber/webservices/CollectionService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/CollectionService.java
@@ -1,5 +1,7 @@
package awais.instagrabber.webservices;
+import android.text.TextUtils;
+
import androidx.annotation.NonNull;
import java.util.HashMap;
@@ -14,7 +16,6 @@ import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class CollectionService extends BaseService {
private static final String TAG = "ProfileService";
@@ -31,10 +32,9 @@ public class CollectionService extends BaseService {
this.deviceUuid = deviceUuid;
this.csrfToken = csrfToken;
this.userId = userId;
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(CollectionRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(CollectionRepository.class);
}
public String getCsrfToken() {
@@ -66,10 +66,10 @@ public class CollectionService extends BaseService {
form.put("module_name", "feed_saved_add_to_collection");
final List ids;
ids = posts.stream()
- .map(Media::getPk)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
- form.put("added_media_ids", "[" + String.join(",", ids) + "]");
+ .map(Media::getPk)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ form.put("added_media_ids", "[" + TextUtils.join(",", ids) + "]");
changeCollection(collectionId, "edit", form, callback);
}
diff --git a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java
index 5e4afea5..0688c761 100644
--- a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java
@@ -41,7 +41,6 @@ import awais.instagrabber.repositories.responses.giphy.GiphyGif;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import retrofit2.Call;
-import retrofit2.Retrofit;
public class DirectMessagesService extends BaseService {
private static final String TAG = "DiscoverService";
@@ -59,10 +58,9 @@ public class DirectMessagesService extends BaseService {
this.csrfToken = csrfToken;
this.userId = userId;
this.deviceUuid = deviceUuid;
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(DirectMessagesRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(DirectMessagesRepository.class);
}
public String getCsrfToken() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java b/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java
index 294a6a7d..880ae526 100644
--- a/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java
@@ -12,7 +12,6 @@ import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class DiscoverService extends BaseService {
@@ -23,10 +22,9 @@ public class DiscoverService extends BaseService {
private static DiscoverService instance;
private DiscoverService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(DiscoverRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(DiscoverRepository.class);
}
public static DiscoverService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/FeedService.java b/app/src/main/java/awais/instagrabber/webservices/FeedService.java
index 3496f8b7..3ed9e7b6 100644
--- a/app/src/main/java/awais/instagrabber/webservices/FeedService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/FeedService.java
@@ -12,17 +12,16 @@ import java.util.Map;
import java.util.UUID;
import awais.instagrabber.repositories.FeedRepository;
+import awais.instagrabber.repositories.responses.Media;
+import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator;
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroup;
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroupSet;
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
-import awais.instagrabber.repositories.responses.Media;
-import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class FeedService extends BaseService {
private static final String TAG = "FeedService";
@@ -32,10 +31,9 @@ public class FeedService extends BaseService {
private static FeedService instance;
private FeedService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(FeedRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(FeedRepository.class);
}
public static FeedService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java
index 7c5da8cf..ced49305 100644
--- a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java
@@ -25,7 +25,6 @@ import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class FriendshipService extends BaseService {
private static final String TAG = "FriendshipService";
@@ -42,10 +41,9 @@ public class FriendshipService extends BaseService {
this.deviceUuid = deviceUuid;
this.csrfToken = csrfToken;
this.userId = userId;
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(FriendshipRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(FriendshipRepository.class);
}
public String getCsrfToken() {
@@ -168,8 +166,8 @@ public class FriendshipService extends BaseService {
form.put("_uuid", deviceUuid);
form.put(story ? "target_reel_author_id" : "target_posts_author_id", String.valueOf(targetUserId));
final Call request = repository.changeMute(unmute ?
- "unmute_posts_or_story_from_follow" :
- "mute_posts_or_story_from_follow",
+ "unmute_posts_or_story_from_follow" :
+ "mute_posts_or_story_from_follow",
form);
request.enqueue(new Callback() {
@Override
@@ -198,8 +196,8 @@ public class FriendshipService extends BaseService {
if (maxId != null) queryMap.put("max_id", maxId);
final Call request = repository.getList(
targetUserId,
- follower ? "followers" : "following",
- queryMap);
+ follower ? "followers" : "following",
+ queryMap);
request.enqueue(new Callback() {
@Override
public void onResponse(@NonNull final Call call, @NonNull final Response response) {
diff --git a/app/src/main/java/awais/instagrabber/webservices/GifService.java b/app/src/main/java/awais/instagrabber/webservices/GifService.java
index 6485efd1..e783f689 100644
--- a/app/src/main/java/awais/instagrabber/webservices/GifService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/GifService.java
@@ -3,7 +3,6 @@ package awais.instagrabber.webservices;
import awais.instagrabber.repositories.GifRepository;
import awais.instagrabber.repositories.responses.giphy.GiphyGifResponse;
import retrofit2.Call;
-import retrofit2.Retrofit;
public class GifService extends BaseService {
@@ -12,10 +11,9 @@ public class GifService extends BaseService {
private static GifService instance;
private GifService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(GifRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(GifRepository.class);
}
public static GifService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java
index b4ca9293..6246cd67 100644
--- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java
@@ -29,7 +29,6 @@ import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class GraphQLService extends BaseService {
private static final String TAG = "GraphQLService";
@@ -40,10 +39,9 @@ public class GraphQLService extends BaseService {
private static GraphQLService instance;
private GraphQLService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://www.instagram.com")
- .build();
- repository = retrofit.create(GraphQLRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofitWeb()
+ .create(GraphQLRepository.class);
}
public static GraphQLService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/LocationService.java b/app/src/main/java/awais/instagrabber/webservices/LocationService.java
index 7b3648f4..aca6ef47 100644
--- a/app/src/main/java/awais/instagrabber/webservices/LocationService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/LocationService.java
@@ -13,7 +13,6 @@ import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class LocationService extends BaseService {
private static final String TAG = "LocationService";
@@ -23,10 +22,9 @@ public class LocationService extends BaseService {
private static LocationService instance;
private LocationService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(LocationRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(LocationRepository.class);
}
public static LocationService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/MediaService.java b/app/src/main/java/awais/instagrabber/webservices/MediaService.java
index e1990e87..d820b954 100644
--- a/app/src/main/java/awais/instagrabber/webservices/MediaService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/MediaService.java
@@ -31,7 +31,6 @@ import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class MediaService extends BaseService {
private static final String TAG = "MediaService";
@@ -51,10 +50,9 @@ public class MediaService extends BaseService {
this.deviceUuid = deviceUuid;
this.csrfToken = csrfToken;
this.userId = userId;
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(MediaRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(MediaRepository.class);
}
public String getCsrfToken() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java
index 5eec9e8c..580e2c04 100644
--- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java
@@ -12,17 +12,16 @@ import java.util.stream.Collectors;
import awais.instagrabber.repositories.NewsRepository;
import awais.instagrabber.repositories.responses.AymlResponse;
import awais.instagrabber.repositories.responses.AymlUser;
-import awais.instagrabber.repositories.responses.notification.NotificationCounts;
-import awais.instagrabber.repositories.responses.UserSearchResponse;
import awais.instagrabber.repositories.responses.NewsInboxResponse;
+import awais.instagrabber.repositories.responses.User;
+import awais.instagrabber.repositories.responses.UserSearchResponse;
import awais.instagrabber.repositories.responses.notification.Notification;
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
-import awais.instagrabber.repositories.responses.User;
+import awais.instagrabber.repositories.responses.notification.NotificationCounts;
import awais.instagrabber.utils.Constants;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class NewsService extends BaseService {
private static final String TAG = "NewsService";
@@ -32,10 +31,9 @@ public class NewsService extends BaseService {
private static NewsService instance;
private NewsService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(NewsRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(NewsRepository.class);
}
public static NewsService getInstance() {
@@ -56,9 +54,11 @@ public class NewsService extends BaseService {
callback.onSuccess(null);
return;
}
- final List result = new ArrayList<>();
- result.addAll(body.getNewStories());
- result.addAll(body.getOldStories());
+ final List result = new ArrayList();
+ final List newStories = body.getNewStories();
+ if (newStories != null) result.addAll(newStories);
+ final List oldStories = body.getOldStories();
+ if (oldStories != null) result.addAll(oldStories);
callback.onSuccess(result);
}
@@ -120,7 +120,8 @@ public class NewsService extends BaseService {
aymlUsers.addAll(oldSuggestions);
}
- final List newsItems = aymlUsers.stream()
+ final List newsItems = aymlUsers
+ .stream()
.map(i -> {
final User u = i.getUser();
return new Notification(
@@ -162,7 +163,9 @@ public class NewsService extends BaseService {
return;
}
- final List newsItems = body.getUsers().stream()
+ final List newsItems = body
+ .getUsers()
+ .stream()
.map(u -> {
return new Notification(
new NotificationArgs(
diff --git a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java
index 65f787a6..cc8199fd 100644
--- a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java
@@ -23,7 +23,6 @@ import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class ProfileService extends BaseService {
private static final String TAG = "ProfileService";
@@ -33,10 +32,9 @@ public class ProfileService extends BaseService {
private static ProfileService instance;
private ProfileService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(ProfileRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(ProfileRepository.class);
}
public static ProfileService getInstance() {
@@ -104,9 +102,9 @@ public class ProfileService extends BaseService {
posts = Collections.emptyList();
} else {
posts = items.stream()
- .map(WrappedMedia::getMedia)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
+ .map(WrappedMedia::getMedia)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
}
callback.onSuccess(new PostsFetchResponse(
posts,
diff --git a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java
new file mode 100644
index 00000000..5062e5c7
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java
@@ -0,0 +1,112 @@
+package awais.instagrabber.webservices;
+
+import androidx.annotation.NonNull;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.io.File;
+
+import awais.instagrabber.BuildConfig;
+import awais.instagrabber.activities.MainActivity;
+import awais.instagrabber.repositories.responses.Caption;
+import awais.instagrabber.utils.Utils;
+import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor;
+import awais.instagrabber.webservices.interceptors.IgErrorsInterceptor;
+import okhttp3.Cache;
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+import retrofit2.converter.scalars.ScalarsConverterFactory;
+
+public final class RetrofitFactory {
+ private static final Object LOCK = new Object();
+
+ private static RetrofitFactory instance;
+
+ private final int cacheSize = 10 * 1024 * 1024; // 10 MB
+ private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize);
+
+ private IgErrorsInterceptor igErrorsInterceptor;
+ private MainActivity mainActivity;
+ private Retrofit.Builder builder;
+ private Retrofit retrofit;
+ private Retrofit retrofitWeb;
+
+ public static void setup(@NonNull final MainActivity mainActivity) {
+ if (instance == null) {
+ synchronized (LOCK) {
+ if (instance == null) {
+ instance = new RetrofitFactory(mainActivity);
+ }
+ }
+ }
+ }
+
+ public static RetrofitFactory getInstance() {
+ if (instance == null) {
+ throw new RuntimeException("Setup not done!");
+ }
+ return instance;
+ }
+
+ private RetrofitFactory(@NonNull final MainActivity mainActivity) {
+ this.mainActivity = mainActivity;
+ }
+
+ private Retrofit.Builder getRetrofitBuilder() {
+ if (builder == null) {
+ igErrorsInterceptor = new IgErrorsInterceptor(mainActivity);
+ final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
+ .followRedirects(false)
+ .followSslRedirects(false)
+ .cache(cache);
+ if (BuildConfig.DEBUG) {
+ // clientBuilder.addInterceptor(new LoggingInterceptor());
+ }
+ clientBuilder.addInterceptor(new AddCookiesInterceptor())
+ .addInterceptor(igErrorsInterceptor);
+ final Gson gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer())
+ .setLenient()
+ .create();
+ builder = new Retrofit.Builder()
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .client(clientBuilder.build());
+ }
+ return builder;
+ }
+
+ public Retrofit getRetrofit() {
+ if (retrofit == null) {
+ retrofit = getRetrofitBuilder()
+ .baseUrl("https://i.instagram.com")
+ .build();
+ }
+ return retrofit;
+ }
+
+ public Retrofit getRetrofitWeb() {
+ if (retrofitWeb == null) {
+ retrofitWeb = getRetrofitBuilder()
+ .baseUrl("https://www.instagram.com")
+ .build();
+ }
+ return retrofitWeb;
+ }
+
+ public void destroy() {
+ if (igErrorsInterceptor != null) {
+ igErrorsInterceptor.destroy();
+ }
+ igErrorsInterceptor = null;
+ mainActivity = null;
+ retrofit = null;
+ retrofitWeb = null;
+ builder = null;
+ instance = null;
+ }
+}
diff --git a/app/src/main/java/awais/instagrabber/webservices/SearchService.java b/app/src/main/java/awais/instagrabber/webservices/SearchService.java
index 39b5bd65..4144f85d 100644
--- a/app/src/main/java/awais/instagrabber/webservices/SearchService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/SearchService.java
@@ -1,16 +1,10 @@
package awais.instagrabber.webservices;
-import androidx.annotation.NonNull;
-
import com.google.common.collect.ImmutableMap;
import awais.instagrabber.repositories.SearchRepository;
import awais.instagrabber.repositories.responses.search.SearchResponse;
-import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-import retrofit2.Retrofit;
public class SearchService extends BaseService {
private static final String TAG = "LocationService";
@@ -20,10 +14,9 @@ public class SearchService extends BaseService {
private static SearchService instance;
private SearchService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://www.instagram.com")
- .build();
- repository = retrofit.create(SearchRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofitWeb()
+ .create(SearchRepository.class);
}
public static SearchService getInstance() {
@@ -43,8 +36,8 @@ public class SearchService extends BaseService {
builder.put("context", context);
builder.put("count", "50");
return repository.search(isLoggedIn
- ? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/"
- : "https://www.instagram.com/web/search/topsearch/",
- builder.build());
+ ? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/"
+ : "https://www.instagram.com/web/search/topsearch/",
+ builder.build());
}
}
diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java
index 9b47839b..09a3a6b7 100644
--- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java
@@ -32,7 +32,6 @@ import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class StoriesService extends BaseService {
private static final String TAG = "StoriesService";
@@ -50,10 +49,9 @@ public class StoriesService extends BaseService {
this.csrfToken = csrfToken;
this.userId = userId;
this.deviceUuid = deviceUuid;
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(StoriesRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(StoriesRepository.class);
}
public String getCsrfToken() {
@@ -137,7 +135,7 @@ public class StoriesService extends BaseService {
final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray");
for (int i = 0; i < feedStoriesReel.length(); ++i) {
final JSONObject node = feedStoriesReel.getJSONObject(i);
- if (node.optBoolean("hide_from_feed_unit")) continue;
+ if (node.optBoolean("hide_from_feed_unit") && Utils.settingsHelper.getBoolean(Constants.HIDE_MUTED_REELS)) continue;
final JSONObject userJson = node.getJSONObject(node.has("user") ? "user" : "owner");
try {
final User user = new User(userJson.getLong("pk"),
@@ -179,17 +177,22 @@ public class StoriesService extends BaseService {
null,
null
);
- final String id = node.getString("id");
final long timestamp = node.getLong("latest_reel_media");
- final int mediaCount = node.getInt("media_count");
final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == timestamp;
final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").optJSONObject(0) : null;
- final boolean isBestie = node.optBoolean("has_besties_media", false);
StoryModel firstStoryModel = null;
if (itemJson != null) {
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null);
}
- feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount, false, isBestie));
+ feedStoryModels.add(new FeedStoryModel(
+ node.getString("id"),
+ user,
+ fullyRead,
+ timestamp,
+ firstStoryModel,
+ node.getInt("media_count"),
+ false,
+ node.optBoolean("has_besties_media")));
}
catch (Exception e) {} // to cover promotional reels with non-long user pk's
}
@@ -242,13 +245,16 @@ public class StoriesService extends BaseService {
null,
null
);
- final String id = node.getString("id");
- final long timestamp = node.getLong("published_time");
- // final JSONObject itemJson = node.has("items") ? node.getJSONArray("items").getJSONObject(0) : null;
- final StoryModel firstStoryModel = ResponseBodyUtils.parseBroadcastItem(node);
- // if (itemJson != null) {
- // }
- feedStoryModels.add(new FeedStoryModel(id, user, false, timestamp, firstStoryModel, 1, true, false));
+ feedStoryModels.add(new FeedStoryModel(
+ node.getString("id"),
+ user,
+ false,
+ node.getLong("published_time"),
+ ResponseBodyUtils.parseBroadcastItem(node),
+ 1,
+ true,
+ false
+ ));
}
callback.onSuccess(sort(feedStoryModels));
} catch (JSONException e) {
diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java
index 615d72af..276f0dc7 100644
--- a/app/src/main/java/awais/instagrabber/webservices/TagsService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java
@@ -21,7 +21,6 @@ import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class TagsService extends BaseService {
@@ -32,10 +31,9 @@ public class TagsService extends BaseService {
private final TagsRepository repository;
private TagsService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com/")
- .build();
- repository = retrofit.create(TagsRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(TagsRepository.class);
}
public static TagsService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/UserService.java b/app/src/main/java/awais/instagrabber/webservices/UserService.java
index 52bb064d..1266662f 100644
--- a/app/src/main/java/awais/instagrabber/webservices/UserService.java
+++ b/app/src/main/java/awais/instagrabber/webservices/UserService.java
@@ -12,7 +12,6 @@ import awais.instagrabber.repositories.responses.WrappedUser;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-import retrofit2.Retrofit;
public class UserService extends BaseService {
private static final String TAG = UserService.class.getSimpleName();
@@ -22,10 +21,9 @@ public class UserService extends BaseService {
private static UserService instance;
private UserService() {
- final Retrofit retrofit = getRetrofitBuilder()
- .baseUrl("https://i.instagram.com")
- .build();
- repository = retrofit.create(UserRepository.class);
+ repository = RetrofitFactory.getInstance()
+ .getRetrofit()
+ .create(UserRepository.class);
}
public static UserService getInstance() {
diff --git a/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java
similarity index 96%
rename from app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java
rename to app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java
index 3b5f709f..610b5f89 100644
--- a/app/src/main/java/awais/instagrabber/webservices/AddCookiesInterceptor.java
+++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java
@@ -1,4 +1,4 @@
-package awais.instagrabber.webservices;
+package awais.instagrabber.webservices.interceptors;
import androidx.annotation.NonNull;
diff --git a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
new file mode 100644
index 00000000..e27eeae2
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
@@ -0,0 +1,136 @@
+package awais.instagrabber.webservices.interceptors;
+
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+import com.google.android.material.snackbar.Snackbar;
+
+import org.json.JSONObject;
+
+import java.io.IOException;
+
+import awais.instagrabber.R;
+import awais.instagrabber.activities.MainActivity;
+import awais.instagrabber.dialogs.ConfirmDialogFragment;
+import awais.instagrabber.utils.Constants;
+import awais.instagrabber.utils.TextUtils;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+public class IgErrorsInterceptor implements Interceptor {
+ private static final String TAG = IgErrorsInterceptor.class.getSimpleName();
+
+ private MainActivity mainActivity;
+
+ public IgErrorsInterceptor(@NonNull final MainActivity mainActivity) {
+ this.mainActivity = mainActivity;
+ }
+
+ @NonNull
+ @Override
+ public Response intercept(@NonNull final Chain chain) throws IOException {
+ final Request request = chain.request();
+ final Response response = chain.proceed(request);
+ if (response.isSuccessful()) {
+ return response;
+ }
+ checkError(response);
+ return response;
+ }
+
+ private void checkError(@NonNull final Response response) {
+ final int errorCode = response.code();
+ switch (errorCode) {
+ case 429: // "429 Too Many Requests"
+ // ('Throttled by Instagram because of too many API requests.');
+ showErrorDialog(R.string.throttle_error);
+ return;
+ case 431: // "431 Request Header Fields Too Large"
+ // show dialog?
+ Log.e(TAG, "Network error: " + getMessage(errorCode, "The request start-line and/or headers are too large to process."));
+ return;
+ case 404:
+ showErrorDialog(R.string.not_found);
+ return;
+ case 302: // redirect
+ final String location = response.header("location");
+ if (location.equals("https://www.instagram.com/accounts/login/")) {
+ // rate limited
+ showErrorDialog(R.string.rate_limit);
+ }
+ return;
+ }
+ final ResponseBody body = response.body();
+ if (body == null) return;
+ try {
+ final String bodyString = body.string();
+ final JSONObject jsonObject = new JSONObject(bodyString);
+ String message = jsonObject.optString("message", null);
+ if (!TextUtils.isEmpty(message)) {
+ message = message.toLowerCase();
+ switch (message) {
+ case "user_has_logged_out":
+ showErrorDialog(R.string.account_logged_out);
+ return;
+ case "login_required":
+ showErrorDialog(R.string.login_required);
+ return;
+ case "execution failure":
+ showSnackbar(message);
+ return;
+ case "not authorized to view user": // Do we handle this in profile view fragment?
+ case "challenge_required": // Since we make users login using browser, we should not be getting this error in api requests
+ default:
+ showSnackbar(message);
+ Log.e(TAG, "checkError: " + bodyString);
+ return;
+ }
+ }
+ final String errorType = jsonObject.optString("error_type", null);
+ if (TextUtils.isEmpty(errorType)) return;
+ if (errorType.equals("sentry_block")) {
+ showErrorDialog(R.string.sentry_block);
+ return;
+ }
+ if (errorType.equals("inactive user")) {
+ showErrorDialog(R.string.inactive_user);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "checkError: ", e);
+ }
+ }
+
+ private void showSnackbar(final String message) {
+ final View view = mainActivity.getRootView();
+ if (view == null) return;
+ Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
+ }
+
+ @NonNull
+ private String getMessage(final int errorCode, final String message) {
+ return String.format("code: %s, internalMessage: %s", errorCode, message);
+ }
+
+ private void showErrorDialog(@StringRes final int messageResId) {
+ if (mainActivity == null) return;
+ if (messageResId == 0) return;
+ final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
+ Constants.GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE,
+ R.string.error,
+ messageResId,
+ R.string.ok,
+ 0,
+ 0
+ );
+ dialogFragment.show(mainActivity.getSupportFragmentManager(), "network_error_dialog");
+ }
+
+ public void destroy() {
+ mainActivity = null;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/webservices/LoggingInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java
similarity index 96%
rename from app/src/main/java/awais/instagrabber/webservices/LoggingInterceptor.java
rename to app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java
index c9358a72..e7bedd3b 100644
--- a/app/src/main/java/awais/instagrabber/webservices/LoggingInterceptor.java
+++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java
@@ -1,4 +1,4 @@
-package awais.instagrabber.webservices;
+package awais.instagrabber.webservices.interceptors;
import android.util.Log;
diff --git a/app/src/main/res/drawable/ic_discover.xml b/app/src/main/res/drawable/ic_discover.xml
deleted file mode 100755
index 7a1ab400..00000000
--- a/app/src/main/res/drawable/ic_discover.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_explore_24.xml b/app/src/main/res/drawable/ic_explore_24.xml
new file mode 100644
index 00000000..0ac168a2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_explore_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_feed.xml b/app/src/main/res/drawable/ic_feed.xml
deleted file mode 100755
index c163a23d..00000000
--- a/app/src/main/res/drawable/ic_feed.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_home_24.xml b/app/src/main/res/drawable/ic_home_24.xml
new file mode 100644
index 00000000..3a4c7dac
--- /dev/null
+++ b/app/src/main/res/drawable/ic_home_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_message_24.xml b/app/src/main/res/drawable/ic_message_24.xml
new file mode 100644
index 00000000..a7adce5a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_message_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_person_24.xml b/app/src/main/res/drawable/ic_person_24.xml
new file mode 100644
index 00000000..6bdced2d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_person_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_round_add_circle_24.xml b/app/src/main/res/drawable/ic_round_add_circle_24.xml
new file mode 100644
index 00000000..1906afe5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_round_add_circle_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_round_drag_handle_24.xml b/app/src/main/res/drawable/ic_round_drag_handle_24.xml
new file mode 100644
index 00000000..3f4f79ca
--- /dev/null
+++ b/app/src/main/res/drawable/ic_round_drag_handle_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_round_remove_circle_24.xml b/app/src/main/res/drawable/ic_round_remove_circle_24.xml
new file mode 100644
index 00000000..68d85995
--- /dev/null
+++ b/app/src/main/res/drawable/ic_round_remove_circle_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 866770aa..97bcb0bb 100755
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -47,7 +47,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
- app:labelVisibilityMode="labeled"
- app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
- app:menu="@menu/main_bottom_navigation_menu" />
+ app:labelVisibilityMode="auto"
+ app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_tab_order_pref.xml b/app/src/main/res/layout/item_tab_order_pref.xml
new file mode 100644
index 00000000..8c2045c9
--- /dev/null
+++ b/app/src/main/res/layout/item_tab_order_pref.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml
index 035a04b0..ea4df164 100644
--- a/app/src/main/res/layout/layout_profile_details.xml
+++ b/app/src/main/res/layout/layout_profile_details.xml
@@ -326,6 +326,7 @@
diff --git a/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml b/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml
deleted file mode 100644
index e93193a0..00000000
--- a/app/src/main/res/menu/logged_out_bottom_navigation_menu.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/main_bottom_navigation_menu.xml b/app/src/main/res/menu/main_bottom_navigation_menu.xml
deleted file mode 100644
index 6e981c7c..00000000
--- a/app/src/main/res/menu/main_bottom_navigation_menu.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/story_menu.xml b/app/src/main/res/menu/story_menu.xml
index a7293f91..8169fd62 100644
--- a/app/src/main/res/menu/story_menu.xml
+++ b/app/src/main/res/menu/story_menu.xml
@@ -5,13 +5,18 @@
+ android:title="@string/reply_story"
+ android:titleCondensed="@string/reply_story"
+ app:showAsAction="never" />
+
+ app:showAsAction="never" />
\ No newline at end of file
diff --git a/app/src/main/res/navigation/favorites_nav_graph.xml b/app/src/main/res/navigation/favorites_nav_graph.xml
new file mode 100644
index 00000000..1a288bf1
--- /dev/null
+++ b/app/src/main/res/navigation/favorites_nav_graph.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/more_nav_graph.xml b/app/src/main/res/navigation/more_nav_graph.xml
index 84ae9423..0274390e 100644
--- a/app/src/main/res/navigation/more_nav_graph.xml
+++ b/app/src/main/res/navigation/more_nav_graph.xml
@@ -11,6 +11,7 @@
+
-
+
+
+
-
-
-
+ app:nullable="true" />
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/profile_nav_graph.xml b/app/src/main/res/navigation/profile_nav_graph.xml
index 8ef07dca..8bff84b8 100644
--- a/app/src/main/res/navigation/profile_nav_graph.xml
+++ b/app/src/main/res/navigation/profile_nav_graph.xml
@@ -71,11 +71,9 @@
app:argType="long" />
-
-
+ app:destination="@id/notificationsViewer">
+
+
+
+
+
Cerca actualitzacions a l\'inici
Block screenshots & app preview
Descarrega les publicacions a carpetes de nom d\'usuari
+ Prepend Username to Filename
Marca les històries com a vistes després de visualitzar-es
L\'autor de la història sabrà que l\'has vista
Marca els missatges com a vists després de visualitzar-los
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 0bb9e0ac..c5bc0f11 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -23,6 +23,7 @@
Zkontrolovat aktualizace při spuštění
Block screenshots & app preview
Stáhnout příspěvky do složek s uživatelským jménem
+ Prepend Username to Filename
Označit příběhy po zhlédnutí jako zobrazené
Autor příběhu bude vědět, že jsi si ho zobrazili
Označovat přímou zprávu po zobrazení jako zobrazenou
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 1f541fcd..e023c6b9 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -23,6 +23,7 @@
Beim Start auf Aktualisierungen prüfen
Block screenshots & app preview
Beiträge in Benutzernamen-Ordner herunterladen
+ Prepend Username to Filename
Stories nach dem Ansehen als gesehen markieren
Die Person wird wissen, dass du dir die Story angesehen hast
Direktnachrichten nach dem Ansehen als gesehen markieren
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index f9817a0a..b8c7df56 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -23,6 +23,7 @@
Έλεγχος για ενημερώσεις στο ξεκίνημα
Block screenshots & app preview
Λήψη δημοσίευσης στους φακέλους με ονόματα χρηστών
+ Prepend Username to Filename
Επισήμανση ιστοριών ως προβληθέντων μετά την προβολή
Ο συντάκτης της ιστορίας θα ξέρει ότι την προβάλατε
Σήμανση ΠΜ ως αναγνωσμένου μετά την προβολή
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index f392ec86..9ee7d1d0 100755
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -23,6 +23,7 @@
Buscar actualizaciones al inicio
Bloquea capturas de pantalla & vista previa de aplicaciones
Usar subcarpetas con el nombre de usuario
+ Prepend Username to Filename
Marcar historias como vistas después de verlas
El autor de la historia sabrá que lo has visto
Marcar Mensaje Directo como visto después de verlo
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index dd0321e2..8f217f17 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -23,6 +23,7 @@
Bilatu eguneratzeak abioan
Block screenshots & app preview
Deskargatu bidalketak erabiltzaile-izena duten karpetetara
+ Prepend Username to Filename
Markatu istorioak ikusita gisa ikusi ondoren
Istorioaren egileak ikusi duzula jakingo du
Markatu MZ ikusita gisa ikusi ondoren
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index c6da89cf..75371835 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -23,6 +23,7 @@
بررسی بروزرسانی هنگام آغاز برنامه
Block screenshots & app preview
بارگیری پست ها در پوشه های به نام کاربر
+ Prepend Username to Filename
نشان کرد استوری ها به عنوان دیده شده بعد از دیدن
نویسنده استوری می داند که شما آن را دیده اید
نشان کردن پیام خصوصی بعنوان دیده شده بعد از دیدن
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 15f8a5cc..d2fd93dd 100755
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -23,6 +23,7 @@
Rechercher les mises à jours au démarrage
Bloquer les captures d\'écran & l\'aperçu de l\'application
Télécharger les messages dans les dossiers des noms d\'utilisateurs
+ Prepend Username to Filename
Marquer les stories comme vues après consultation
L\'auteur de la story saura que vous l\'avez vue
Marquer les messages privés comme vus après consultation
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index bc923135..623bc2ce 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -23,6 +23,7 @@
खुलने पर अपडेट के लिए जाँच करें
Block screenshots & app preview
पोस्ट को ब्यबहारकारी के नाम पर किये फोल्डरस में रखें
+ Prepend Username to Filename
स्टोरि को दिखने के बाद \"दिखा गया\" दिखादें
सटोरि के लेखक जानेगा कि तुम देखे हो इसको
तुम देखने के बाद सीधा संदेश को \"दिखागया\" लिखा जाएगा
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index 462c1a2e..6801759b 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -23,6 +23,7 @@
Cek pembaruan saat memulai
Block screenshots & app preview
Unduh kiriman ke folder nama pengguna
+ Prepend Username to Filename
Tandai cerita dibaca setelah melihat
Pembuat cerita akan tahu Anda melihatnya
Tandai DM dibaca setelah melihat
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index d8202389..eefead25 100755
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -23,6 +23,7 @@
Verifica per aggiornamenti all\'avvio
Blocca screenshot & anteprima app
Scarica i post nelle cartelle del nome utente
+ Prepend Username to Filename
Segna le storie come viste dopo la visualizzazione
L\'autore della storia saprà che l\'hai visualizzata
Segna il DM come visto dopo la visualizzazione
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 5a11dc06..178f3726 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -23,6 +23,7 @@
起動時にアップデートを確認
Block screenshots & app preview
ユーザ名のフォルダに投稿をダウンロード
+ Prepend Username to Filename
ストーリーズを表示後に既読にする
ストーリーの作成者は、あなたが閲覧したことを知ることができます。
DMを表示後に既読にする
diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml
index 80d8b915..85c0390c 100644
--- a/app/src/main/res/values-kn/strings.xml
+++ b/app/src/main/res/values-kn/strings.xml
@@ -23,6 +23,7 @@
Check for updates at startup
Block screenshots & app preview
Download posts to username folders
+ Prepend Username to Filename
Mark stories as seen after viewing
Story author will know you viewed it
Mark DM as seen after viewing
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index abb89551..118e07f4 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -23,6 +23,7 @@
Провери за ажурирање
Block screenshots & app preview
Превземи објави во папката со кориснички имиња
+ Prepend Username to Filename
Означи ги приказните како видени
Авторот на приказната ќе знае дека сте ја погледнале приказната
Означи порака како видена
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index fda4c863..b904bed6 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -23,6 +23,7 @@
Controleer op updates bij het opstarten
Block screenshots & app preview
Download berichten naar gebruikersnaam mappen
+ Prepend Username to Filename
Markeer verhalen als gelezen na bekijken
Verhaalmaker zal het weten als je het bekeken hebt
Markeer privéberichten als gelezen na bekijken
diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml
index ce4427ec..12b95d7b 100644
--- a/app/src/main/res/values-or/strings.xml
+++ b/app/src/main/res/values-or/strings.xml
@@ -23,6 +23,7 @@
ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ
Block screenshots & app preview
ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ
+ Prepend Username to Filename
କାହାଣୀଗୁଡିକ ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |
କାହାଣୀ ପ୍ରେରକ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ
ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 93fb3ff8..2c449634 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -23,6 +23,7 @@
Sprawdź aktualizacje przy starcie
Blokuj zrzuty ekranu & podgląd aplikacji
Pobierz posty do folderów o nazwie użytkownika
+ Prepend Username to Filename
Oznacz relacje jako widoczne po wyświetleniu
Autor relacji będzie widział, że to wyświetliłeś
Oznacz wiadomość jako przeczytaną
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 4c7bbbc4..f8c3f401 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -23,6 +23,7 @@
Verificar se há atualizações ao iniciar
Block screenshots & app preview
Baixar publicações para pastas com o nome de usuário
+ Prepend Username to Filename
Marcar stories como vistos após a visualização
O autor do story saberá que você viu
Marcar DM como vista após a visualização
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index b491a1c5..ca3155ef 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -23,6 +23,7 @@
Проверять наличие обновлений при запуске
Block screenshots & app preview
Скачать публикации в папки с именем пользователя
+ Prepend Username to Filename
Отметить истории как увиденные после просмотра
Автор истории узнает, что вы просмотрели её
Отметить ЛС как увиденные после просмотра
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index f12178ec..7b1c175a 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -23,6 +23,7 @@
Kontrolovať aktualizácie pri štarte
Block screenshots & app preview
Ukľadať do priečinkov podľa mena
+ Prepend Username to Filename
Označiť príbehy po videní ako videné
Autor príbehu bude vedieť že ste ho videli
Po prečítaní, označiť správu ako prečítanú
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 4ca6836d..fea3a299 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -23,6 +23,7 @@
Güncellemeleri başlangıçta kontrol et
Block screenshots & app preview
İndirmeleri kullanıcı adından oluşan bir alt klasörün içine yap
+ Prepend Username to Filename
Hikayeleri gördükten sonra görüldü olarak işaretle
Hikayeyi paylaşan gördüğünüzü bilecek
DM\'leri gördükten sonra görüldü olarak işaretle
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index debb92fc..858193f6 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -23,6 +23,7 @@
Kiểm tra cập nhật khi khởi động
Block screenshots & app preview
Tải bài viết xuống theo thư mục tên người dùng trong Downloads
+ Prepend Username to Filename
Đánh dấu story là đã xem sau khi xem
Người đăng story sẽ biết bạn đã xem nó
Đánh dấu DM là đã xem sau khi xem
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index a6fe9c77..0fb2193f 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -23,6 +23,7 @@
启动时检查更新
屏蔽截图及应用预览
下载帖子到用户名文件夹
+ Prepend Username to Filename
查看快拍后将其标记为已读
快拍作者会知道您已看过
查看私信后将其标记为已读
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 26371e94..3ce706fa 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -23,6 +23,7 @@
啟動時檢查更新
Block screenshots & app preview
將貼文下載到用戶名資料夾
+ Prepend Username to Filename
檢視完限時動態後標記為已讀
限時動態的作者會知道您已查看了此限時動態
檢視完訊息後標記為已讀
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 0ba42065..d01e496f 100755
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -88,24 +88,61 @@
- HH:mm:ss
- H:mm:ss
-
+
+ - @id/direct_messages_nav_graph
+ - @id/feed_nav_graph
+ - @id/profile_nav_graph
+ - @id/discover_nav_graph
+ - @id/more_nav_graph
+
+ - @id/favorites_nav_graph
+ - @id/notification_viewer_nav_graph
+
+
+
- @navigation/direct_messages_nav_graph
- @navigation/feed_nav_graph
- @navigation/profile_nav_graph
- @navigation/discover_nav_graph
- @navigation/more_nav_graph
+ - @navigation/favorites_nav_graph
+ - @navigation/notification_viewer_nav_graph
-
+
+
- @string/title_dm
- @string/feed
- @string/profile
- @string/title_discover
- @string/more
+ - @string/title_favorites
+ - @string/title_notifications
-
- - @navigation/profile_nav_graph
- - @navigation/more_nav_graph
+
+
+ - @drawable/ic_message_24
+ - @drawable/ic_home_24
+ - @drawable/ic_person_24
+ - @drawable/ic_explore_24
+ - @drawable/ic_more_horiz_24
+ - @drawable/ic_star_24
+ - @drawable/ic_not_liked
+
+
+
+ - @id/directMessagesInboxFragment
+ - @id/feedFragment
+ - @id/profileFragment
+ - @id/discoverFragment
+ - @id/morePreferencesFragment
+ - @id/favoritesFragment
+ - @id/notificationsViewer
+
+
+
+
+
- @string/light_white_theme
- @string/light_barinsta_theme
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bd79862c..3adc84b8 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -26,8 +26,10 @@
Check for updates at startup
Block screenshots & app preview
Download posts to username folders
+ Prepend Username to Filename
Mark stories as seen after viewing
Story author will know you viewed it
+ Hide muted stories from feed
Mark DM as seen after viewing
Other members will know you viewed it
Enable activity notifications
@@ -473,8 +475,22 @@
Removed keyword: %s from filter list
Marked as seen
Delete unsuccessful
+ Throttled by Instagram because of too many API requests. Wait for some time before retrying.
+ Error
+ This account has been logged out.
+ Login required!
+ Sentry block.
+ User is inactive!
Barinsta Crash Report
Select an email app to send crash logs
+ Not found!
+ Your IP has been rate limited by Instagram. Wait for an hour and try again.
+ Skip this update
+ You\'re already on the latest version
+ Screen order
+ Other tabs
+ The tab order will be reflected on next launch
+ If saved, all DM related features will be disabled on next launch
Copy caption
Copy reply
Restore
diff --git a/app/src/main/resources/feed_response.json b/app/src/main/resources/feed_response.json
deleted file mode 100644
index 9e26dfee..00000000
--- a/app/src/main/resources/feed_response.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/app/src/main/resources/stories_response.json b/app/src/main/resources/stories_response.json
deleted file mode 100644
index 9e26dfee..00000000
--- a/app/src/main/resources/stories_response.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file