From 5bdfb7df51ed2612da51c1003786474ac1f02ad5 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 21 Mar 2021 22:50:23 +0900 Subject: [PATCH 01/12] Add sentry to github builds This commit adds github and fdroid product flavors. Sentry is added only to github builds. Sentry is opt-in. --- .gitignore | 1 + app/build.gradle | 21 +- app/sentry.gradle | 13 ++ .../fragments/settings/FlavorSettings.java | 40 ++++ .../java/awaisomereport/CrashHandler.java | 56 ++++++ app/src/github/AndroidManifest.xml | 10 + .../fragments/settings/FlavorSettings.java | 83 ++++++++ .../java/awaisomereport/CrashHandler.java | 59 ++++++ .../instagrabber/InstaGrabberApplication.java | 39 ++-- .../dialogs/ConfirmDialogFragment.java | 69 ++++--- .../DirectMessageSettingsFragment.java | 8 +- .../settings/GeneralPreferencesFragment.java | 10 + .../fragments/settings/IFlavorSettings.java | 14 ++ .../fragments/settings/PreferenceKeys.java | 1 + .../fragments/settings/SettingCategory.java | 6 + .../awais/instagrabber/utils/Constants.java | 2 + .../instagrabber/utils/SettingsHelper.java | 7 +- .../java/awaisomereport/CrashReporter.java | 179 ++---------------- .../awaisomereport/CrashReporterHelper.java | 134 +++++++++++++ .../awaisomereport/ErrorReporterActivity.java | 5 +- .../java/awaisomereport/ICrashHandler.java | 7 + app/src/main/res/values/strings.xml | 5 + 22 files changed, 553 insertions(+), 216 deletions(-) create mode 100644 app/sentry.gradle create mode 100644 app/src/fdroid/java/awais/instagrabber/fragments/settings/FlavorSettings.java create mode 100644 app/src/fdroid/java/awaisomereport/CrashHandler.java create mode 100644 app/src/github/AndroidManifest.xml create mode 100644 app/src/github/java/awais/instagrabber/fragments/settings/FlavorSettings.java create mode 100644 app/src/github/java/awaisomereport/CrashHandler.java create mode 100644 app/src/main/java/awais/instagrabber/fragments/settings/IFlavorSettings.java create mode 100644 app/src/main/java/awais/instagrabber/fragments/settings/SettingCategory.java create mode 100644 app/src/main/java/awaisomereport/CrashReporterHelper.java create mode 100644 app/src/main/java/awaisomereport/ICrashHandler.java diff --git a/.gitignore b/.gitignore index 4d79357f..d849b086 100755 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ .externalNativeBuild .cxx app/release +/sentry.properties \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 74bbf1dc..d945f017 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: "androidx.navigation.safeargs" +apply from: 'sentry.gradle' android { compileSdkVersion 29 @@ -48,8 +49,22 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } -} + flavorDimensions "repo" + + productFlavors { + github { + dimension "repo" + versionNameSuffix "-github" + buildConfigField("String", "dsn", SENTRY_DSN) + } + + fdroid { + dimension "repo" + versionNameSuffix "-fdroid" + } + } +} configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' @@ -81,7 +96,7 @@ dependencies { implementation 'androidx.palette:palette:1.0.0' implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" - implementation 'com.google.guava:guava:27.1-jre' + implementation 'com.google.guava:guava:27.0.1-android' // Room def room_version = "2.2.6" @@ -116,5 +131,7 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6' + githubImplementation 'io.sentry:sentry-android:4.3.0' + testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' } diff --git a/app/sentry.gradle b/app/sentry.gradle new file mode 100644 index 00000000..f2b24aa7 --- /dev/null +++ b/app/sentry.gradle @@ -0,0 +1,13 @@ +def dsnKey = 'DSN' +def defaultDsn = '\"\"' + +final Properties properties = new Properties() +File propertiesFile = rootProject.file('sentry.properties') +if (!propertiesFile.exists()) { + propertiesFile.createNewFile() +} +properties.load(new FileInputStream(propertiesFile)) + +ext{ + SENTRY_DSN = properties.getProperty(dsnKey, defaultDsn) +} \ No newline at end of file diff --git a/app/src/fdroid/java/awais/instagrabber/fragments/settings/FlavorSettings.java b/app/src/fdroid/java/awais/instagrabber/fragments/settings/FlavorSettings.java new file mode 100644 index 00000000..b30e263e --- /dev/null +++ b/app/src/fdroid/java/awais/instagrabber/fragments/settings/FlavorSettings.java @@ -0,0 +1,40 @@ +package awais.instagrabber.fragments.settings; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; + +import java.util.Collections; +import java.util.List; + +import awais.instagrabber.fragments.settings.IFlavorSettings; +import awais.instagrabber.fragments.settings.SettingCategory; + +public final class FlavorSettings implements IFlavorSettings { + + private static FlavorSettings instance; + + private FlavorSettings() { + } + + public static FlavorSettings getInstance() { + if (instance == null) { + instance = new FlavorSettings(); + } + return instance; + } + + @NonNull + @Override + public List getPreferences(@NonNull final Context context, + @NonNull final FragmentManager fragmentManager, + @NonNull final SettingCategory settingCategory) { + // switch (settingCategory) { + // default: + // break; + // } + return Collections.emptyList(); + } +} diff --git a/app/src/fdroid/java/awaisomereport/CrashHandler.java b/app/src/fdroid/java/awaisomereport/CrashHandler.java new file mode 100644 index 00000000..2f27d1c3 --- /dev/null +++ b/app/src/fdroid/java/awaisomereport/CrashHandler.java @@ -0,0 +1,56 @@ +package awaisomereport; + +import android.app.Application; + +import androidx.annotation.NonNull; + +public class CrashHandler implements ICrashHandler { + private static final String TAG = CrashHandler.class.getSimpleName(); + + private final Application application; + + public CrashHandler(@NonNull final Application application) { + this.application = application; + } + + @Override + public void uncaughtException(@NonNull final Thread t, + @NonNull final Throwable exception, + @NonNull final Thread.UncaughtExceptionHandler defaultEH) { + CrashReporterHelper.startErrorReporterActivity(application, exception); + // zipLogs(); + defaultEH.uncaughtException(t, exception); + } + + // public synchronized CrashReporter zipLogs() { + // final File logDir = Utils.logCollector != null ? Utils.logCollector.getLogDir() : + // new File(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? application.getDataDir() : application.getFilesDir(), "crashlogs"); + // + // try (final FileOutputStream fos = new FileOutputStream(crashLogsZip); + // final ZipOutputStream zos = new ZipOutputStream(fos)) { + // + // final File[] files = logDir.listFiles(); + // + // if (files != null) { + // zos.setLevel(5); + // byte[] buffer; + // for (final File file : files) { + // if (file != null && file.length() > 0) { + // buffer = new byte[1024]; + // try (final FileInputStream fis = new FileInputStream(file)) { + // zos.putNextEntry(new ZipEntry(file.getName())); + // int length; + // while ((length = fis.read(buffer)) > 0) zos.write(buffer, 0, length); + // zos.closeEntry(); + // } + // } + // } + // } + // + // } catch (final Exception e) { + // if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); + // } + // + // return this; + // } +} diff --git a/app/src/github/AndroidManifest.xml b/app/src/github/AndroidManifest.xml new file mode 100644 index 00000000..4c6a6fe0 --- /dev/null +++ b/app/src/github/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/github/java/awais/instagrabber/fragments/settings/FlavorSettings.java b/app/src/github/java/awais/instagrabber/fragments/settings/FlavorSettings.java new file mode 100644 index 00000000..85adb8a9 --- /dev/null +++ b/app/src/github/java/awais/instagrabber/fragments/settings/FlavorSettings.java @@ -0,0 +1,83 @@ +package awais.instagrabber.fragments.settings; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; + +import com.google.common.collect.ImmutableList; + +import java.util.Collections; +import java.util.List; + +import awais.instagrabber.R; +import awais.instagrabber.dialogs.ConfirmDialogFragment; + +import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY; +import static awais.instagrabber.utils.Utils.settingsHelper; + +public final class FlavorSettings implements IFlavorSettings { + + private static FlavorSettings instance; + + private FlavorSettings() { + } + + public static FlavorSettings getInstance() { + if (instance == null) { + instance = new FlavorSettings(); + } + return instance; + } + + @NonNull + @Override + public List getPreferences(@NonNull final Context context, + @NonNull final FragmentManager fragmentManager, + @NonNull final SettingCategory settingCategory) { + switch (settingCategory) { + case GENERAL: + return getGeneralPrefs(context, fragmentManager); + default: + break; + } + return Collections.emptyList(); + } + + private List getGeneralPrefs(@NonNull final Context context, + @NonNull final FragmentManager fragmentManager) { + return ImmutableList.of( + getSentryPreference(context, fragmentManager) + ); + } + + private Preference getSentryPreference(@NonNull final Context context, + @NonNull final FragmentManager fragmentManager) { + if (!settingsHelper.hasPreference(PREF_ENABLE_SENTRY)) { + // disabled by default + settingsHelper.putBoolean(PREF_ENABLE_SENTRY, false); + } + return PreferenceHelper.getSwitchPreference( + context, + PREF_ENABLE_SENTRY, + R.string.enable_sentry, + R.string.sentry_summary, + false, + (preference, newValue) -> { + if (!(newValue instanceof Boolean)) return true; + final boolean enabled = (Boolean) newValue; + if (enabled) { + final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( + 111, + 0, + R.string.sentry_start_next_launch, + R.string.ok, + 0, + 0); + dialogFragment.show(fragmentManager, "sentry_dialog"); + } + return true; + }); + } +} diff --git a/app/src/github/java/awaisomereport/CrashHandler.java b/app/src/github/java/awaisomereport/CrashHandler.java new file mode 100644 index 00000000..cd28eaa2 --- /dev/null +++ b/app/src/github/java/awaisomereport/CrashHandler.java @@ -0,0 +1,59 @@ +package awaisomereport; + +import android.app.Application; + +import androidx.annotation.NonNull; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.fragments.settings.PreferenceKeys; +import io.sentry.SentryLevel; +import io.sentry.android.core.SentryAndroid; +import io.sentry.protocol.Contexts; +import io.sentry.protocol.Device; + +import static awais.instagrabber.utils.Utils.settingsHelper; + +public class CrashHandler implements ICrashHandler { + private static final String TAG = CrashHandler.class.getSimpleName(); + + private final Application application; + private final boolean enabled; + + public CrashHandler(@NonNull final Application application) { + this.application = application; + if (!settingsHelper.hasPreference(PreferenceKeys.PREF_ENABLE_SENTRY)) { + // disabled by default (change to true if we need enabled by default) + enabled = false; + } else { + enabled = settingsHelper.getBoolean(PreferenceKeys.PREF_ENABLE_SENTRY); + } + if (!enabled) return; + SentryAndroid.init(application, options -> { + options.setDsn(BuildConfig.dsn); + options.setDiagnosticLevel(SentryLevel.ERROR); + options.setBeforeSend((event, hint) -> { + // Removing unneeded info from event + final Contexts contexts = event.getContexts(); + final Device device = contexts.getDevice(); + device.setName(null); + device.setTimezone(null); + device.setCharging(null); + device.setBootTime(null); + device.setFreeStorage(null); + device.setBatteryTemperature(null); + return event; + }); + }); + } + + @Override + public void uncaughtException(@NonNull final Thread t, + @NonNull final Throwable exception, + @NonNull final Thread.UncaughtExceptionHandler defaultEH) { + // When enabled, Sentry auto captures unhandled exceptions + if (!enabled) { + CrashReporterHelper.startErrorReporterActivity(application, exception); + } + defaultEH.uncaughtException(t, exception); + } +} diff --git a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java index b90c8343..a033473d 100644 --- a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java +++ b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java @@ -18,14 +18,12 @@ import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.SettingsHelper; import awais.instagrabber.utils.TextUtils; import awaisomereport.CrashReporter; -//import awaisomereport.LogCollector; import static awais.instagrabber.utils.CookieUtils.NET_COOKIE_MANAGER; import static awais.instagrabber.utils.Utils.applicationHandler; import static awais.instagrabber.utils.Utils.cacheDir; import static awais.instagrabber.utils.Utils.clipboardManager; import static awais.instagrabber.utils.Utils.datetimeParser; -//import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.settingsHelper; public final class InstaGrabberApplication extends Application { @@ -34,16 +32,16 @@ public final class InstaGrabberApplication extends Application { @Override public void onCreate() { super.onCreate(); - // final Set requestListeners = new HashSet<>(); - // requestListeners.add(new RequestLoggingListener()); - final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig - .newBuilder(this) - // .setMainDiskCacheConfig(diskCacheConfig) - // .setRequestListeners(requestListeners) - .setDownsampleEnabled(true) - .build(); - Fresco.initialize(this, imagePipelineConfig); - // FLog.setMinimumLoggingLevel(FLog.VERBOSE); + CookieHandler.setDefault(NET_COOKIE_MANAGER); + + if (settingsHelper == null) { + settingsHelper = new SettingsHelper(this); + } + + if (!BuildConfig.DEBUG) { + CrashReporter.get(this).start(); + } + // logCollector = new LogCollector(this); if (BuildConfig.DEBUG) { try { @@ -55,13 +53,16 @@ public final class InstaGrabberApplication extends Application { } } - if (!BuildConfig.DEBUG) CrashReporter.get(this).start(); -// logCollector = new LogCollector(this); - - CookieHandler.setDefault(NET_COOKIE_MANAGER); - - if (settingsHelper == null) - settingsHelper = new SettingsHelper(this); + // final Set requestListeners = new HashSet<>(); + // requestListeners.add(new RequestLoggingListener()); + final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig + .newBuilder(this) + // .setMainDiskCacheConfig(diskCacheConfig) + // .setRequestListeners(requestListeners) + .setDownsampleEnabled(true) + .build(); + Fresco.initialize(this, imagePipelineConfig); + // FLog.setMinimumLoggingLevel(FLog.VERBOSE); if (applicationHandler == null) { applicationHandler = new Handler(getApplicationContext().getMainLooper()); diff --git a/app/src/main/java/awais/instagrabber/dialogs/ConfirmDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/ConfirmDialogFragment.java index caba0b38..5b8eb3c9 100644 --- a/app/src/main/java/awais/instagrabber/dialogs/ConfirmDialogFragment.java +++ b/app/src/main/java/awais/instagrabber/dialogs/ConfirmDialogFragment.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -17,6 +18,9 @@ public class ConfirmDialogFragment extends DialogFragment { private Context context; private ConfirmDialogFragmentCallback callback; + private final int defaultPositiveButtonText = R.string.ok; + // private final int defaultNegativeButtonText = R.string.cancel; + @NonNull public static ConfirmDialogFragment newInstance(final int requestCode, @StringRes final int title, @@ -26,11 +30,21 @@ public class ConfirmDialogFragment extends DialogFragment { @StringRes final int neutralText) { Bundle args = new Bundle(); args.putInt("requestCode", requestCode); - args.putInt("title", title); - args.putInt("message", message); - args.putInt("positive", positiveText); - args.putInt("negative", negativeText); - args.putInt("neutral", neutralText); + if (title != 0) { + args.putInt("title", title); + } + if (message != 0) { + args.putInt("message", message); + } + if (positiveText != 0) { + args.putInt("positive", positiveText); + } + if (negativeText != 0) { + args.putInt("negative", negativeText); + } + if (neutralText != 0) { + args.putInt("neutral", neutralText); + } ConfirmDialogFragment fragment = new ConfirmDialogFragment(); fragment.setArguments(args); return fragment; @@ -41,10 +55,9 @@ public class ConfirmDialogFragment extends DialogFragment { @Override public void onAttach(@NonNull final Context context) { super.onAttach(context); - try { - callback = (ConfirmDialogFragmentCallback) getParentFragment(); - } catch (ClassCastException e) { - throw new ClassCastException("Calling fragment must implement ConfirmDialogFragmentCallback interface"); + final Fragment parentFragment = getParentFragment(); + if (parentFragment instanceof ConfirmDialogFragmentCallback) { + callback = (ConfirmDialogFragmentCallback) parentFragment; } this.context = context; } @@ -53,38 +66,42 @@ public class ConfirmDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { final Bundle arguments = getArguments(); - int title = -1; - int message = -1; - int positiveButtonText = R.string.ok; - int negativeButtonText = R.string.cancel; - int neutralButtonText = -1; + int title = 0; + int message = 0; + int neutralButtonText = 0; + int negativeButtonText = 0; + + final int positiveButtonText; final int requestCode; if (arguments != null) { - title = arguments.getInt("title", -1); - message = arguments.getInt("message", -1); - positiveButtonText = arguments.getInt("positive", R.string.ok); - negativeButtonText = arguments.getInt("negative", R.string.cancel); - neutralButtonText = arguments.getInt("neutral", -1); + title = arguments.getInt("title", 0); + message = arguments.getInt("message", 0); + positiveButtonText = arguments.getInt("positive", defaultPositiveButtonText); + negativeButtonText = arguments.getInt("negative", 0); + neutralButtonText = arguments.getInt("neutral", 0); requestCode = arguments.getInt("requestCode", 0); } else { requestCode = 0; + positiveButtonText = defaultPositiveButtonText; } final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context) .setPositiveButton(positiveButtonText, (d, w) -> { if (callback == null) return; callback.onPositiveButtonClicked(requestCode); - }) - .setNegativeButton(negativeButtonText, (dialog, which) -> { - if (callback == null) return; - callback.onNegativeButtonClicked(requestCode); }); - if (title > 0) { + if (title != 0) { builder.setTitle(title); } - if (message > 0) { + if (message != 0) { builder.setMessage(message); } - if (neutralButtonText > 0) { + if (negativeButtonText != 0) { + builder.setNegativeButton(negativeButtonText, (dialog, which) -> { + if (callback == null) return; + callback.onNegativeButtonClicked(requestCode); + }); + } + if (neutralButtonText != 0) { builder.setNeutralButton(neutralButtonText, (dialog, which) -> { if (callback == null) return; callback.onNeutralButtonClicked(requestCode); diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java index bbd174f2..64c7fbca 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java @@ -186,7 +186,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi R.string.admin_approval_required_description, R.string.ok, R.string.cancel, - -1 + 0 ); confirmDialogFragment.show(getChildFragmentManager(), "approval_required_dialog"); return; @@ -272,10 +272,10 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi final ConfirmDialogFragment confirmDialogFragment = ConfirmDialogFragment.newInstance( LEAVE_THREAD_REQUEST_CODE, R.string.dms_action_leave_question, - -1, + 0, R.string.yes, R.string.no, - -1 + 0 ); confirmDialogFragment.show(getChildFragmentManager(), "leave_thread_confirmation_dialog"); }); @@ -290,7 +290,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi R.string.dms_action_end_description, R.string.yes, R.string.no, - -1 + 0 ); confirmDialogFragment.show(getChildFragmentManager(), "end_thread_confirmation_dialog"); }); diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java index 4606fb48..f63c4a7a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java @@ -9,6 +9,8 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreferenceCompat; +import java.util.List; + import awais.instagrabber.R; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; @@ -29,6 +31,14 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment { } screen.addPreference(getUpdateCheckPreference(context)); screen.addPreference(getFlagSecurePreference(context)); + final List preferences = FlavorSettings.getInstance().getPreferences(context, + getChildFragmentManager(), + SettingCategory.GENERAL); + if (preferences != null) { + for (final Preference preference : preferences) { + screen.addPreference(preference); + } + } } private Preference getDefaultTabPreference(@NonNull final Context context) { diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/IFlavorSettings.java b/app/src/main/java/awais/instagrabber/fragments/settings/IFlavorSettings.java new file mode 100644 index 00000000..4b0f1c5a --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/settings/IFlavorSettings.java @@ -0,0 +1,14 @@ +package awais.instagrabber.fragments.settings; + +import android.content.Context; + +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; + +import java.util.List; + +public interface IFlavorSettings { + List getPreferences(Context context, + FragmentManager childFragmentManager, + SettingCategory settingCategory); +} 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 3f481685..3482cf7f 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java @@ -5,4 +5,5 @@ public final class PreferenceKeys { public static final String PREF_ENABLE_DM_AUTO_REFRESH = "enable_dm_auto_refresh"; 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"; } diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/SettingCategory.java b/app/src/main/java/awais/instagrabber/fragments/settings/SettingCategory.java new file mode 100644 index 00000000..88ba5e6f --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/settings/SettingCategory.java @@ -0,0 +1,6 @@ +package awais.instagrabber.fragments.settings; + +public enum SettingCategory { + GENERAL, + // add more as and when required +} diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index cb56eba2..64666798 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -1,6 +1,8 @@ package awais.instagrabber.utils; public final class Constants { + public static final String CRASH_REPORT_EMAIL = "barinsta@austinhuang.me"; + // string prefs public static final String FOLDER_PATH = "custom_path"; public static final String DATE_TIME_FORMAT = "date_time_format"; diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index b6238a97..d51acd4a 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -12,6 +12,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER; 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.utils.Constants.APP_LANGUAGE; import static awais.instagrabber.utils.Constants.APP_THEME; import static awais.instagrabber.utils.Constants.APP_UA; @@ -130,6 +131,10 @@ public final class SettingsHelper { if (sharedPreferences != null) sharedPreferences.edit().putBoolean(key, val).apply(); } + public boolean hasPreference(final String key) { + return sharedPreferences != null && sharedPreferences.contains(key); + } + @StringDef( {APP_LANGUAGE, APP_THEME, APP_UA, BROWSER_UA, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, @@ -141,7 +146,7 @@ public final class SettingsHelper { @StringDef({DOWNLOAD_USER_FOLDER, 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}) + FLAG_SECURE, PREF_ENABLE_SENTRY}) 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/awaisomereport/CrashReporter.java b/app/src/main/java/awaisomereport/CrashReporter.java index f5f22143..8b61e952 100755 --- a/app/src/main/java/awaisomereport/CrashReporter.java +++ b/app/src/main/java/awaisomereport/CrashReporter.java @@ -1,50 +1,35 @@ package awaisomereport; import android.app.Application; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.Process; -import android.util.Log; import androidx.annotation.NonNull; -import androidx.core.content.FileProvider; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Date; -//import java.util.zip.ZipEntry; -//import java.util.zip.ZipOutputStream; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.utils.Utils; public final class CrashReporter implements Thread.UncaughtExceptionHandler { + private static final String TAG = CrashReporter.class.getSimpleName(); + private static CrashReporter reporterInstance; - private final Application application; - private final String email; -// private final File crashLogsZip; + + // private final File crashLogsZip; + private final CrashHandler crashHandler; + private boolean startAttempted = false; + private Thread.UncaughtExceptionHandler defaultEH; public static CrashReporter get(final Application application) { - if (reporterInstance == null) reporterInstance = new CrashReporter(application); + if (reporterInstance == null) { + reporterInstance = new CrashReporter(application); + } return reporterInstance; } private CrashReporter(@NonNull final Application application) { - this.application = application; - this.email = "barinsta@austinhuang.me"; -// this.crashLogsZip = new File(application.getExternalCacheDir(), "crash_logs.zip"); + crashHandler = new CrashHandler(application); + // this.crashLogsZip = new File(application.getExternalCacheDir(), "crash_logs.zip"); } public void start() { if (!startAttempted) { + defaultEH = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); startAttempted = true; } @@ -52,140 +37,10 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(@NonNull final Thread t, @NonNull final Throwable exception) { - final StringBuilder reportBuilder = new StringBuilder(); - reportBuilder.append("IMPORTANT: If sending by email, your email address and the entire content will be made public on GitHub issues."); - reportBuilder.append("\r\nIMPORTANT: When possible, please describe the steps leading to this crash. Thank you for your cooperation."); - reportBuilder.append("\r\n\r\nError report collected on: ").append(new Date().toString()); - - reportBuilder - .append("\r\n\r\nInformation:\r\n==============") - .append("\r\nVERSION : ").append(BuildConfig.VERSION_NAME) - .append("\r\nVERSION_CODE : ").append(BuildConfig.VERSION_CODE) - .append("\r\nPHONE-MODEL : ").append(Build.MODEL) - .append("\r\nANDROID_VERS : ").append(Build.VERSION.RELEASE) - .append("\r\nANDROID_REL : ").append(Build.VERSION.SDK_INT) - .append("\r\nBRAND : ").append(Build.BRAND) - .append("\r\nMANUFACTURER : ").append(Build.MANUFACTURER) - .append("\r\nBOARD : ").append(Build.BOARD) - .append("\r\nDEVICE : ").append(Build.DEVICE) - .append("\r\nPRODUCT : ").append(Build.PRODUCT) - .append("\r\nHOST : ").append(Build.HOST) - .append("\r\nTAGS : ").append(Build.TAGS); - - reportBuilder.append("\r\n\r\nStack:\r\n==============\r\n"); - final Writer result = new StringWriter(); - try (final PrintWriter printWriter = new PrintWriter(result)) { - exception.printStackTrace(printWriter); - reportBuilder.append(result.toString()); - - reportBuilder.append("\r\nCause:\r\n=============="); - - // for AsyncTask crashes - Throwable cause = exception.getCause(); - while (cause != null) { - cause.printStackTrace(printWriter); - reportBuilder.append(result.toString()); - cause = cause.getCause(); - } - } - reportBuilder.append("\r\n\r\n**** End of current Report ***"); - - final String errorContent = reportBuilder.toString(); - try (final FileOutputStream trace = application.openFileOutput("stack-" + System.currentTimeMillis() + ".stacktrace", Context.MODE_PRIVATE)) { - trace.write(errorContent.getBytes()); - } catch (final Exception ex) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", ex); - } - - application.startActivity(new Intent(application, ErrorReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - -// zipLogs(); - - Process.killProcess(Process.myPid()); - System.exit(10); - } - -// public synchronized CrashReporter zipLogs() { -// final File logDir = Utils.logCollector != null ? Utils.logCollector.getLogDir() : -// new File(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? application.getDataDir() : application.getFilesDir(), "crashlogs"); -// -// try (final FileOutputStream fos = new FileOutputStream(crashLogsZip); -// final ZipOutputStream zos = new ZipOutputStream(fos)) { -// -// final File[] files = logDir.listFiles(); -// -// if (files != null) { -// zos.setLevel(5); -// byte[] buffer; -// for (final File file : files) { -// if (file != null && file.length() > 0) { -// buffer = new byte[1024]; -// try (final FileInputStream fis = new FileInputStream(file)) { -// zos.putNextEntry(new ZipEntry(file.getName())); -// int length; -// while ((length = fis.read(buffer)) > 0) zos.write(buffer, 0, length); -// zos.closeEntry(); -// } -// } -// } -// } -// -// } catch (final Exception e) { -// if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); -// } -// -// return this; -// } - - @SuppressWarnings("ResultOfMethodCallIgnored") - public void startCrashEmailIntent(final Context context) { - try { - final String filePath = context.getFilesDir().getAbsolutePath(); - - String[] errorFileList; - - try { - final File dir = new File(filePath); - if (dir.exists() && !dir.isDirectory()) dir.delete(); - dir.mkdir(); - errorFileList = dir.list((d, name) -> name.endsWith(".stacktrace")); - } catch (final Exception e) { - errorFileList = null; - } - - if (errorFileList != null && errorFileList.length > 0) { - final StringBuilder errorStringBuilder; - - errorStringBuilder = new StringBuilder("\r\n\r\n"); - final int maxSendMail = 5; - - int curIndex = 0; - for (final String curString : errorFileList) { - final File file = new File(filePath + '/' + curString); - - if (curIndex++ <= maxSendMail) { - errorStringBuilder.append("New Trace collected:\r\n=====================\r\n"); - try (final BufferedReader input = new BufferedReader(new FileReader(file))) { - String line; - while ((line = input.readLine()) != null) - errorStringBuilder.append(line).append("\r\n"); - } - } - - file.delete(); - } - - errorStringBuilder.append("\r\n\r\n"); - - context.startActivity(Intent.createChooser(new Intent(Intent.ACTION_SEND).setType("message/rfc822") - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - .putExtra(Intent.EXTRA_EMAIL, new String[]{email}) -// .putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(application, BuildConfig.APPLICATION_ID + ".provider", crashLogsZip)) - .putExtra(Intent.EXTRA_SUBJECT, "Barinsta Crash Report") - .putExtra(Intent.EXTRA_TEXT, errorStringBuilder.toString()), "Select an email app to send crash logs")); - } - } catch (final Exception e) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); + if (crashHandler == null) { + defaultEH.uncaughtException(t, exception); + return; } + crashHandler.uncaughtException(t, exception, defaultEH); } } diff --git a/app/src/main/java/awaisomereport/CrashReporterHelper.java b/app/src/main/java/awaisomereport/CrashReporterHelper.java new file mode 100644 index 00000000..83f17f3e --- /dev/null +++ b/app/src/main/java/awaisomereport/CrashReporterHelper.java @@ -0,0 +1,134 @@ +package awaisomereport; + +import android.app.Application; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Build; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Date; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.R; +import awais.instagrabber.utils.Constants; + +public final class CrashReporterHelper { + private static final String TAG = CrashReporterHelper.class.getSimpleName(); + + public static void startErrorReporterActivity(@NonNull final Application application, + @NonNull final Throwable exception) { + final StringBuilder reportBuilder = new StringBuilder(); + reportBuilder.append("IMPORTANT: If sending by email, your email address and the entire content will be made public on GitHub issues.") + .append("\r\nIMPORTANT: When possible, please describe the steps leading to this crash. Thank you for your cooperation.") + .append("\r\n\r\nError report collected on: ").append(new Date().toString()) + .append("\r\n\r\nInformation:\r\n==============") + .append("\r\nVERSION : ").append(BuildConfig.VERSION_NAME) + .append("\r\nVERSION_CODE : ").append(BuildConfig.VERSION_CODE) + .append("\r\nPHONE-MODEL : ").append(Build.MODEL) + .append("\r\nANDROID_VERS : ").append(Build.VERSION.RELEASE) + .append("\r\nANDROID_REL : ").append(Build.VERSION.SDK_INT) + .append("\r\nBRAND : ").append(Build.BRAND) + .append("\r\nMANUFACTURER : ").append(Build.MANUFACTURER) + .append("\r\nBOARD : ").append(Build.BOARD) + .append("\r\nDEVICE : ").append(Build.DEVICE) + .append("\r\nPRODUCT : ").append(Build.PRODUCT) + .append("\r\nHOST : ").append(Build.HOST) + .append("\r\nTAGS : ").append(Build.TAGS); + + reportBuilder.append("\r\n\r\nStack:\r\n==============\r\n"); + final Writer result = new StringWriter(); + try (final PrintWriter printWriter = new PrintWriter(result)) { + exception.printStackTrace(printWriter); + reportBuilder.append(result.toString()); + reportBuilder.append("\r\nCause:\r\n=============="); + // for AsyncTask crashes + Throwable cause = exception.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + reportBuilder.append(result.toString()); + cause = cause.getCause(); + } + } + reportBuilder.append("\r\n\r\n**** End of current Report ***"); + + final String errorContent = reportBuilder.toString(); + try (final FileOutputStream trace = application.openFileOutput("stack-" + System.currentTimeMillis() + ".stacktrace", Context.MODE_PRIVATE)) { + trace.write(errorContent.getBytes()); + } catch (final Exception ex) { + if (BuildConfig.DEBUG) Log.e(TAG, "", ex); + } + + application.startActivity(new Intent(application, ErrorReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + public static void startCrashEmailIntent(final Context context) { + try { + final String filePath = context.getFilesDir().getAbsolutePath(); + + String[] errorFileList; + + try { + final File dir = new File(filePath); + if (dir.exists() && !dir.isDirectory()) { + //noinspection ResultOfMethodCallIgnored + dir.delete(); + } + //noinspection ResultOfMethodCallIgnored + dir.mkdirs(); + errorFileList = dir.list((d, name) -> name.endsWith(".stacktrace")); + } catch (final Exception e) { + errorFileList = null; + } + + if (errorFileList == null || errorFileList.length <= 0) { + return; + } + final StringBuilder errorStringBuilder; + + errorStringBuilder = new StringBuilder("\r\n\r\n"); + final int maxSendMail = 5; + int curIndex = 0; + for (final String curString : errorFileList) { + final File file = new File(filePath + '/' + curString); + + if (curIndex++ <= maxSendMail) { + errorStringBuilder.append("New Trace collected:\r\n=====================\r\n"); + try (final BufferedReader input = new BufferedReader(new FileReader(file))) { + String line; + while ((line = input.readLine()) != null) + errorStringBuilder.append(line).append("\r\n"); + } + } + //noinspection ResultOfMethodCallIgnored + file.delete(); + } + + errorStringBuilder.append("\r\n\r\n"); + final Resources resources = context.getResources(); + context.startActivity(Intent.createChooser( + new Intent(Intent.ACTION_SEND) + .setType("message/rfc822") + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + .putExtra(Intent.EXTRA_EMAIL, new String[]{Constants.CRASH_REPORT_EMAIL}) + // .putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(application, BuildConfig.APPLICATION_ID + ".provider", crashLogsZip)) + .putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.crash_report_subject)) + .putExtra(Intent.EXTRA_TEXT, errorStringBuilder.toString()), + context.getResources().getString(R.string.crash_report_title)) + ); + } catch (final Exception e) { + Log.e(TAG, "", e); + } + } +} diff --git a/app/src/main/java/awaisomereport/ErrorReporterActivity.java b/app/src/main/java/awaisomereport/ErrorReporterActivity.java index 9fb1ce40..31dc3817 100755 --- a/app/src/main/java/awaisomereport/ErrorReporterActivity.java +++ b/app/src/main/java/awaisomereport/ErrorReporterActivity.java @@ -43,8 +43,9 @@ public final class ErrorReporterActivity extends Activity implements View.OnClic @Override public void onClick(@NonNull final View v) { - if (v == btnReport) - CrashReporter.get(getApplication()).startCrashEmailIntent(this); + if (v == btnReport) { + CrashReporterHelper.startCrashEmailIntent(this); + } finish(); System.exit(10); } diff --git a/app/src/main/java/awaisomereport/ICrashHandler.java b/app/src/main/java/awaisomereport/ICrashHandler.java new file mode 100644 index 00000000..103987d9 --- /dev/null +++ b/app/src/main/java/awaisomereport/ICrashHandler.java @@ -0,0 +1,7 @@ +package awaisomereport; + +public interface ICrashHandler { + void uncaughtException(Thread t, + Throwable exception, + Thread.UncaughtExceptionHandler defaultEH); +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b13df845..8dacbcb5 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -468,4 +468,9 @@ Request failed! Marked as seen Delete unsuccessful + Barinsta Crash Report + Select an email app to send crash logs + Enable Sentry + Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io + Sentry will start on next launch From 39c472d6c2d1dcbec5e6227ed21ebe3924666997 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 21 Mar 2021 23:30:38 +0900 Subject: [PATCH 02/12] Move sentry strings to github flavor strings.xml --- app/src/github/res/values/strings.xml | 6 ++++++ app/src/main/res/values/strings.xml | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 app/src/github/res/values/strings.xml diff --git a/app/src/github/res/values/strings.xml b/app/src/github/res/values/strings.xml new file mode 100644 index 00000000..6bc4c7a4 --- /dev/null +++ b/app/src/github/res/values/strings.xml @@ -0,0 +1,6 @@ + + + Enable Sentry + Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io + Sentry will start on next launch + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8dacbcb5..cf7a695f 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -470,7 +470,4 @@ Delete unsuccessful Barinsta Crash Report Select an email app to send crash logs - Enable Sentry - Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io - Sentry will start on next launch From 81bdced2305647b8035b9ce80c27ac3fbc113d64 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 12:12:03 -0400 Subject: [PATCH 03/12] close #843 --- .../directmessages/DirectItemRavenMediaViewHolder.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java index a8fb8dda..949b2a9a 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java @@ -24,6 +24,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectItemVisual import awais.instagrabber.repositories.responses.directmessages.DirectThread; import awais.instagrabber.utils.NumberUtils; import awais.instagrabber.utils.ResponseBodyUtils; +import awais.instagrabber.utils.TextUtils; public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder { @@ -48,7 +49,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder { if (media == null) return; setExpiryInfo(visualMedia); setPreview(visualMedia, messageDirection); - final boolean expired = media.getPk() == null; + final boolean expired = TextUtils.isEmpty(media.getId()); if (expired) return; itemView.setOnClickListener(v -> openMedia(media)); /*final boolean isExpired = visualMedia == null || (mediaModel = visualMedia.getMedia()) == null || @@ -118,7 +119,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder { final RavenMediaViewMode viewMode = visualMedia.getViewMode(); if (viewMode != RavenMediaViewMode.PERMANENT) { final MediaItemType mediaType = media.getMediaType(); - final boolean expired = media.getPk() == null; + final boolean expired = TextUtils.isEmpty(media.getId()); final int info; switch (mediaType) { case MEDIA_TYPE_IMAGE: @@ -153,7 +154,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder { private void setPreview(final DirectItemVisualMedia visualMedia, final MessageDirection messageDirection) { final Media media = visualMedia.getMedia(); - final boolean expired = media.getPk() == null; + final boolean expired = TextUtils.isEmpty(media.getId()); if (expired) { binding.preview.setVisibility(View.GONE); binding.typeIcon.setVisibility(View.GONE); From ac89f9d70e7c89dc88fd675b26683510d68bd819 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 12:12:48 -0400 Subject: [PATCH 04/12] remove duplicate code --- app/src/main/java/awais/instagrabber/utils/TextUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/awais/instagrabber/utils/TextUtils.java b/app/src/main/java/awais/instagrabber/utils/TextUtils.java index e26bd8cf..64eddd22 100644 --- a/app/src/main/java/awais/instagrabber/utils/TextUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/TextUtils.java @@ -69,7 +69,7 @@ public final class TextUtils { str = str.trim(); return "".equals(str) || "null".equals(str) || str.isEmpty(); } - return "null".contentEquals(charSequence) || "".contentEquals(charSequence) || charSequence.length() < 1; + return "null".contentEquals(charSequence) || "".contentEquals(charSequence); } public static String millisToTimeString(final long millis) { From aca44f0ab9992726d1b1d29cf2baf87cae9778b4 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 13:53:35 -0400 Subject: [PATCH 05/12] fix pending badge --- .../DirectMessageInboxFragment.java | 31 ++++++++++++------- app/src/main/res/menu/dm_inbox_menu.xml | 10 ++++++ app/src/main/res/values/ids.xml | 1 - 3 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 app/src/main/res/menu/dm_inbox_menu.xml diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java index 4b8bece2..34d4ed1c 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.IntentFilter; import android.content.res.Configuration; import android.os.Bundle; +import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -104,6 +105,11 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh public void onPause() { super.onPause(); unregisterReceiver(); + isPendingRequestTotalBadgeAttached = false; + if (pendingRequestTotalBadgeDrawable != null) { + BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); + pendingRequestTotalBadgeDrawable = null; + } } @Override @@ -124,21 +130,13 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh public void onDestroyView() { super.onDestroyView(); unregisterReceiver(); - isPendingRequestTotalBadgeAttached = false; - if (pendingRequestTotalBadgeDrawable != null) { - BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); - pendingRequestTotalBadgeDrawable = null; - } } @Override public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - pendingRequestsMenuItem = menu.add(Menu.NONE, R.id.pending_requests, Menu.NONE, "Pending requests"); - pendingRequestsMenuItem.setIcon(R.drawable.ic_account_clock_24) - .setVisible(false) - .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS); - attachPendingRequestsBadge(viewModel.getPendingRequestsTotal().getValue()); + inflater.inflate(R.menu.dm_inbox_menu, menu); + pendingRequestsMenuItem = menu.findItem(R.id.pending_requests); + pendingRequestsMenuItem.setVisible(isPendingRequestTotalBadgeAttached); } @Override @@ -213,7 +211,16 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh @SuppressLint("UnsafeExperimentalUsageError") private void attachPendingRequestsBadge(@Nullable final Integer count) { - if (pendingRequestsMenuItem == null) return; + if (pendingRequestsMenuItem == null) { + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + attachPendingRequestsBadge(count); + } + }, 500); + return; + } if (pendingRequestTotalBadgeDrawable == null) { final Context context = getContext(); if (context == null) return; diff --git a/app/src/main/res/menu/dm_inbox_menu.xml b/app/src/main/res/menu/dm_inbox_menu.xml new file mode 100644 index 00000000..041ebda7 --- /dev/null +++ b/app/src/main/res/menu/dm_inbox_menu.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index ecb381cf..7319700f 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -4,5 +4,4 @@ - \ No newline at end of file From 1dd78b7d9196daba20bfa2e98dbbc387900f2eaf Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 14:51:44 -0400 Subject: [PATCH 06/12] reorganize responses --- .../adapters/NotificationsAdapter.java | 2 +- .../viewholder/NotificationViewHolder.java | 4 ++-- .../fragments/NotificationsViewerFragment.java | 7 +++---- .../repositories/FeedRepository.java | 2 +- .../repositories/responses/Media.java | 1 + .../responses/NewsInboxResponse.java | 3 +++ .../{ => feed}/EndOfFeedDemarcator.java | 2 +- .../responses/{ => feed}/EndOfFeedGroup.java | 4 +++- .../responses/{ => feed}/EndOfFeedGroupSet.java | 2 +- .../responses/{ => feed}/FeedFetchResponse.java | 4 +++- .../{ => notification}/Notification.java | 2 +- .../{ => notification}/NotificationArgs.java | 4 +--- .../{ => notification}/NotificationCounts.java | 2 +- .../{ => notification}/NotificationImage.java | 2 +- .../services/ActivityCheckerService.java | 4 +--- .../viewmodels/NotificationViewModel.java | 2 +- .../instagrabber/webservices/FeedService.java | 8 ++++---- .../instagrabber/webservices/NewsService.java | 17 +++-------------- 18 files changed, 32 insertions(+), 40 deletions(-) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => feed}/EndOfFeedDemarcator.java (94%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => feed}/EndOfFeedGroup.java (92%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => feed}/EndOfFeedGroupSet.java (97%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => feed}/FeedFetchResponse.java (90%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => notification}/Notification.java (91%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => notification}/NotificationArgs.java (97%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => notification}/NotificationCounts.java (95%) rename app/src/main/java/awais/instagrabber/repositories/responses/{ => notification}/NotificationImage.java (84%) diff --git a/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java index 8a5c3a4b..80ab465b 100644 --- a/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java @@ -16,7 +16,7 @@ import java.util.stream.Collectors; import awais.instagrabber.adapters.viewholder.NotificationViewHolder; import awais.instagrabber.databinding.ItemNotificationBinding; import awais.instagrabber.models.enums.NotificationType; -import awais.instagrabber.repositories.responses.Notification; +import awais.instagrabber.repositories.responses.notification.Notification; public final class NotificationsAdapter extends ListAdapter { private final OnNotificationClickListener notificationClickListener; diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java index 1c896770..153837e8 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java @@ -9,8 +9,8 @@ import awais.instagrabber.R; import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener; import awais.instagrabber.databinding.ItemNotificationBinding; import awais.instagrabber.models.enums.NotificationType; -import awais.instagrabber.repositories.responses.Notification; -import awais.instagrabber.repositories.responses.NotificationArgs; +import awais.instagrabber.repositories.responses.notification.Notification; +import awais.instagrabber.repositories.responses.notification.NotificationArgs; public final class NotificationViewHolder extends RecyclerView.ViewHolder { private final ItemNotificationBinding binding; diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index cae95e09..d9b56ce7 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -2,7 +2,6 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.DialogInterface; -import android.os.AsyncTask; import android.os.Bundle; import android.text.SpannableString; import android.text.Spanned; @@ -37,9 +36,9 @@ import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.requests.StoryViewerOptions; import awais.instagrabber.repositories.responses.FriendshipChangeResponse; import awais.instagrabber.repositories.responses.Media; -import awais.instagrabber.repositories.responses.Notification; -import awais.instagrabber.repositories.responses.NotificationArgs; -import awais.instagrabber.repositories.responses.NotificationImage; +import awais.instagrabber.repositories.responses.notification.Notification; +import awais.instagrabber.repositories.responses.notification.NotificationArgs; +import awais.instagrabber.repositories.responses.notification.NotificationImage; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; diff --git a/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java b/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java index bb7d036c..b5273e35 100644 --- a/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java @@ -2,7 +2,7 @@ package awais.instagrabber.repositories; import java.util.Map; -import awais.instagrabber.repositories.responses.FeedFetchResponse; +import awais.instagrabber.repositories.responses.feed.FeedFetchResponse; import retrofit2.Call; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Media.java b/app/src/main/java/awais/instagrabber/repositories/responses/Media.java index 1a149a66..c11669a8 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Media.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Media.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Objects; import awais.instagrabber.models.enums.MediaItemType; +import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator; import awais.instagrabber.utils.Utils; public class Media implements Serializable { diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java index 5dcdb487..a6339e20 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java @@ -2,6 +2,9 @@ package awais.instagrabber.repositories.responses; import java.util.List; +import awais.instagrabber.repositories.responses.notification.Notification; +import awais.instagrabber.repositories.responses.notification.NotificationCounts; + public class NewsInboxResponse { private final NotificationCounts counts; private final List newStories; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedDemarcator.java b/app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedDemarcator.java similarity index 94% rename from app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedDemarcator.java rename to app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedDemarcator.java index 44b9936d..2408bc89 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedDemarcator.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedDemarcator.java @@ -1,4 +1,4 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.feed; import java.io.Serializable; import java.util.Objects; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedGroup.java b/app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedGroup.java similarity index 92% rename from app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedGroup.java rename to app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedGroup.java index 43384a41..e675691e 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedGroup.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedGroup.java @@ -1,9 +1,11 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.feed; import java.io.Serializable; import java.util.List; import java.util.Objects; +import awais.instagrabber.repositories.responses.Media; + public class EndOfFeedGroup implements Serializable { private final String id; private final String title; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedGroupSet.java b/app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedGroupSet.java similarity index 97% rename from app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedGroupSet.java rename to app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedGroupSet.java index 3da29e03..cfda0f39 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/EndOfFeedGroupSet.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/feed/EndOfFeedGroupSet.java @@ -1,4 +1,4 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.feed; import java.io.Serializable; import java.util.List; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/FeedFetchResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/feed/FeedFetchResponse.java similarity index 90% rename from app/src/main/java/awais/instagrabber/repositories/responses/FeedFetchResponse.java rename to app/src/main/java/awais/instagrabber/repositories/responses/feed/FeedFetchResponse.java index 2d91a9f7..9d8659af 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/FeedFetchResponse.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/feed/FeedFetchResponse.java @@ -1,7 +1,9 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.feed; import java.util.List; +import awais.instagrabber.repositories.responses.Media; + public class FeedFetchResponse { private final List items; private final int numResults; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Notification.java b/app/src/main/java/awais/instagrabber/repositories/responses/notification/Notification.java similarity index 91% rename from app/src/main/java/awais/instagrabber/repositories/responses/Notification.java rename to app/src/main/java/awais/instagrabber/repositories/responses/notification/Notification.java index c784d52b..6da18866 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Notification.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/notification/Notification.java @@ -1,4 +1,4 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.notification; import awais.instagrabber.models.enums.NotificationType; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationArgs.java similarity index 97% rename from app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java rename to app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationArgs.java index 87116896..27fde081 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationArgs.java @@ -1,4 +1,4 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.notification; import androidx.annotation.NonNull; @@ -7,8 +7,6 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import android.util.Log; - import awais.instagrabber.utils.Utils; public class NotificationArgs { diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java similarity index 95% rename from app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java rename to app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java index 38fb70f9..10074f70 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationCounts.java @@ -1,4 +1,4 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.notification; import androidx.annotation.NonNull; diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationImage.java similarity index 84% rename from app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java rename to app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationImage.java index 3ba92ce2..e3d31bc9 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/notification/NotificationImage.java @@ -1,4 +1,4 @@ -package awais.instagrabber.repositories.responses; +package awais.instagrabber.repositories.responses.notification; public class NotificationImage { private final String id; diff --git a/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java b/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java index 5160f9aa..1845188e 100644 --- a/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java +++ b/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java @@ -18,13 +18,11 @@ import java.util.List; import awais.instagrabber.R; import awais.instagrabber.activities.MainActivity; -import awais.instagrabber.repositories.responses.NotificationCounts; +import awais.instagrabber.repositories.responses.notification.NotificationCounts; import awais.instagrabber.utils.Constants; import awais.instagrabber.webservices.NewsService; import awais.instagrabber.webservices.ServiceCallback; -import static awais.instagrabber.utils.Utils.settingsHelper; - public class ActivityCheckerService extends Service { private static final String TAG = "ActivityCheckerService"; private static final int INITIAL_DELAY_MILLIS = 200; diff --git a/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java index 59a8bb64..1e3e9845 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java @@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModel; import java.util.List; -import awais.instagrabber.repositories.responses.Notification; +import awais.instagrabber.repositories.responses.notification.Notification; public class NotificationViewModel extends ViewModel { private MutableLiveData> list; diff --git a/app/src/main/java/awais/instagrabber/webservices/FeedService.java b/app/src/main/java/awais/instagrabber/webservices/FeedService.java index 2bd91690..3496f8b7 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FeedService.java +++ b/app/src/main/java/awais/instagrabber/webservices/FeedService.java @@ -12,10 +12,10 @@ import java.util.Map; import java.util.UUID; import awais.instagrabber.repositories.FeedRepository; -import awais.instagrabber.repositories.responses.EndOfFeedDemarcator; -import awais.instagrabber.repositories.responses.EndOfFeedGroup; -import awais.instagrabber.repositories.responses.EndOfFeedGroupSet; -import awais.instagrabber.repositories.responses.FeedFetchResponse; +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; diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index fe54c13d..5eec9e8c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -1,35 +1,24 @@ package awais.instagrabber.webservices; -import android.util.Log; - import androidx.annotation.NonNull; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; -import awais.instagrabber.BuildConfig; -import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.repositories.NewsRepository; import awais.instagrabber.repositories.responses.AymlResponse; import awais.instagrabber.repositories.responses.AymlUser; -import awais.instagrabber.repositories.responses.NotificationCounts; +import awais.instagrabber.repositories.responses.notification.NotificationCounts; import awais.instagrabber.repositories.responses.UserSearchResponse; import awais.instagrabber.repositories.responses.NewsInboxResponse; -import awais.instagrabber.repositories.responses.Notification; -import awais.instagrabber.repositories.responses.NotificationArgs; -import awais.instagrabber.repositories.responses.NotificationImage; +import awais.instagrabber.repositories.responses.notification.Notification; +import awais.instagrabber.repositories.responses.notification.NotificationArgs; import awais.instagrabber.repositories.responses.User; import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; From 0f996f88ba5ae7d503c963e5e6a4129b454f454a Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 15:33:43 -0400 Subject: [PATCH 07/12] remove avatar from hashtag avatars don't exist on app api, and there's no pattern... so bye bye --- .../instagrabber/fragments/HashTagFragment.java | 6 +++--- .../repositories/responses/Hashtag.java | 7 ------- app/src/main/res/drawable/ic_hashtag.png | Bin 0 -> 5581 bytes 3 files changed, 3 insertions(+), 10 deletions(-) create mode 100644 app/src/main/res/drawable/ic_hashtag.png diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 75e72949..9b684c68 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -474,7 +474,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe hashtag, FavoriteType.HASHTAG, hashtagModel.getName(), - hashtagModel.getProfilePicUrl(), + "res:/" + R.drawable.ic_hashtag, result.getDateAdded() ), new RepositoryCallback() { @Override @@ -518,7 +518,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe hashtag, FavoriteType.HASHTAG, hashtagModel.getName(), - hashtagModel.getProfilePicUrl(), + "res:/" + R.drawable.ic_hashtag, new Date() ), new RepositoryCallback() { @Override @@ -533,7 +533,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe }); } })); - hashtagDetailsBinding.mainHashtagImage.setImageURI(hashtagModel.getProfilePicUrl()); + hashtagDetailsBinding.mainHashtagImage.setImageURI("res:/" + R.drawable.ic_hashtag); final String postCount = String.valueOf(hashtagModel.getMediaCount()); final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, hashtagModel.getMediaCount() > 2000000000L diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java b/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java index aca5daad..17bc3c63 100755 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java @@ -9,16 +9,13 @@ public final class Hashtag implements Serializable { private final long mediaCount; private final String id; private final String name; - private final String profilePicUrl; // on app API this is always null (property exists) public Hashtag(final String id, final String name, - final String profilePicUrl, final long mediaCount, final FollowingType following) { this.id = id; this.name = name; - this.profilePicUrl = profilePicUrl; this.mediaCount = mediaCount; this.following = following; } @@ -31,10 +28,6 @@ public final class Hashtag implements Serializable { return name; } - public String getProfilePicUrl() { - return profilePicUrl; - } - public Long getMediaCount() { return mediaCount; } diff --git a/app/src/main/res/drawable/ic_hashtag.png b/app/src/main/res/drawable/ic_hashtag.png new file mode 100644 index 0000000000000000000000000000000000000000..ce135fc079765faebf645e16ded7f974b8f89a8d GIT binary patch literal 5581 zcmV;;6*B6HP)Px~hepAwRVk?^XNX+-KWYvNliVb>eM;E@3(*FcYf!0PNke=r|K0eR@B^d(@kTqy6URBOD?%& za#dB;h;%w#qiv+NQQB%#snjUMaPi{B&Yqs0GYvPhu$r)ulMRF(48SehB&$w zx^bTf5W1Z|e;%@US#i(dbLY@r7M!QBrV zHmqRa^Q{&{IeYf3^W%>{x|=kHt4VbI+z&te(7b>D{#6YP4SSVuPriAV>;5t9k@=fUh2cO9n_0$Aqy8Db!PO zNur)hyNuD_&z?Q|J==(36CtX0?AS5)nrp6EDI!e3E*Lp-q-z(%kpz8}8GGZzi4(5P zA!2kKJ9g|3GiT1+toyAnLTw;K>aDlls+X_eb%=mnP*YRm+6H|IH3`?THM+XGTzdmz z$j9;9dGqG&R^7^KW0aK;FTC)=)sH;#$luj7XrO73c5vt={E`yA6ln>!DbaE38*jYv zUy{qIa><}vgs5t3Yg=4fTl+Wl7^+8&8s!>`o4E?YL*E=#oR>%z5A;W$iiR@oR*AS~$ubwz<+O+rNT$+eh z7(RS>WQG4FWOU}t8CP4#sdZr2u3h&mUcC4~G3#AaLdd~%uLhsC&_s+GGsYcgDrRMp znm2=LM~)nEn-C42$)7cQd$HXZBMHQ@h5r_bSZ5gcgPocpKR&DS8Ru;bhbJ$X^r~^t9d(*+5y8ghNYibn)5XJm}5kvX#0^+ibS*2Xyb=HdumBUVDYP^N5dyzD?r3k2s^VuTRQ%CB2L{-1 zU;;LUj(rqjnWh+QQDoB-3V^M+qocz#lALgJE0C8+taa*+E>fm>c{B6Y5Da0ftMdeG zWD-mz*(Cum0UIy^t9(nB7a<64A)W!tmiDTW?34i5fDu@MSw5xAhY(dnI?+Z|jL3XM zT%LQu2&}+NB^Y!_+Mo$R3?yN1sG~TJTrx1UY}qpB&O7gPG*QO+^wUp`k@E7?tTIPN zob&O=9~ayGY_up?^k$2vC zCz~I6N0Fy-p#m9z8Q6j0U`R0-4Ur;Lp6KW}JD(J=nj;U*oXR;bScb6&_vFwcn-Cl-=TQJ(>`j6Ko7 zgs6dDHV`4IB)C>}VPZXRLR!?3+RTx~lqpkk&I>syMxKR~W1wf4DG!Fsj?=yU8kqeO zg1MGr*aT)&#W~SDFh$>=CQqL1Kh67C;qmU|UH^lodHVB;`WOts5={HcyFWstnRv@w zOEnq&l?e>N5=>RVK5_5!A56)IQE@gTJ!HbbGbKbA z$!yjT$O0_E6l^`&1owRrBF*{?Ovz``NZeBpJk2R}ml`msSCC{QMvQR#{U&)9`&qCA zQ?S*$La`6M$jU8ZQXT6vBq0UCi$b*rNoKot@NfiEumxl9ntvZgh!o5CV3oqAxF;6q z`1Z`AE9y4u%axyF837CQ{80$5?{1Uwg!2(~b>6DakIDW}= zJN?O2Luhf2>~e%&zH!kIloxEl7_7bWd;4C5V6`{=;0oOI?uqrjy}i9x`As!MunFP? zaUulRf-zVJg%c!1TJe$3dJhC|j^lX{JpD2pQ!i!Eeo&k2+zHcWH;P!L+pZuz!CE>gs74ys|n^LC1|$dvi3urdkn^44d(h!c6=jC2o@68O+#^SCM5-b z$<)jA*BopvqR6vc@&;=#2Yas!SwgU?JgiBAXVR4B;e0jmW44ho+)~)N6=gTj@ zocF*MhUlzWvwG!K$_ro(=3uY)uHxM;`h0w3{rdIiqVVxYS)mtSe9>96W=)h?T9wzL zMT?y0pMSorWn!6St&8a_Sg>HIBEZhOO$J}0p;WfHs$YBUwXzDU*e|!Cejer?2V6q% zSt6Vjw#7YMcinZx#-yzIv%W*Q6PSZN9H1;NA=D?G?im>6E};MY`j!=gF#b!4Ii_Ar z3n+KOj(`+!fU>worKW$~jZ4?Iq`8R>MrFQ<`Hi&C`if2VQQXTLHf(Tizy0>?wR{f9 zQ)@&z{^)IlsVaA#danbV@~$rwwxUen4;`%|}itly}jF0-BZ~ z%w=slwIMBVGkG53YMs&Ei@eg%%=dwzBl+w=6$BW=CC|X-QdNR!(j6VdpH0W z(&}AI#-QXvQc|$FpkAf{EXByv7I}j`9DoaH8A^Ny+m^CLQjX6*|2!ujCaIVP3S9Ea2*LL;gHhI| z;1Okg;J|?#{7h|!*5MO-pMXxApQ{yiz%G$KoVgUzoiU0?+!G&}! zCrL?R#-Ax6f;I`VN}`5vxga%>C=C&8>#?4RJupc@n*@)gY2>y^d5ZBYO2OqqF)}Y_ zo3S=VB`J1sYFC!g<0Lc(Po{56|47sw@;XVUBk>IetmLRtsM zlR}6vm$hjR9sIO((DJ15O4uPBt}C7n+qyxsv&~ffjpC{A>aapIH8St#y*Ah zFibT>(0)Kj3DyuNAVgPE2oVG?3YT?IL*TMb;!3`704}8U(eaZ>B}5cm!%sf>Bu8_a z&g;m@%%T%G02iv|mffe%2)o`r^+U^AL}CuMZQJHB{~_Omb~t?aaL!|ZxpL*of`f-? zf`V>vChFvyCy~wf-FF|0k>`}pmJ@nsZ~!i(wB+wyV*PHMH|310#F~HTp@(`|^tK4i zv>Ytb@#dRvIyOdoJseQkx?L;sqmMq?popURn!RIVc?T>LUBd?-d@$!eLhe_sT2=5G-K=aMoQ!+h zZMQkEyz)xHdFB+*q7w|~lP6DZl*}G?$G!Fa=r)2tur}kE_yq>j0}ni41YDSbZJKAW zj5eHu`Ps8)`G$BK<#7q2F@PQPL-|J>Q<%%z)SDRQ^-QA68qC2S4uHK&2+g5%*X}E% z|8E0HeFbkvkQZA)N{5&(OzY*|8dbad?G28_!%rLZV#Q}B>MFv{9APa9?G zbtJ&vD_@on>L>qOgg6)c@{D(*t^2SjYf}w@#=+3?C(}IrdD(Id)?g0yUYW9l(1i=S zq51Ub)3Itcf~uX0nf{u?j8xM+J%QV@r!@d;Fjtu_c;)gF!r8xn|ElipZns_WZm@kH z1TTsx>tLRl6<=)^MPB8@b^vQI_dl3Jh=zuSy;7A&U`||8P(u)}U>ao|%#(#dk``qR z#$XNReyno{p?~zq;#`KI7HmWP57}~z+ABs6Bd8&gW7DC?kxOq%`R{ouhmh-)uGG&MCHm7`)eJ*Lx3$9gEjT@ zr(T56KQC&eZz)EH=hpN;VAF9JAxyyw%hQx(HpvW3!4{0cI#{+aLNIRsF9lq-v+S+S zDF|LA%6ee5z!Yr3IPC6FLg>aGwa>qYO*VTji(ya($3;v>O~ZsbwI=Z^t2)nRn%X$sNh#(e!G6fHT$&KsJGEw#eSb{0o=2X&m(kCHwPtUPq z$NqqO)5bUnT-L#48m|!MvQCQq0ES=*reGVCop;_JA)J{rXKsd3%EY_hntf2UQ!rBv zk>nl*7=k63_6K6WgwTT*6q@~8tkPiLyuVCK@juw^Pb}U(apFY(rM!=Wy(-+`QOy3z zyC4xi0Cr#qmdZLiZV~pHfe7Kun>TN_)J@(? zVEgdH569kR4Q5~mhG01mSh=ft_i?x8Ol-UL)?1&Jt2k}TN7|SPMOZuYIUalLG3UuA zpEO>4m9Ny1C*4;Fwq(f?_gfNuh$R-6`C5)NU-#>;zy6yYJ9Z2h?Ba&u52j{qZEa6! z*7HC3&I9VXlI)iNy(W5M(hy6gPoJJMs@YfR2TcfNQ1!n`nz&jwZrr%o|8n{gNK&pd z9>shMX@_=c_ghu3LACb-+7LbgUC_rvW~nXep-rkJyCsmZ8+yP@B^?wQs8K!|!j-_z zojdkSyvTrj3LymR9Gu;?Yu7#46Gx98ja5)?Qb|Gd7+8P_*nm+XbuFaH$i8RG zmM!<{yV2Y9sbIJ7p8ZGVpyU$3HLZ|12Iub6;MMj*3s8`T@LtA?Wz9BH5L-t@y|N~G zkLNCb6pHdh%8NQeGP%zj^K`SKw`H|n>KB^>SWwZ_~lXzLXdw-qoa?D3@x~~X+o0p87IF0 zOLdIX39W$LKyM;rKt@Ui7r0_pDC4KtGHlqeG{$Dd&0UzZaYy5U#OWkIgL;;Q`xyo* zL6kN`uXj=K_uqg2Mh(Fpz`qW=D=9w-ATwl#43T9q$&g>k4DOyYXU;HsAPQo=s1dk} z3hPpHSV{d!02v`GWQOdJp#cPgezaINL|6e*8ai*#(D{0r5bTOd$mDthjsKqYHDiu=5$!uesR|bh|PE%-RX7& zw=7(^@L(wgQF20LDp#dm$l}`C+P`UWk7~N61i1c^6QS~SDYdFgw*q5-r(VQr$z#xw zPEpCOTtCf=S~L1X5n`pjt2s%*p#LGG$!$VRSAU60Fr~^z&4Sy5z_%bdv=SXHt?<6y zUy>#wSkH242!AKCwl_tcrs_B?Om_N-(((MZ(qG=wOaHOW9Lu)-XXaV>CDHjnu zKx`m{SC%Tx8vEIs;NnsS^>}nUXJ`!h5Q8B!g0(@J#nM62hxfdh_PZ zzaBq+{0hyntcMJc0^<{s*gifYAA<`%#v){Z6fEN-C)3i*VjWfy!4ta8gvge$xw(1t z)TvV&)J=U>#2AC&2{EuYur+KU2PD8Yz%GCYtOF?`9Ff7ej0L_jYdV$1SoDNB&^``? z@Yf;T+S)or2Ix~FLz9Rw6f$6Epf%Xb=~XgI6g0CAq?Ovh zFIew5ZiMj4&AzIorDc+Wd}l~=%vZB=FBfTA&>BqTXE4p%&?<#$5Ub2-3-nHbeOz0oj!&vLa6(&`?1FvjA++;d%gkpjyZd-w b>@WWxdE}tdsP|`K00000NkvXXu0mjfw{f|C literal 0 HcmV?d00001 From 1cee2cd4c07cd34ce460f5183f42f6c290d01b46 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 16:48:35 -0400 Subject: [PATCH 08/12] improve search 1. separate logged-in and anonymous endpoints 2. migrate to retrofit + gson, retire SuggestionsFetcher 3. prefixing search with @ or # will only return users or hashtags, respectively 4. add subtitles for locations (address) and hashtags (rough post count) --- .../instagrabber/activities/MainActivity.java | 113 ++++++++++++------ .../adapters/SuggestionsAdapter.java | 26 ++-- .../asyncs/SuggestionsFetcher.java | 113 ------------------ .../repositories/SearchRepository.java | 15 +++ .../repositories/responses/Hashtag.java | 11 +- .../repositories/responses/search/Place.java | 36 ++++++ .../responses/search/SearchItem.java | 39 ++++++ .../responses/search/SearchResponse.java | 48 ++++++++ .../webservices/GraphQLService.java | 4 +- .../webservices/SearchService.java | 50 ++++++++ 10 files changed, 283 insertions(+), 172 deletions(-) delete mode 100755 app/src/main/java/awais/instagrabber/asyncs/SuggestionsFetcher.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/SearchRepository.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/search/SearchResponse.java create mode 100644 app/src/main/java/awais/instagrabber/webservices/SearchService.java diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 8328d3c3..e279b54e 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -11,7 +11,6 @@ import android.content.ServiceConnection; import android.content.res.TypedArray; import android.database.MatrixCursor; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -57,21 +56,22 @@ import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import awais.instagrabber.R; import awais.instagrabber.adapters.SuggestionsAdapter; import awais.instagrabber.asyncs.PostFetcher; -import awais.instagrabber.asyncs.SuggestionsFetcher; import awais.instagrabber.customviews.emoji.EmojiVariantManager; import awais.instagrabber.databinding.ActivityMainBinding; import awais.instagrabber.fragments.PostViewV2Fragment; import awais.instagrabber.fragments.directmessages.DirectMessageInboxFragmentDirections; import awais.instagrabber.fragments.main.FeedFragment; import awais.instagrabber.fragments.settings.PreferenceKeys; -import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.IntentModel; import awais.instagrabber.models.SuggestionModel; import awais.instagrabber.models.enums.SuggestionType; +import awais.instagrabber.repositories.responses.search.SearchItem; +import awais.instagrabber.repositories.responses.search.SearchResponse; import awais.instagrabber.services.ActivityCheckerService; import awais.instagrabber.services.DMSyncAlarmReceiver; import awais.instagrabber.utils.AppExecutors; @@ -83,6 +83,10 @@ import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.emoji.EmojiParser; import awais.instagrabber.viewmodels.AppStateViewModel; +import awais.instagrabber.webservices.SearchService; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -105,6 +109,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage private SuggestionsAdapter suggestionAdapter; private AutoCompleteTextView searchAutoComplete; private SearchView searchView; + private SearchService searchService; private boolean showSearch = true; private Handler suggestionsFetchHandler; private int firstFragmentGraphIndex; @@ -175,6 +180,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage EmojiVariantManager.getInstance(); }); initEmojiCompat(); + searchService = SearchService.getInstance(); // initDmService(); } @@ -338,51 +344,84 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { private boolean searchUser; private boolean searchHash; - private AsyncTask prevSuggestionAsync; + private Call prevSuggestionAsync; private final String[] COLUMNS = { BaseColumns._ID, Constants.EXTRAS_USERNAME, Constants.EXTRAS_NAME, Constants.EXTRAS_TYPE, + "query", "pfp", "verified" }; private String currentSearchQuery; - private final FetchListener fetchListener = new FetchListener() { + private final Callback cb = new Callback() { @Override - public void doBefore() { - suggestionAdapter.changeCursor(null); - } - - @Override - public void onResult(final SuggestionModel[] result) { + public void onResponse(@NonNull final Call call, + @NonNull final Response response) { final MatrixCursor cursor; - if (result == null) cursor = null; + final SearchResponse body = response.body(); + if (body == null) { + cursor = null; + return; + } + final List result = new ArrayList(); + if (isLoggedIn) { + if (body.getList() != null) result.addAll(searchHash ? body.getList() + .stream() + .filter(i -> i.getUser() == null) + .collect(Collectors.toList()) : body.getList()); + } else { - cursor = new MatrixCursor(COLUMNS, 0); - for (int i = 0; i < result.length; i++) { - final SuggestionModel suggestionModel = result[i]; - if (suggestionModel != null) { - final SuggestionType suggestionType = suggestionModel.getSuggestionType(); - final Object[] objects = { - i, - suggestionType == SuggestionType.TYPE_LOCATION ? suggestionModel.getName() : suggestionModel.getUsername(), - suggestionType == SuggestionType.TYPE_LOCATION ? suggestionModel.getUsername() : suggestionModel.getName(), - suggestionType, - suggestionModel.getProfilePic(), - suggestionModel.isVerified()}; - if (!searchHash && !searchUser) cursor.addRow(objects); - else { - final boolean isCurrHash = suggestionType == SuggestionType.TYPE_HASHTAG; - if (searchHash && isCurrHash || !searchHash && !isCurrHash) - cursor.addRow(objects); - } - } + if (body.getUsers() != null && !searchHash) result.addAll(body.getUsers()); + if (body.getHashtags() != null) result.addAll(body.getHashtags()); + if (body.getPlaces() != null) result.addAll(body.getPlaces()); + } + cursor = new MatrixCursor(COLUMNS, 0); + for (int i = 0; i < result.size(); i++) { + final SearchItem suggestionModel = result.get(i); + if (suggestionModel != null) { + Object[] objects = null; + if (suggestionModel.getUser() != null) + objects = new Object[]{ + suggestionModel.getPosition(), + suggestionModel.getUser().getUsername(), + suggestionModel.getUser().getFullName(), + SuggestionType.TYPE_USER, + suggestionModel.getUser().getUsername(), + suggestionModel.getUser().getProfilePicUrl(), + suggestionModel.getUser().isVerified()}; + else if (suggestionModel.getHashtag() != null) + objects = new Object[]{ + suggestionModel.getPosition(), + suggestionModel.getHashtag().getName(), + suggestionModel.getHashtag().getSubtitle(), + SuggestionType.TYPE_HASHTAG, + suggestionModel.getHashtag().getName(), + "res:/" + R.drawable.ic_hashtag, + false}; + else if (suggestionModel.getPlace() != null) + objects = new Object[]{ + suggestionModel.getPosition(), + suggestionModel.getPlace().getTitle(), + suggestionModel.getPlace().getSubtitle(), + SuggestionType.TYPE_LOCATION, + suggestionModel.getPlace().getLocation().getPk(), + "res:/" + R.drawable.ic_location, + false}; + cursor.addRow(objects); } } suggestionAdapter.changeCursor(cursor); } + + @Override + public void onFailure(@NonNull final Call call, + Throwable t) { + if (!call.isCanceled() && t != null) + Log.e(TAG, "Exception on search:", t); + } }; private final Runnable runnable = () -> { @@ -401,17 +440,19 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage if (searchAutoComplete != null) { searchAutoComplete.setThreshold(1); } - prevSuggestionAsync = new SuggestionsFetcher(fetchListener).executeOnExecutor( - AsyncTask.THREAD_POOL_EXECUTOR, - searchUser || searchHash ? currentSearchQuery.substring(1) - : currentSearchQuery); + prevSuggestionAsync = searchService.search(isLoggedIn, + searchUser || searchHash ? currentSearchQuery.substring(1) + : currentSearchQuery, + searchUser ? "user" : (searchHash ? "hashtag" : "blended")); + suggestionAdapter.changeCursor(null); + prevSuggestionAsync.enqueue(cb); } }; private void cancelSuggestionsAsync() { if (prevSuggestionAsync != null) try { - prevSuggestionAsync.cancel(true); + prevSuggestionAsync.cancel(); } catch (final Exception ignored) {} } diff --git a/app/src/main/java/awais/instagrabber/adapters/SuggestionsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/SuggestionsAdapter.java index 154e83f2..6c4fa4c7 100755 --- a/app/src/main/java/awais/instagrabber/adapters/SuggestionsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/SuggestionsAdapter.java @@ -35,12 +35,12 @@ public final class SuggestionsAdapter extends CursorAdapter { @Override public void bindView(@NonNull final View view, final Context context, @NonNull final Cursor cursor) { - // i, username, fullname, type, picUrl, verified - // 0, 1 , 2 , 3 , 4 , 5 + // i, username, fullname, type, query, picUrl, verified + // 0, 1 , 2 , 3 , 4 , 5 , 6 final String fullName = cursor.getString(2); String username = cursor.getString(1); - String picUrl = cursor.getString(4); - final boolean verified = cursor.getString(5).charAt(0) == 't'; + String picUrl = cursor.getString(5); + final boolean verified = cursor.getString(6).charAt(0) == 't'; final String type = cursor.getString(3); SuggestionType suggestionType = null; @@ -50,22 +50,14 @@ public final class SuggestionsAdapter extends CursorAdapter { Log.e(TAG, "Unknown suggestion type: " + type, e); } if (suggestionType == null) return; - final String query; + String query = cursor.getString(4); switch (suggestionType) { case TYPE_USER: username = '@' + username; - query = username; break; case TYPE_HASHTAG: username = '#' + username; - query = username; break; - case TYPE_LOCATION: - query = fullName; - picUrl = "res:/" + R.drawable.ic_location; - break; - default: - return; // will never come here } if (onSuggestionClickListener != null) { @@ -75,12 +67,8 @@ public final class SuggestionsAdapter extends CursorAdapter { final ItemSuggestionBinding binding = ItemSuggestionBinding.bind(view); binding.isVerified.setVisibility(verified ? View.VISIBLE : View.GONE); binding.tvUsername.setText(username); - if (suggestionType.equals(SuggestionType.TYPE_LOCATION)) { - binding.tvFullName.setVisibility(View.GONE); - } else { - binding.tvFullName.setVisibility(View.VISIBLE); - binding.tvFullName.setText(fullName); - } + binding.tvFullName.setVisibility(View.VISIBLE); + binding.tvFullName.setText(fullName); binding.ivProfilePic.setImageURI(picUrl); } diff --git a/app/src/main/java/awais/instagrabber/asyncs/SuggestionsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/SuggestionsFetcher.java deleted file mode 100755 index c40d0406..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/SuggestionsFetcher.java +++ /dev/null @@ -1,113 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.io.InterruptedIOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.models.SuggestionModel; -import awais.instagrabber.models.enums.SuggestionType; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.NetworkUtils; -import awais.instagrabber.utils.UrlEncoder; - -public final class SuggestionsFetcher extends AsyncTask { - private final FetchListener fetchListener; - - public SuggestionsFetcher(final FetchListener fetchListener) { - this.fetchListener = fetchListener; - } - - @Override - protected void onPreExecute() { - if (fetchListener != null) fetchListener.doBefore(); - } - - @Override - protected SuggestionModel[] doInBackground(final String... params) { - SuggestionModel[] result = null; - try { - final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/web/search/topsearch/?context=blended&count=50&query=" - + UrlEncoder.encodeUrl(params[0])).openConnection(); - conn.setUseCaches(false); - conn.connect(); - - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - final JSONObject jsonObject = new JSONObject(NetworkUtils.readFromConnection(conn)); - conn.disconnect(); - - final JSONArray usersArray = jsonObject.getJSONArray("users"); - final JSONArray hashtagsArray = jsonObject.getJSONArray("hashtags"); - final JSONArray placesArray = jsonObject.getJSONArray("places"); - - final int usersLen = usersArray.length(); - final int hashtagsLen = hashtagsArray.length(); - final int placesLen = placesArray.length(); - - final ArrayList suggestionModels = new ArrayList<>(usersLen + hashtagsLen); - for (int i = 0; i < hashtagsLen; i++) { - final JSONObject hashtagsArrayJSONObject = hashtagsArray.getJSONObject(i); - - final JSONObject hashtag = hashtagsArrayJSONObject.getJSONObject("hashtag"); - - suggestionModels.add(new SuggestionModel(false, - hashtag.getString(Constants.EXTRAS_NAME), - null, - hashtag.optString("profile_pic_url", Constants.DEFAULT_HASH_TAG_PIC), - SuggestionType.TYPE_HASHTAG, - hashtagsArrayJSONObject.optInt("position", suggestionModels.size() - 1))); - } - - for (int i = 0; i < placesLen; i++) { - final JSONObject placesArrayJSONObject = placesArray.getJSONObject(i); - - final JSONObject place = placesArrayJSONObject.getJSONObject("place"); - - // name - suggestionModels.add(new SuggestionModel(false, - place.getJSONObject("location").getString("pk"), // +"/"+place.getString("slug"), - place.getString("title"), - place.optString("profile_pic_url"), - SuggestionType.TYPE_LOCATION, - placesArrayJSONObject.optInt("position", suggestionModels.size() - 1))); - } - - for (int i = 0; i < usersLen; i++) { - final JSONObject usersArrayJSONObject = usersArray.getJSONObject(i); - - final JSONObject user = usersArrayJSONObject.getJSONObject(Constants.EXTRAS_USER); - - suggestionModels.add(new SuggestionModel(user.getBoolean("is_verified"), - user.getString(Constants.EXTRAS_USERNAME), - user.getString("full_name"), - user.getString("profile_pic_url"), - SuggestionType.TYPE_USER, - usersArrayJSONObject.optInt("position", suggestionModels.size() - 1))); - } - - suggestionModels.trimToSize(); - - Collections.sort(suggestionModels); - - result = suggestionModels.toArray(new SuggestionModel[0]); - } - } catch (final Exception e) { - if (BuildConfig.DEBUG && !(e instanceof InterruptedIOException)) Log.e("AWAISKING_APP", "", e); - } - return result; - } - - @Override - protected void onPostExecute(final SuggestionModel[] result) { - if (fetchListener != null) fetchListener.onResult(result); - } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java b/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java new file mode 100644 index 00000000..7dda390d --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/SearchRepository.java @@ -0,0 +1,15 @@ +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; +import retrofit2.http.Url; + +public interface SearchRepository { + @GET + Call search(@Url String url, @QueryMap(encoded = true) Map queryParams); +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java b/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java index 17bc3c63..2ce08eb5 100755 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Hashtag.java @@ -5,19 +5,22 @@ import java.io.Serializable; import awais.instagrabber.models.enums.FollowingType; public final class Hashtag implements Serializable { - private final FollowingType following; // 0 false 1 true + private final FollowingType following; // 0 false 1 true; not on search results private final long mediaCount; private final String id; private final String name; + private final String searchResultSubtitle; // shows how many posts there are on search results public Hashtag(final String id, final String name, final long mediaCount, - final FollowingType following) { + final FollowingType following, + final String searchResultSubtitle) { this.id = id; this.name = name; this.mediaCount = mediaCount; this.following = following; + this.searchResultSubtitle = searchResultSubtitle; } public String getId() { @@ -35,4 +38,8 @@ public final class Hashtag implements Serializable { public FollowingType getFollowing() { return following; } + + public String getSubtitle() { + return searchResultSubtitle; + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java b/app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java new file mode 100644 index 00000000..e4a44646 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java @@ -0,0 +1,36 @@ +package awais.instagrabber.repositories.responses.search; + +import awais.instagrabber.repositories.responses.Location; + +public class Place { + private final Location location; + private final String title; // those are repeated within location + private final String subtitle; // address + private final String slug; // browser only; for end of address + + public Place(final Location location, + final String title, + final String subtitle, + final String slug) { + this.location = location; + this.title = title; + this.subtitle = subtitle; + this.slug = slug; + } + + public Location getLocation() { + return location; + } + + public String getTitle() { + return title; + } + + public String getSubtitle() { + return subtitle; + } + + public String getSlug() { + return slug; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java new file mode 100644 index 00000000..52749321 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java @@ -0,0 +1,39 @@ +package awais.instagrabber.repositories.responses.search; + +import java.util.List; + +import awais.instagrabber.repositories.responses.Hashtag; +import awais.instagrabber.repositories.responses.User; + +public class SearchItem { + private final User user; + private final Place place; + private final Hashtag hashtag; + private final int position; + + public SearchItem(final User user, + final Place place, + final Hashtag hashtag, + final int position) { + this.user = user; + this.place = place; + this.hashtag = hashtag; + this.position = position; + } + + public User getUser() { + return user; + } + + public Place getPlace() { + return place; + } + + public Hashtag getHashtag() { + return hashtag; + } + + public int getPosition() { + return position; + } +} 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 new file mode 100644 index 00000000..04db0286 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchResponse.java @@ -0,0 +1,48 @@ +package awais.instagrabber.repositories.responses.search; + +import java.util.List; + +import awais.instagrabber.repositories.responses.User; + +public class SearchResponse { + // app + private final List list; + // browser + private final List users; + private final List places; + private final List hashtags; + // universal + private final String status; + + public SearchResponse(final List list, + final List users, + final List places, + final List hashtags, + final String status) { + this.list = list; + this.users = users; + this.places = places; + this.hashtags = hashtags; + this.status = status; + } + + public List getList() { + return list; + } + + public List getUsers() { + return users; + } + + public List getPlaces() { + return places; + } + + public List getHashtags() { + return hashtags; + } + + public String getStatus() { + return status; + } +} diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index 4cd1c1b6..b373b3c8 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -394,9 +394,9 @@ public class GraphQLService extends BaseService { callback.onSuccess(new Hashtag( body.getString(Constants.EXTRAS_ID), body.getString("name"), - body.getString("profile_pic_url"), timelineMedia.getLong("count"), - body.optBoolean("is_following") ? FollowingType.FOLLOWING : FollowingType.NOT_FOLLOWING)); + body.optBoolean("is_following") ? FollowingType.FOLLOWING : FollowingType.NOT_FOLLOWING, + null)); } catch (JSONException e) { Log.e(TAG, "onResponse", e); if (callback != null) { diff --git a/app/src/main/java/awais/instagrabber/webservices/SearchService.java b/app/src/main/java/awais/instagrabber/webservices/SearchService.java new file mode 100644 index 00000000..39b5bd65 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/webservices/SearchService.java @@ -0,0 +1,50 @@ +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"; + + private final SearchRepository repository; + + private static SearchService instance; + + private SearchService() { + final Retrofit retrofit = getRetrofitBuilder() + .baseUrl("https://www.instagram.com") + .build(); + repository = retrofit.create(SearchRepository.class); + } + + public static SearchService getInstance() { + if (instance == null) { + instance = new SearchService(); + } + return instance; + } + + public Call search(final boolean isLoggedIn, + final String query, + final String context) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put("query", query); + // context is one of: "blended", "user", "place", "hashtag" + // note that "place" and "hashtag" can contain ONE user result, who knows why + 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()); + } +} From fa1f5d2b72818226f763b8b498a9f475899f3a19 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 18:04:45 -0400 Subject: [PATCH 09/12] retire LocationFetcher and enforce consistency --- .../instagrabber/activities/MainActivity.java | 5 +- .../instagrabber/asyncs/LocationFetcher.java | 81 ----------- .../asyncs/LocationPostFetchService.java | 10 +- .../fragments/LocationFragment.java | 135 +++++++++--------- .../instagrabber/models/LocationModel.java | 56 -------- .../instagrabber/models/SuggestionModel.java | 51 ------- .../repositories/GraphQLRepository.java | 3 + .../repositories/LocationRepository.java | 3 + .../repositories/responses/Location.java | 18 +-- .../responses/{search => }/Place.java | 15 +- .../responses/search/SearchItem.java | 3 +- .../webservices/GraphQLService.java | 45 ++++++ .../webservices/LocationService.java | 50 +++---- .../res/layout/layout_location_details.xml | 56 +++----- 14 files changed, 187 insertions(+), 344 deletions(-) delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/LocationFetcher.java delete mode 100755 app/src/main/java/awais/instagrabber/models/LocationModel.java delete mode 100755 app/src/main/java/awais/instagrabber/models/SuggestionModel.java rename app/src/main/java/awais/instagrabber/repositories/responses/{search => }/Place.java (71%) diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index e279b54e..408a841a 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -68,7 +68,6 @@ import awais.instagrabber.fragments.directmessages.DirectMessageInboxFragmentDir import awais.instagrabber.fragments.main.FeedFragment; import awais.instagrabber.fragments.settings.PreferenceKeys; import awais.instagrabber.models.IntentModel; -import awais.instagrabber.models.SuggestionModel; import awais.instagrabber.models.enums.SuggestionType; import awais.instagrabber.repositories.responses.search.SearchItem; import awais.instagrabber.repositories.responses.search.SearchResponse; @@ -316,7 +315,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final Bundle bundle = new Bundle(); switch (type) { case TYPE_LOCATION: - bundle.putString("locationId", query); + bundle.putLong("locationId", Long.valueOf(query)); navController.navigate(R.id.action_global_locationFragment, bundle); break; case TYPE_HASHTAG: @@ -744,7 +743,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage final NavController navController = currentNavControllerLiveData.getValue(); if (navController == null) return; final Bundle bundle = new Bundle(); - bundle.putString("locationId", locationId); + bundle.putLong("locationId", Long.valueOf(locationId)); navController.navigate(R.id.action_global_locationFragment, bundle); } diff --git a/app/src/main/java/awais/instagrabber/asyncs/LocationFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/LocationFetcher.java deleted file mode 100644 index 8aabc107..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/LocationFetcher.java +++ /dev/null @@ -1,81 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import androidx.annotation.Nullable; - -import org.json.JSONObject; - -import java.math.BigDecimal; -import java.net.HttpURLConnection; -import java.net.URL; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.models.LocationModel; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.NetworkUtils; -//import awaisomereport.LogCollector; - -//import static awais.instagrabber.utils.Utils.logCollector; - -public final class LocationFetcher extends AsyncTask { - private static final String TAG = "LocationFetcher"; - - private final FetchListener fetchListener; - private final long id; - - public LocationFetcher(final long id, final FetchListener fetchListener) { - // idSlug = id + "/" + slug UPDATE: slug can be ignored tbh - this.id = id; - this.fetchListener = fetchListener; - } - - @Nullable - @Override - protected LocationModel doInBackground(final Void... voids) { - LocationModel result = null; - - try { - final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/explore/locations/" + id + "/?__a=1") - .openConnection(); - conn.setUseCaches(true); - conn.connect(); - - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - final JSONObject location = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("graphql") - .getJSONObject(Constants.EXTRAS_LOCATION); - - final JSONObject timelineMedia = location.getJSONObject("edge_location_to_media"); - // if (timelineMedia.has("edges")) { - // final JSONArray edges = timelineMedia.getJSONArray("edges"); - // } - result = new LocationModel( - location.getLong(Constants.EXTRAS_ID), - location.getString("name"), - location.getString("blurb"), - location.getString("website"), - location.getString("profile_pic_url"), - timelineMedia.getLong("count"), - BigDecimal.valueOf(location.optDouble("lat", 0d)).toString(), - BigDecimal.valueOf(location.optDouble("lng", 0d)).toString() - ); - } - - conn.disconnect(); - } catch (final Exception e) { -// if (logCollector != null) -// logCollector.appendException(e, LogCollector.LogFile.ASYNC_LOCATION_FETCHER, "doInBackground"); - if (BuildConfig.DEBUG) { - Log.e(TAG, "", e); - } - } - return result; - } - - @Override - protected void onPostExecute(final LocationModel result) { - if (fetchListener != null) fetchListener.onResult(result); - } -} diff --git a/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java index 7613c9d2..274b2314 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java @@ -4,7 +4,7 @@ import java.util.List; import awais.instagrabber.customviews.helpers.PostFetcher; import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.models.LocationModel; +import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.webservices.GraphQLService; @@ -14,12 +14,12 @@ import awais.instagrabber.webservices.ServiceCallback; public class LocationPostFetchService implements PostFetcher.PostFetchService { private final LocationService locationService; private final GraphQLService graphQLService; - private final LocationModel locationModel; + private final Location locationModel; private String nextMaxId; private boolean moreAvailable; private final boolean isLoggedIn; - public LocationPostFetchService(final LocationModel locationModel, final boolean isLoggedIn) { + public LocationPostFetchService(final Location locationModel, final boolean isLoggedIn) { this.locationModel = locationModel; this.isLoggedIn = isLoggedIn; locationService = isLoggedIn ? LocationService.getInstance() : null; @@ -47,8 +47,8 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService { } } }; - if (isLoggedIn) locationService.fetchPosts(locationModel.getId(), nextMaxId, cb); - else graphQLService.fetchLocationPosts(locationModel.getId(), nextMaxId, cb); + if (isLoggedIn) locationService.fetchPosts(locationModel.getPk(), nextMaxId, cb); + else graphQLService.fetchLocationPosts(locationModel.getPk(), nextMaxId, cb); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 24fa4b88..1d834a08 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -3,14 +3,10 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.graphics.Typeface; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; -import android.text.SpannableStringBuilder; -import android.text.style.RelativeSizeSpan; -import android.text.style.StyleSpan; import android.util.Log; import android.view.ActionMode; import android.view.LayoutInflater; @@ -45,7 +41,6 @@ import java.util.Set; import awais.instagrabber.R; import awais.instagrabber.activities.MainActivity; import awais.instagrabber.adapters.FeedAdapterV2; -import awais.instagrabber.asyncs.LocationFetcher; import awais.instagrabber.asyncs.LocationPostFetchService; import awais.instagrabber.asyncs.PostFetcher; import awais.instagrabber.customviews.PrimaryActionModeCallback; @@ -56,23 +51,24 @@ import awais.instagrabber.db.entities.Favorite; import awais.instagrabber.db.repositories.FavoriteRepository; import awais.instagrabber.db.repositories.RepositoryCallback; import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; -import awais.instagrabber.models.LocationModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.FavoriteType; import awais.instagrabber.repositories.requests.StoryViewerOptions; +import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; +import awais.instagrabber.webservices.GraphQLService; +import awais.instagrabber.webservices.LocationService; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesService; //import awaisomereport.LogCollector; import static androidx.core.content.PermissionChecker.checkSelfPermission; -import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; //import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.settingsHelper; @@ -89,9 +85,11 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR private boolean hasStories = false; private boolean opening = false; private long locationId; - private LocationModel locationModel; + private Location locationModel; private ActionMode actionMode; private StoriesService storiesService; + private GraphQLService graphQLService; + private LocationService locationService; private AsyncTask currentlyExecuting; private boolean isLoggedIn; private boolean storiesFetching; @@ -265,12 +263,29 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR } } }; + private final ServiceCallback cb = new ServiceCallback() { + @Override + public void onSuccess(final Location result) { + locationModel = result; + binding.swipeRefreshLayout.setRefreshing(false); + setupLocationDetails(); + } + + @Override + public void onFailure(final Throwable t) { + setupLocationDetails(); + } + }; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); fragmentActivity = (MainActivity) requireActivity(); + final String cookie = settingsHelper.getString(Constants.COOKIE); + isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; + locationService = isLoggedIn ? LocationService.getInstance() : null; storiesService = StoriesService.getInstance(null, 0L, null); + graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); setHasOptionsMenu(true); } @@ -354,8 +369,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR private void init() { if (getArguments() == null) return; - final String cookie = settingsHelper.getString(Constants.COOKIE); - isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; final LocationFragmentArgs fragmentArgs = LocationFragmentArgs.fromBundle(getArguments()); locationId = fragmentArgs.getLocationId(); locationDetailsBinding.favChip.setVisibility(View.GONE); @@ -377,42 +390,38 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR } private void fetchLocationModel() { - stopCurrentExecutor(); binding.swipeRefreshLayout.setRefreshing(true); - currentlyExecuting = new LocationFetcher(locationId, result -> { - locationModel = result; - binding.swipeRefreshLayout.setRefreshing(false); - if (locationModel == null) { - final Context context = getContext(); - if (context == null) return; - Toast.makeText(context, R.string.error_loading_location, Toast.LENGTH_SHORT).show(); - binding.swipeRefreshLayout.setEnabled(false); - return; - } - setTitle(); - setupLocationDetails(); - setupPosts(); - fetchStories(); - // fetchPosts(); - }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (isLoggedIn) locationService.fetch(locationId, cb); + else graphQLService.fetchLocation(locationId, cb); } private void setupLocationDetails() { - final long locationId = locationModel.getId(); + if (locationModel == null) { + try { + Toast.makeText(getContext(), R.string.error_loading_location, Toast.LENGTH_SHORT).show(); + binding.swipeRefreshLayout.setEnabled(false); + } + catch (Exception ignored) {} + return; + } + setTitle(); + setupPosts(); + fetchStories(); + final long locationId = locationModel.getPk(); // binding.swipeRefreshLayout.setRefreshing(true); - locationDetailsBinding.mainLocationImage.setImageURI(locationModel.getSdProfilePic()); - final String postCount = String.valueOf(locationModel.getPostCount()); - final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, - locationModel.getPostCount() > 2000000000L - ? 2000000000 - : locationModel.getPostCount().intValue(), - postCount)); - span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); - span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); - locationDetailsBinding.mainLocPostCount.setText(span); - locationDetailsBinding.mainLocPostCount.setVisibility(View.VISIBLE); + locationDetailsBinding.mainLocationImage.setImageURI("res:/" + R.drawable.ic_location); +// final String postCount = String.valueOf(locationModel.getCount()); +// final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, +// locationModel.getPostCount() > 2000000000L +// ? 2000000000 +// : locationModel.getPostCount().intValue(), +// postCount)); +// span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); +// span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); +// locationDetailsBinding.mainLocPostCount.setText(span); +// locationDetailsBinding.mainLocPostCount.setVisibility(View.VISIBLE); locationDetailsBinding.locationFullName.setText(locationModel.getName()); - CharSequence biography = locationModel.getBio(); + CharSequence biography = locationModel.getAddress() + "\n" + locationModel.getCity(); // binding.locationBiography.setCaptionIsExpandable(true); // binding.locationBiography.setCaptionIsExpanded(true); @@ -423,22 +432,22 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR } else { locationDetailsBinding.locationBiography.setVisibility(View.VISIBLE); locationDetailsBinding.locationBiography.setText(biography); - locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> { - final NavController navController = NavHostFragment.findNavController(this); - final Bundle bundle = new Bundle(); - final String originalText = autoLinkItem.getOriginalText().trim(); - bundle.putString(ARG_HASHTAG, originalText); - navController.navigate(R.id.action_global_hashTagFragment, bundle); - }); - locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> { - final String originalText = autoLinkItem.getOriginalText().trim(); - navigateToProfile(originalText); - }); - locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(context, - autoLinkItem.getOriginalText() - .trim())); - locationDetailsBinding.locationBiography - .addOnURLClickListener(autoLinkItem -> Utils.openURL(context, autoLinkItem.getOriginalText().trim())); +// locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> { +// final NavController navController = NavHostFragment.findNavController(this); +// final Bundle bundle = new Bundle(); +// final String originalText = autoLinkItem.getOriginalText().trim(); +// bundle.putString(ARG_HASHTAG, originalText); +// navController.navigate(R.id.action_global_hashTagFragment, bundle); +// }); +// locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> { +// final String originalText = autoLinkItem.getOriginalText().trim(); +// navigateToProfile(originalText); +// }); +// locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(context, +// autoLinkItem.getOriginalText() +// .trim())); +// locationDetailsBinding.locationBiography +// .addOnURLClickListener(autoLinkItem -> Utils.openURL(context, autoLinkItem.getOriginalText().trim())); locationDetailsBinding.locationBiography.setOnLongClickListener(v -> { Utils.copyText(context, biography); return true; @@ -457,16 +466,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR locationDetailsBinding.btnMap.setOnClickListener(null); } - final String url = locationModel.getUrl(); - if (TextUtils.isEmpty(url)) { - locationDetailsBinding.locationUrl.setVisibility(View.GONE); - } else if (!url.startsWith("http")) { - locationDetailsBinding.locationUrl.setVisibility(View.VISIBLE); - locationDetailsBinding.locationUrl.setText(TextUtils.getSpannableUrl("http://" + url)); - } else { - locationDetailsBinding.locationUrl.setVisibility(View.VISIBLE); - locationDetailsBinding.locationUrl.setText(TextUtils.getSpannableUrl(url)); - } final FavoriteDataSource dataSource = FavoriteDataSource.getInstance(context); final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(dataSource); locationDetailsBinding.favChip.setVisibility(View.VISIBLE); @@ -481,7 +480,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR String.valueOf(locationId), FavoriteType.LOCATION, locationModel.getName(), - locationModel.getSdProfilePic(), + "res:/" + R.drawable.ic_location, result.getDateAdded() ), new RepositoryCallback() { @Override @@ -523,7 +522,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR String.valueOf(locationId), FavoriteType.LOCATION, locationModel.getName(), - locationModel.getSdProfilePic(), + "res:/" + R.drawable.ic_location, new Date() ), new RepositoryCallback() { @Override diff --git a/app/src/main/java/awais/instagrabber/models/LocationModel.java b/app/src/main/java/awais/instagrabber/models/LocationModel.java deleted file mode 100755 index e0e13730..00000000 --- a/app/src/main/java/awais/instagrabber/models/LocationModel.java +++ /dev/null @@ -1,56 +0,0 @@ -package awais.instagrabber.models; - -import java.io.Serializable; - -public final class LocationModel implements Serializable { - private final long postCount; - private final long id; - private final String name; - private final String bio; - private final String url; - private final String sdProfilePic; - private final String lat; - private final String lng; - - public LocationModel(final long id, - final String name, - final String bio, - final String url, - final String sdProfilePic, - final long postCount, - final String lat, - final String lng) { - this.id = id; - this.name = name; - this.bio = bio; - this.url = url; - this.sdProfilePic = sdProfilePic; - this.postCount = postCount; - this.lat = lat; - this.lng = lng; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getBio() { - return bio; - } - - public String getUrl() { - return url; - } - - public String getGeo() { return "geo:" + lat + "," + lng + "?z=17&q=" + lat + "," + lng + "(" + name + ")"; } - - public String getSdProfilePic() { - return sdProfilePic; - } - - public Long getPostCount() { return postCount; } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/models/SuggestionModel.java b/app/src/main/java/awais/instagrabber/models/SuggestionModel.java deleted file mode 100755 index 855b1d4b..00000000 --- a/app/src/main/java/awais/instagrabber/models/SuggestionModel.java +++ /dev/null @@ -1,51 +0,0 @@ -package awais.instagrabber.models; - -import androidx.annotation.NonNull; - -import awais.instagrabber.models.enums.SuggestionType; - -public final class SuggestionModel implements Comparable { - private final int position; - private final boolean isVerified; - private final String username, name, profilePic; - private final SuggestionType suggestionType; - - public SuggestionModel(final boolean isVerified, final String username, final String name, final String profilePic, - final SuggestionType suggestionType, final int position) { - this.isVerified = isVerified; - this.username = username; - this.name = name; - this.profilePic = profilePic; - this.suggestionType = suggestionType; - this.position = position; - } - - public boolean isVerified() { - return isVerified; - } - - public String getUsername() { - return username; - } - - public String getName() { - return name; - } - - public String getProfilePic() { - return profilePic; - } - - public SuggestionType getSuggestionType() { - return suggestionType; - } - - public int getPosition() { - return position; - } - - @Override - public int compareTo(@NonNull final SuggestionModel model) { - return Integer.compare(getPosition(), model.getPosition()); - } -} diff --git a/app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java b/app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java index a6246fe0..efbc1c9a 100644 --- a/app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java @@ -16,4 +16,7 @@ public interface GraphQLRepository { @GET("/explore/tags/{tag}/?__a=1") Call getTag(@Path("tag") String tag); + + @GET("/explore/locations/{locationId}/?__a=1") + Call getLocation(@Path("locationId") long locationId); } diff --git a/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java b/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java index df999f0b..69e7302e 100644 --- a/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java @@ -3,12 +3,15 @@ package awais.instagrabber.repositories; import java.util.Map; import awais.instagrabber.repositories.responses.LocationFeedResponse; +import awais.instagrabber.repositories.responses.Place; import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Path; import retrofit2.http.QueryMap; public interface LocationRepository { + @GET("/api/v1/locations/{location}/info/") + Call fetch(@Path("location") final long locationId); @GET("/api/v1/feed/location/{location}/") Call fetchPosts(@Path("location") final long locationId, diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Location.java b/app/src/main/java/awais/instagrabber/repositories/responses/Location.java index ea1e66fe..c6a3d950 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/Location.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Location.java @@ -9,16 +9,16 @@ public class Location implements Serializable { private final String name; private final String address; private final String city; - private final float lng; - private final float lat; + private final double lng; + private final double lat; public Location(final long pk, final String shortName, final String name, final String address, final String city, - final float lng, - final float lat) { + final double lng, + final double lat) { this.pk = pk; this.shortName = shortName; this.name = name; @@ -48,22 +48,24 @@ public class Location implements Serializable { return city; } - public float getLng() { + public double getLng() { return lng; } - public float getLat() { + public double getLat() { return lat; } + public String getGeo() { return "geo:" + lat + "," + lng + "?z=17&q=" + lat + "," + lng + "(" + name + ")"; } + @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Location location = (Location) o; return pk == location.pk && - Float.compare(location.lng, lng) == 0 && - Float.compare(location.lat, lat) == 0 && + Double.compare(location.lng, lng) == 0 && + Double.compare(location.lat, lat) == 0 && Objects.equals(shortName, location.shortName) && Objects.equals(name, location.name) && Objects.equals(address, location.address) && diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java b/app/src/main/java/awais/instagrabber/repositories/responses/Place.java similarity index 71% rename from app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java rename to app/src/main/java/awais/instagrabber/repositories/responses/Place.java index e4a44646..c72e1c41 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/search/Place.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Place.java @@ -1,21 +1,24 @@ -package awais.instagrabber.repositories.responses.search; - -import awais.instagrabber.repositories.responses.Location; +package awais.instagrabber.repositories.responses; public class Place { private final Location location; + // for search private final String title; // those are repeated within location private final String subtitle; // address private final String slug; // browser only; for end of address + // for location info + private final String status; public Place(final Location location, final String title, final String subtitle, - final String slug) { + final String slug, + final String status) { this.location = location; this.title = title; this.subtitle = subtitle; this.slug = slug; + this.status = status; } public Location getLocation() { @@ -33,4 +36,8 @@ public class Place { public String getSlug() { return slug; } + + public String getStatus() { + return status; + } } diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java index 52749321..4aca79da 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/search/SearchItem.java @@ -1,8 +1,7 @@ package awais.instagrabber.repositories.responses.search; -import java.util.List; - import awais.instagrabber.repositories.responses.Hashtag; +import awais.instagrabber.repositories.responses.Place; import awais.instagrabber.repositories.responses.User; public class SearchItem { diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index b373b3c8..b4ca9293 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -19,6 +19,7 @@ import awais.instagrabber.repositories.GraphQLRepository; import awais.instagrabber.repositories.responses.FriendshipStatus; import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse; import awais.instagrabber.repositories.responses.Hashtag; +import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.User; @@ -413,4 +414,48 @@ public class GraphQLService extends BaseService { } }); } + + public void fetchLocation(final long locationId, + final ServiceCallback callback) { + final Call request = repository.getLocation(locationId); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final String rawBody = response.body(); + if (rawBody == null) { + Log.e(TAG, "Error occurred while fetching gql location of " + locationId); + callback.onSuccess(null); + return; + } + try { + final JSONObject body = new JSONObject(rawBody) + .getJSONObject("graphql") + .getJSONObject(Constants.EXTRAS_LOCATION); + final JSONObject timelineMedia = body.getJSONObject("edge_location_to_media"); + final JSONObject address = new JSONObject(body.getString("address_json")); + callback.onSuccess(new Location( + body.getLong(Constants.EXTRAS_ID), + body.getString("slug"), + body.getString("name"), + address.optString("street_address"), + address.optString("city_name"), + body.optDouble("lng", 0d), + body.optDouble("lat", 0d) + )); + } catch (JSONException e) { + Log.e(TAG, "onResponse", e); + if (callback != null) { + callback.onFailure(e); + } + } + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); + } } diff --git a/app/src/main/java/awais/instagrabber/webservices/LocationService.java b/app/src/main/java/awais/instagrabber/webservices/LocationService.java index 381ba440..7b3648f4 100644 --- a/app/src/main/java/awais/instagrabber/webservices/LocationService.java +++ b/app/src/main/java/awais/instagrabber/webservices/LocationService.java @@ -5,7 +5,9 @@ import androidx.annotation.NonNull; import com.google.common.collect.ImmutableMap; import awais.instagrabber.repositories.LocationRepository; +import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.LocationFeedResponse; +import awais.instagrabber.repositories.responses.Place; import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.utils.TextUtils; import retrofit2.Call; @@ -69,34 +71,24 @@ public class LocationService extends BaseService { }); } - // private PostsFetchResponse parseResponse(@NonNull final String body) throws JSONException { - // final JSONObject root = new JSONObject(body); - // final boolean moreAvailable = root.optBoolean("more_available"); - // final String nextMaxId = root.optString("next_max_id"); - // final JSONArray itemsJson = root.optJSONArray("items"); - // final List items = parseItems(itemsJson); - // return new PostsFetchResponse( - // items, - // moreAvailable, - // nextMaxId - // ); - // } + public void fetch(@NonNull final long locationId, + final ServiceCallback callback) { + final Call request = repository.fetch(locationId); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + if (callback == null) { + return; + } + callback.onSuccess(response.body() == null ? null : response.body().getLocation()); + } - // private List parseItems(final JSONArray items) throws JSONException { - // if (items == null) { - // return Collections.emptyList(); - // } - // final List feedModels = new ArrayList<>(); - // for (int i = 0; i < items.length(); i++) { - // final JSONObject itemJson = items.optJSONObject(i); - // if (itemJson == null) { - // continue; - // } - // final FeedModel feedModel = ResponseBodyUtils.parseItem(itemJson); - // if (feedModel != null) { - // feedModels.add(feedModel); - // } - // } - // return feedModels; - // } + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); + } } diff --git a/app/src/main/res/layout/layout_location_details.xml b/app/src/main/res/layout/layout_location_details.xml index 912c225c..bc880ebf 100644 --- a/app/src/main/res/layout/layout_location_details.xml +++ b/app/src/main/res/layout/layout_location_details.xml @@ -15,25 +15,25 @@ android:layout_height="@dimen/profile_picture_size" android:background="?selectableItemBackgroundBorderless" app:actualImageScaleType="centerCrop" - app:layout_constraintEnd_toStartOf="@id/mainLocPostCount" + app:layout_constraintEnd_toStartOf="@id/btnMap" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:background="@mipmap/ic_launcher" /> - + + + + + + + + + + + + + + @@ -60,8 +59,8 @@ app:chipIcon="@drawable/ic_outline_star_plus_24" app:chipIconTint="@color/yellow_800" app:layout_constraintBottom_toBottomOf="@id/mainLocationImage" - app:layout_constraintStart_toEndOf="@id/btnMap" - app:layout_constraintTop_toBottomOf="@id/mainLocPostCount" + app:layout_constraintStart_toEndOf="@id/mainLocationImage" + app:layout_constraintTop_toBottomOf="@id/btnMap" app:rippleColor="@color/yellow_400" /> - - \ No newline at end of file From 2b3359076ea5daee7ebfad8c00f146e04a946298 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 18:13:40 -0400 Subject: [PATCH 10/12] #825 --- .../fragments/FollowViewerFragment.java | 2 - .../fragments/HashTagFragment.java | 2 - .../fragments/LocationFragment.java | 2 - .../DirectMessageThreadFragment.java | 141 ------------------ 4 files changed, 147 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index 42fcee57..52b4fed7 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -2,7 +2,6 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.res.Resources; -import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -57,7 +56,6 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh private FollowAdapter adapter; private View.OnClickListener clickListener; private FragmentFollowersViewerBinding binding; - private AsyncTask currentlyExecuting; private SwipeRefreshLayout root; private FriendshipService friendshipService; private AppCompatActivity fragmentActivity; diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 9b684c68..81530dc5 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -3,7 +3,6 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Typeface; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.text.SpannableStringBuilder; @@ -95,7 +94,6 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe private Hashtag hashtagModel = null; private ActionMode actionMode; private StoriesService storiesService; - private AsyncTask currentlyExecuting; private boolean isLoggedIn; private TagsService tagsService; private GraphQLService graphQLService; diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 1d834a08..ea48a647 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.util.Log; @@ -90,7 +89,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR private StoriesService storiesService; private GraphQLService graphQLService; private LocationService locationService; - private AsyncTask currentlyExecuting; private boolean isLoggedIn; private boolean storiesFetching; private Set selectedFeedModels; diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java index d1e4b5f9..2962c078 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -1328,95 +1328,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact } } - // private void sendText(final String text, final String itemId, final boolean delete) { - // DirectThreadBroadcaster.TextBroadcastOptions textOptions = null; - // DirectThreadBroadcaster.ReactionBroadcastOptions reactionOptions = null; - // if (text != null) { - // try { - // textOptions = new DirectThreadBroadcaster.TextBroadcastOptions(text); - // } catch (UnsupportedEncodingException e) { - // Log.e(TAG, "Error", e); - // return; - // } - // } else { - // reactionOptions = new DirectThreadBroadcaster.ReactionBroadcastOptions(itemId, delete); - // } - // broadcast(text != null ? textOptions : reactionOptions, result -> { - // final Context context = getContext(); - // if (context == null) return; - // if (result == null || result.getResponseCode() != HttpURLConnection.HTTP_OK) { - // Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - // return; - // } - // if (text != null) { - // // binding.commentText.setText(""); - // } else { - // // final View viewWithTag = binding.messageList.findViewWithTag(directItemModel); - // // if (viewWithTag != null) { - // // final ViewParent dim = viewWithTag.getParent(); - // // if (dim instanceof View) { - // // final View dimView = (View) dim; - // // final View likedContainer = dimView.findViewById(R.id.liked_container); - // // if (likedContainer != null) { - // // likedContainer.setVisibility(delete ? View.GONE : View.VISIBLE); - // // } - // // } - // // } - // // directItemModel.setLiked(); - // } - // context.sendBroadcast(new Intent(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM)); - // hasSentSomething = true; - // // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener) - // // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // }); - // } - - // private void sendImage(final Uri imageUri) { - // final Context context = getContext(); - // if (context == null) return; - // try (InputStream inputStream = context.getContentResolver().openInputStream(imageUri)) { - // final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); - // Toast.makeText(context, R.string.uploading, Toast.LENGTH_SHORT).show(); - // // Upload Image - // final ImageUploader imageUploader = new ImageUploader(); - // imageUploader.setOnTaskCompleteListener(response -> { - // if (response == null || response.getResponseCode() != HttpURLConnection.HTTP_OK) { - // Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - // if (response != null && response.getResponse() != null) { - // Log.e(TAG, response.getResponse().toString()); - // } - // return; - // } - // final JSONObject responseJson = response.getResponse(); - // try { - // final String uploadId = responseJson.getString("upload_id"); - // // Broadcast - // final DirectThreadBroadcaster.ImageBroadcastOptions options = new DirectThreadBroadcaster.ImageBroadcastOptions(true, uploadId); - // hasSentSomething = true; - // broadcast(options, - // broadcastResponse -> { - // // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener) - // // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // }); - // } catch (JSONException e) { - // Log.e(TAG, "Error parsing json response", e); - // } - // }); - // final ImageUploadOptions options = ImageUploadOptions.builder(bitmap).build(); - // imageUploader.execute(options); - // } catch (IOException e) { - // Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - // Log.e(TAG, "Error opening file", e); - // } - // } - - // private void broadcast(final DirectThreadBroadcaster.BroadcastOptions broadcastOptions, - // final DirectThreadBroadcaster.OnBroadcastCompleteListener listener) { - // final DirectThreadBroadcaster broadcaster = new DirectThreadBroadcaster(threadId); - // broadcaster.setOnTaskCompleteListener(listener); - // broadcaster.execute(broadcastOptions); - // } - @NonNull private User getUser(final long userId) { for (final User user : users) { @@ -1426,58 +1337,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact return null; } - // private void searchUsername(final String text) { - // final Bundle bundle = new Bundle(); - // bundle.putString("username", "@" + text); - // NavHostFragment.findNavController(this).navigate(R.id.action_global_profileFragment, bundle); - // } - - // class ThreadAction extends AsyncTask { - // String action, argument; - // - // protected Void doInBackground(String... rawAction) { - // action = rawAction[0]; - // argument = rawAction[1]; - // final String url = "https://i.instagram.com/api/v1/direct_v2/threads/" + threadId + "/items/" + argument + "/" + action + "/"; - // try { - // String urlParameters = "_csrftoken=" + COOKIE.split("csrftoken=")[1].split(";")[0] - // + "&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID); - // final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); - // urlConnection.setRequestMethod("POST"); - // urlConnection.setUseCaches(false); - // urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); - // urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - // urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); - // urlConnection.setDoOutput(true); - // DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); - // wr.writeBytes(urlParameters); - // wr.flush(); - // wr.close(); - // urlConnection.connect(); - // if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - // if (action.equals("delete")) { - // hasDeletedSomething = true; - // } else if (action.equals("seen")) { - // // context.sendBroadcast(new Intent(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM)); - // } - // } - // urlConnection.disconnect(); - // } catch (Throwable ex) { - // Log.e("austin_debug", action + ": " + ex); - // } - // return null; - // } - // - // @Override - // protected void onPostExecute(Void result) { - // if (hasDeletedSomething) { - // // directItemModel = null; - // // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener) - // // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // } - // } - // } - private void setupKbHeightProvider() { if (heightProvider != null) return; heightProvider = new HeightProvider(fragmentActivity).init().setHeightListener(height -> { From 6833e0329959cf6f6b523e152bfa8d71c2a8d229 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 22 Mar 2021 18:16:50 -0400 Subject: [PATCH 11/12] #825 --- .../fragments/FollowViewerFragment.java | 2 - .../fragments/HashTagFragment.java | 2 - .../fragments/LocationFragment.java | 14 -- .../DirectMessageThreadFragment.java | 141 ------------------ 4 files changed, 159 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index 42fcee57..52b4fed7 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -2,7 +2,6 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.res.Resources; -import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -57,7 +56,6 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh private FollowAdapter adapter; private View.OnClickListener clickListener; private FragmentFollowersViewerBinding binding; - private AsyncTask currentlyExecuting; private SwipeRefreshLayout root; private FriendshipService friendshipService; private AppCompatActivity fragmentActivity; diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 9b684c68..81530dc5 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -3,7 +3,6 @@ package awais.instagrabber.fragments; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Typeface; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.text.SpannableStringBuilder; @@ -95,7 +94,6 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe private Hashtag hashtagModel = null; private ActionMode actionMode; private StoriesService storiesService; - private AsyncTask currentlyExecuting; private boolean isLoggedIn; private TagsService tagsService; private GraphQLService graphQLService; diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 1d834a08..65db4826 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.util.Log; @@ -90,7 +89,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR private StoriesService storiesService; private GraphQLService graphQLService; private LocationService locationService; - private AsyncTask currentlyExecuting; private boolean isLoggedIn; private boolean storiesFetching; private Set selectedFeedModels; @@ -580,18 +578,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR } } - private void stopCurrentExecutor() { - if (currentlyExecuting != null) { - try { - currentlyExecuting.cancel(true); - } catch (final Exception e) { -// if (logCollector != null) logCollector.appendException( -// e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor"); - Log.e(TAG, "", e); - } - } - } - private void setTitle() { final ActionBar actionBar = fragmentActivity.getSupportActionBar(); if (actionBar != null && locationModel != null) { diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java index d1e4b5f9..2962c078 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -1328,95 +1328,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact } } - // private void sendText(final String text, final String itemId, final boolean delete) { - // DirectThreadBroadcaster.TextBroadcastOptions textOptions = null; - // DirectThreadBroadcaster.ReactionBroadcastOptions reactionOptions = null; - // if (text != null) { - // try { - // textOptions = new DirectThreadBroadcaster.TextBroadcastOptions(text); - // } catch (UnsupportedEncodingException e) { - // Log.e(TAG, "Error", e); - // return; - // } - // } else { - // reactionOptions = new DirectThreadBroadcaster.ReactionBroadcastOptions(itemId, delete); - // } - // broadcast(text != null ? textOptions : reactionOptions, result -> { - // final Context context = getContext(); - // if (context == null) return; - // if (result == null || result.getResponseCode() != HttpURLConnection.HTTP_OK) { - // Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - // return; - // } - // if (text != null) { - // // binding.commentText.setText(""); - // } else { - // // final View viewWithTag = binding.messageList.findViewWithTag(directItemModel); - // // if (viewWithTag != null) { - // // final ViewParent dim = viewWithTag.getParent(); - // // if (dim instanceof View) { - // // final View dimView = (View) dim; - // // final View likedContainer = dimView.findViewById(R.id.liked_container); - // // if (likedContainer != null) { - // // likedContainer.setVisibility(delete ? View.GONE : View.VISIBLE); - // // } - // // } - // // } - // // directItemModel.setLiked(); - // } - // context.sendBroadcast(new Intent(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM)); - // hasSentSomething = true; - // // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener) - // // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // }); - // } - - // private void sendImage(final Uri imageUri) { - // final Context context = getContext(); - // if (context == null) return; - // try (InputStream inputStream = context.getContentResolver().openInputStream(imageUri)) { - // final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); - // Toast.makeText(context, R.string.uploading, Toast.LENGTH_SHORT).show(); - // // Upload Image - // final ImageUploader imageUploader = new ImageUploader(); - // imageUploader.setOnTaskCompleteListener(response -> { - // if (response == null || response.getResponseCode() != HttpURLConnection.HTTP_OK) { - // Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - // if (response != null && response.getResponse() != null) { - // Log.e(TAG, response.getResponse().toString()); - // } - // return; - // } - // final JSONObject responseJson = response.getResponse(); - // try { - // final String uploadId = responseJson.getString("upload_id"); - // // Broadcast - // final DirectThreadBroadcaster.ImageBroadcastOptions options = new DirectThreadBroadcaster.ImageBroadcastOptions(true, uploadId); - // hasSentSomething = true; - // broadcast(options, - // broadcastResponse -> { - // // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener) - // // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // }); - // } catch (JSONException e) { - // Log.e(TAG, "Error parsing json response", e); - // } - // }); - // final ImageUploadOptions options = ImageUploadOptions.builder(bitmap).build(); - // imageUploader.execute(options); - // } catch (IOException e) { - // Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - // Log.e(TAG, "Error opening file", e); - // } - // } - - // private void broadcast(final DirectThreadBroadcaster.BroadcastOptions broadcastOptions, - // final DirectThreadBroadcaster.OnBroadcastCompleteListener listener) { - // final DirectThreadBroadcaster broadcaster = new DirectThreadBroadcaster(threadId); - // broadcaster.setOnTaskCompleteListener(listener); - // broadcaster.execute(broadcastOptions); - // } - @NonNull private User getUser(final long userId) { for (final User user : users) { @@ -1426,58 +1337,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact return null; } - // private void searchUsername(final String text) { - // final Bundle bundle = new Bundle(); - // bundle.putString("username", "@" + text); - // NavHostFragment.findNavController(this).navigate(R.id.action_global_profileFragment, bundle); - // } - - // class ThreadAction extends AsyncTask { - // String action, argument; - // - // protected Void doInBackground(String... rawAction) { - // action = rawAction[0]; - // argument = rawAction[1]; - // final String url = "https://i.instagram.com/api/v1/direct_v2/threads/" + threadId + "/items/" + argument + "/" + action + "/"; - // try { - // String urlParameters = "_csrftoken=" + COOKIE.split("csrftoken=")[1].split(";")[0] - // + "&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID); - // final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); - // urlConnection.setRequestMethod("POST"); - // urlConnection.setUseCaches(false); - // urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); - // urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - // urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); - // urlConnection.setDoOutput(true); - // DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); - // wr.writeBytes(urlParameters); - // wr.flush(); - // wr.close(); - // urlConnection.connect(); - // if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - // if (action.equals("delete")) { - // hasDeletedSomething = true; - // } else if (action.equals("seen")) { - // // context.sendBroadcast(new Intent(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM)); - // } - // } - // urlConnection.disconnect(); - // } catch (Throwable ex) { - // Log.e("austin_debug", action + ": " + ex); - // } - // return null; - // } - // - // @Override - // protected void onPostExecute(Void result) { - // if (hasDeletedSomething) { - // // directItemModel = null; - // // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener) - // // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // } - // } - // } - private void setupKbHeightProvider() { if (heightProvider != null) return; heightProvider = new HeightProvider(fragmentActivity).init().setHeightListener(height -> { From eaff5bf93eb7660ebb835d75385bc4599bb21b45 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 23 Mar 2021 09:10:58 -0400 Subject: [PATCH 12/12] Update crowdin.yml --- crowdin.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crowdin.yml b/crowdin.yml index 8f046a46..7cae19af 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,3 +1,5 @@ files: - source: '/app/src/main/res/values/[arrays][strings][!styles]' translation: /app/src/main/res/values-%two_letters_code%/%original_file_name% + - source: '/app/src/github/res/values/[arrays][strings][!styles]' + translation: /app/src/github/res/values-%two_letters_code%/%original_file_name%