Convert some more classes to kotlin
This commit is contained in:
parent
746925e54d
commit
17fb608c34
@ -27,9 +27,6 @@ import static awais.instagrabber.utils.Utils.clipboardManager;
|
|||||||
import static awais.instagrabber.utils.Utils.datetimeParser;
|
import static awais.instagrabber.utils.Utils.datetimeParser;
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||||
|
|
||||||
//import awaisomereport.LogCollector;
|
|
||||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
|
||||||
|
|
||||||
public final class InstaGrabberApplication extends Application {
|
public final class InstaGrabberApplication extends Application {
|
||||||
private static final String TAG = "InstaGrabberApplication";
|
private static final String TAG = "InstaGrabberApplication";
|
||||||
|
|
||||||
@ -56,7 +53,7 @@ public final class InstaGrabberApplication extends Application {
|
|||||||
Log.e(TAG, "Error", e);
|
Log.e(TAG, "Error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// final Set<RequestListener> requestListeners = new HashSet<>();
|
// final Set<RequestListener> requestListeners = new HashSet<>();
|
||||||
// requestListeners.add(new RequestLoggingListener());
|
// requestListeners.add(new RequestLoggingListener());
|
||||||
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
||||||
|
@ -153,7 +153,7 @@ public class FormattedNumberTextView extends AppCompatTextView {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (showAbbreviation) {
|
if (showAbbreviation) {
|
||||||
setText(NumberUtils.abbreviate(number));
|
setText(NumberUtils.abbreviate(number, null));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setText(String.valueOf(number));
|
setText(String.valueOf(number));
|
||||||
|
@ -16,6 +16,8 @@ import awais.instagrabber.utils.AppExecutors;
|
|||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.utils.ViewUtils;
|
import awais.instagrabber.utils.ViewUtils;
|
||||||
|
|
||||||
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
|
||||||
public class Tooltip extends AppCompatTextView {
|
public class Tooltip extends AppCompatTextView {
|
||||||
|
|
||||||
private View anchor;
|
private View anchor;
|
||||||
@ -40,8 +42,7 @@ public class Tooltip extends AppCompatTextView {
|
|||||||
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
setPadding(Utils.convertDpToPx(8), Utils.convertDpToPx(7), Utils.convertDpToPx(8), Utils.convertDpToPx(7));
|
setPadding(Utils.convertDpToPx(8), Utils.convertDpToPx(7), Utils.convertDpToPx(8), Utils.convertDpToPx(7));
|
||||||
setGravity(Gravity.CENTER_VERTICAL);
|
setGravity(Gravity.CENTER_VERTICAL);
|
||||||
parentView.addView(this, ViewUtils.createFrame(
|
parentView.addView(this, ViewUtils.createFrame(WRAP_CONTENT, WRAP_CONTENT, Gravity.START | Gravity.TOP, 5, 0, 5, 3));
|
||||||
ViewUtils.WRAP_CONTENT, ViewUtils.WRAP_CONTENT, Gravity.START | Gravity.TOP, 5, 0, 5, 3));
|
|
||||||
setVisibility(GONE);
|
setVisibility(GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,185 +1,157 @@
|
|||||||
package awais.instagrabber.utils;/*
|
/*
|
||||||
* This is the source code of Telegram for Android v. 5.x.x.
|
* This is the source code of Telegram for Android v. 5.x.x.
|
||||||
* It is licensed under GNU GPL v. 2 or later.
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
* You should have received a copy of the license in this archive (see LICENSE).
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
*
|
* <p>
|
||||||
* Copyright Nikolai Kudashov, 2013-2018.
|
* Copyright Nikolai Kudashov, 2013-2018.
|
||||||
*/
|
*/
|
||||||
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.PixelFormat
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
class CombinedDrawable : Drawable, Drawable.Callback {
|
||||||
|
val background: Drawable
|
||||||
|
val icon: Drawable?
|
||||||
|
private var left = 0
|
||||||
|
private var top = 0
|
||||||
|
private var iconWidth = 0
|
||||||
|
private var iconHeight = 0
|
||||||
|
private var backWidth = 0
|
||||||
|
private var backHeight = 0
|
||||||
|
private var offsetX = 0
|
||||||
|
private var offsetY = 0
|
||||||
|
private var fullSize = false
|
||||||
|
|
||||||
public class CombinedDrawable extends Drawable implements Drawable.Callback {
|
constructor(backgroundDrawable: Drawable, iconDrawable: Drawable?, leftOffset: Int, topOffset: Int) {
|
||||||
|
background = backgroundDrawable
|
||||||
private final Drawable background;
|
icon = iconDrawable
|
||||||
private final Drawable icon;
|
left = leftOffset
|
||||||
private int left;
|
top = topOffset
|
||||||
private int top;
|
|
||||||
private int iconWidth;
|
|
||||||
private int iconHeight;
|
|
||||||
private int backWidth;
|
|
||||||
private int backHeight;
|
|
||||||
private int offsetX;
|
|
||||||
private int offsetY;
|
|
||||||
private boolean fullSize;
|
|
||||||
|
|
||||||
public CombinedDrawable(Drawable backgroundDrawable, Drawable iconDrawable, int leftOffset, int topOffset) {
|
|
||||||
background = backgroundDrawable;
|
|
||||||
icon = iconDrawable;
|
|
||||||
left = leftOffset;
|
|
||||||
top = topOffset;
|
|
||||||
if (iconDrawable != null) {
|
if (iconDrawable != null) {
|
||||||
iconDrawable.setCallback(this);
|
iconDrawable.callback = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CombinedDrawable(Drawable backgroundDrawable, Drawable iconDrawable) {
|
constructor(backgroundDrawable: Drawable, iconDrawable: Drawable?) {
|
||||||
background = backgroundDrawable;
|
background = backgroundDrawable
|
||||||
icon = iconDrawable;
|
icon = iconDrawable
|
||||||
if (iconDrawable != null) {
|
if (iconDrawable != null) {
|
||||||
iconDrawable.setCallback(this);
|
iconDrawable.callback = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconSize(int width, int height) {
|
fun setIconSize(width: Int, height: Int) {
|
||||||
iconWidth = width;
|
iconWidth = width
|
||||||
iconHeight = height;
|
iconHeight = height
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCustomSize(int width, int height) {
|
fun setCustomSize(width: Int, height: Int) {
|
||||||
backWidth = width;
|
backWidth = width
|
||||||
backHeight = height;
|
backHeight = height
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconOffset(int x, int y) {
|
fun setIconOffset(x: Int, y: Int) {
|
||||||
offsetX = x;
|
offsetX = x
|
||||||
offsetY = y;
|
offsetY = y
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable getIcon() {
|
fun setFullsize(value: Boolean) {
|
||||||
return icon;
|
fullSize = value
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable getBackground() {
|
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||||
return background;
|
icon?.colorFilter = colorFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFullsize(boolean value) {
|
override fun isStateful(): Boolean {
|
||||||
fullSize = value;
|
return icon?.isStateful ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun setState(stateSet: IntArray): Boolean {
|
||||||
public void setColorFilter(ColorFilter colorFilter) {
|
icon?.state = stateSet
|
||||||
icon.setColorFilter(colorFilter);
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getState(): IntArray {
|
||||||
public boolean isStateful() {
|
return icon?.state ?: super.getState()
|
||||||
return icon.isStateful();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun onStateChange(state: IntArray): Boolean {
|
||||||
public boolean setState(@NonNull int[] stateSet) {
|
return true
|
||||||
icon.setState(stateSet);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
override fun jumpToCurrentState() {
|
||||||
@Override
|
icon?.jumpToCurrentState()
|
||||||
public int[] getState() {
|
|
||||||
return icon.getState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getConstantState(): ConstantState? {
|
||||||
protected boolean onStateChange(int[] state) {
|
return icon?.constantState
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun draw(canvas: Canvas) {
|
||||||
public void jumpToCurrentState() {
|
background.bounds = bounds
|
||||||
icon.jumpToCurrentState();
|
background.draw(canvas)
|
||||||
}
|
if (icon == null) return
|
||||||
|
if (fullSize) {
|
||||||
@Override
|
val bounds = bounds
|
||||||
public ConstantState getConstantState() {
|
if (left != 0) {
|
||||||
return icon.getConstantState();
|
icon.setBounds(bounds.left + left, bounds.top + top, bounds.right - left, bounds.bottom - top)
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(@NonNull Canvas canvas) {
|
|
||||||
background.setBounds(getBounds());
|
|
||||||
background.draw(canvas);
|
|
||||||
if (icon != null) {
|
|
||||||
if (fullSize) {
|
|
||||||
android.graphics.Rect bounds = getBounds();
|
|
||||||
if (left != 0) {
|
|
||||||
icon.setBounds(bounds.left + left, bounds.top + top, bounds.right - left, bounds.bottom - top);
|
|
||||||
} else {
|
|
||||||
icon.setBounds(bounds);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
int x;
|
icon.bounds = bounds
|
||||||
int y;
|
}
|
||||||
if (iconWidth != 0) {
|
} else {
|
||||||
x = getBounds().centerX() - iconWidth / 2 + left + offsetX;
|
val x: Int
|
||||||
y = getBounds().centerY() - iconHeight / 2 + top + offsetY;
|
val y: Int
|
||||||
icon.setBounds(x, y, x + iconWidth, y + iconHeight);
|
if (iconWidth != 0) {
|
||||||
} else {
|
x = bounds.centerX() - iconWidth / 2 + left + offsetX
|
||||||
x = getBounds().centerX() - icon.getIntrinsicWidth() / 2 + left;
|
y = bounds.centerY() - iconHeight / 2 + top + offsetY
|
||||||
y = getBounds().centerY() - icon.getIntrinsicHeight() / 2 + top;
|
icon.setBounds(x, y, x + iconWidth, y + iconHeight)
|
||||||
icon.setBounds(x, y, x + icon.getIntrinsicWidth(), y + icon.getIntrinsicHeight());
|
} else {
|
||||||
}
|
x = bounds.centerX() - icon.intrinsicWidth / 2 + left
|
||||||
|
y = bounds.centerY() - icon.intrinsicHeight / 2 + top
|
||||||
|
icon.setBounds(x, y, x + icon.intrinsicWidth, y + icon.intrinsicHeight)
|
||||||
}
|
}
|
||||||
icon.draw(canvas);
|
|
||||||
}
|
}
|
||||||
|
icon.draw(canvas)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun setAlpha(alpha: Int) {
|
||||||
public void setAlpha(int alpha) {
|
icon?.alpha = alpha
|
||||||
icon.setAlpha(alpha);
|
background.alpha = alpha
|
||||||
background.setAlpha(alpha);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getIntrinsicWidth(): Int {
|
||||||
public int getIntrinsicWidth() {
|
return if (backWidth != 0) backWidth else background.intrinsicWidth
|
||||||
return backWidth != 0 ? backWidth : background.getIntrinsicWidth();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getIntrinsicHeight(): Int {
|
||||||
public int getIntrinsicHeight() {
|
return if (backHeight != 0) backHeight else background.intrinsicHeight
|
||||||
return backHeight != 0 ? backHeight : background.getIntrinsicHeight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getMinimumWidth(): Int {
|
||||||
public int getMinimumWidth() {
|
return if (backWidth != 0) backWidth else background.minimumWidth
|
||||||
return backWidth != 0 ? backWidth : background.getMinimumWidth();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getMinimumHeight(): Int {
|
||||||
public int getMinimumHeight() {
|
return if (backHeight != 0) backHeight else background.minimumHeight
|
||||||
return backHeight != 0 ? backHeight : background.getMinimumHeight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getOpacity(): Int {
|
||||||
public int getOpacity() {
|
return icon?.opacity ?: PixelFormat.UNKNOWN
|
||||||
return icon.getOpacity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun invalidateDrawable(who: Drawable) {
|
||||||
public void invalidateDrawable(@NonNull Drawable who) {
|
invalidateSelf()
|
||||||
invalidateSelf();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) {
|
||||||
public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
|
scheduleSelf(what, `when`)
|
||||||
scheduleSelf(what, when);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun unscheduleDrawable(who: Drawable, what: Runnable) {
|
||||||
public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
|
unscheduleSelf(what)
|
||||||
unscheduleSelf(what);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,139 +1,114 @@
|
|||||||
package awais.instagrabber.utils;
|
@file:JvmName("CookieUtils")
|
||||||
|
|
||||||
import android.content.Context;
|
package awais.instagrabber.utils
|
||||||
import android.util.Log;
|
|
||||||
import android.webkit.CookieManager;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import android.webkit.CookieManager
|
||||||
|
import awais.instagrabber.db.datasources.AccountDataSource
|
||||||
|
import awais.instagrabber.db.repositories.AccountRepository
|
||||||
|
import awais.instagrabber.db.repositories.RepositoryCallback
|
||||||
|
import java.net.CookiePolicy
|
||||||
|
import java.net.HttpCookie
|
||||||
|
import java.net.URI
|
||||||
|
import java.net.URISyntaxException
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
import java.net.CookiePolicy;
|
private const val TAG = "CookieUtils"
|
||||||
import java.net.CookieStore;
|
private val COOKIE_MANAGER = CookieManager.getInstance()
|
||||||
import java.net.HttpCookie;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
@JvmField
|
||||||
import awais.instagrabber.db.datasources.AccountDataSource;
|
val NET_COOKIE_MANAGER = java.net.CookieManager(null, CookiePolicy.ACCEPT_ALL)
|
||||||
import awais.instagrabber.db.repositories.AccountRepository;
|
|
||||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
|
||||||
//import awaisomereport.LogCollector;
|
|
||||||
|
|
||||||
public final class CookieUtils {
|
fun setupCookies(cookieRaw: String) {
|
||||||
private static final String TAG = CookieUtils.class.getSimpleName();
|
val cookieStore = NET_COOKIE_MANAGER.cookieStore
|
||||||
public static final CookieManager COOKIE_MANAGER = CookieManager.getInstance();
|
if (cookieStore == null || TextUtils.isEmpty(cookieRaw)) {
|
||||||
public static final java.net.CookieManager NET_COOKIE_MANAGER = new java.net.CookieManager(null, CookiePolicy.ACCEPT_ALL);
|
return
|
||||||
|
|
||||||
public static void setupCookies(final String cookieRaw) {
|
|
||||||
final CookieStore cookieStore = NET_COOKIE_MANAGER.getCookieStore();
|
|
||||||
if (cookieStore == null || TextUtils.isEmpty(cookieRaw)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (cookieRaw.equals("LOGOUT")) {
|
|
||||||
cookieStore.removeAll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final URI uri1 = new URI("https://instagram.com");
|
|
||||||
final URI uri2 = new URI("https://instagram.com/");
|
|
||||||
final URI uri3 = new URI("https://i.instagram.com/");
|
|
||||||
for (final String cookie : cookieRaw.split("; ")) {
|
|
||||||
final String[] strings = cookie.split("=", 2);
|
|
||||||
final HttpCookie httpCookie = new HttpCookie(strings[0].trim(), strings[1].trim());
|
|
||||||
httpCookie.setDomain(".instagram.com");
|
|
||||||
httpCookie.setPath("/");
|
|
||||||
httpCookie.setVersion(0);
|
|
||||||
cookieStore.add(uri1, httpCookie);
|
|
||||||
cookieStore.add(uri2, httpCookie);
|
|
||||||
cookieStore.add(uri3, httpCookie);
|
|
||||||
}
|
|
||||||
} catch (final URISyntaxException e) {
|
|
||||||
// if (Utils.logCollector != null)
|
|
||||||
// Utils.logCollector.appendException(e, LogCollector.LogFile.UTILS, "setupCookies");
|
|
||||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (cookieRaw == "LOGOUT") {
|
||||||
public static void removeAllAccounts(final Context context, final RepositoryCallback<Void> callback) {
|
cookieStore.removeAll()
|
||||||
final CookieStore cookieStore = NET_COOKIE_MANAGER.getCookieStore();
|
return
|
||||||
if (cookieStore == null) return;
|
|
||||||
cookieStore.removeAll();
|
|
||||||
try {
|
|
||||||
AccountRepository.getInstance(AccountDataSource.getInstance(context))
|
|
||||||
.deleteAllAccounts(callback);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "setupCookies", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
public static long getUserIdFromCookie(final String cookies) {
|
val uri1 = URI("https://instagram.com")
|
||||||
final String dsUserId = getCookieValue(cookies, "ds_user_id");
|
val uri2 = URI("https://instagram.com/")
|
||||||
if (dsUserId == null) {
|
val uri3 = URI("https://i.instagram.com/")
|
||||||
return 0;
|
for (cookie in cookieRaw.split("; ")) {
|
||||||
|
val strings = cookie.split("=", limit = 2)
|
||||||
|
val httpCookie = HttpCookie(strings[0].trim { it <= ' ' }, strings[1].trim { it <= ' ' })
|
||||||
|
httpCookie.domain = ".instagram.com"
|
||||||
|
httpCookie.path = "/"
|
||||||
|
httpCookie.version = 0
|
||||||
|
cookieStore.add(uri1, httpCookie)
|
||||||
|
cookieStore.add(uri2, httpCookie)
|
||||||
|
cookieStore.add(uri3, httpCookie)
|
||||||
}
|
}
|
||||||
try {
|
} catch (e: URISyntaxException) {
|
||||||
return Long.parseLong(dsUserId);
|
Log.e(TAG, "", e)
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "getUserIdFromCookie: ", e);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String getCsrfTokenFromCookie(final String cookies) {
|
|
||||||
return getCookieValue(cookies, "csrftoken");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String getCookieValue(final String cookies, final String name) {
|
|
||||||
if (cookies == null) return null;
|
|
||||||
final Pattern pattern = Pattern.compile(name + "=(.+?);");
|
|
||||||
final Matcher matcher = pattern.matcher(cookies);
|
|
||||||
if (matcher.find()) {
|
|
||||||
return matcher.group(1);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String getCookie(@Nullable final String webViewUrl) {
|
|
||||||
final List<String> domains = new ArrayList<>(Arrays.asList(
|
|
||||||
"https://instagram.com",
|
|
||||||
"https://instagram.com/",
|
|
||||||
"http://instagram.com",
|
|
||||||
"http://instagram.com",
|
|
||||||
"https://www.instagram.com",
|
|
||||||
"https://www.instagram.com/",
|
|
||||||
"http://www.instagram.com",
|
|
||||||
"http://www.instagram.com/"
|
|
||||||
));
|
|
||||||
if (!TextUtils.isEmpty(webViewUrl)) {
|
|
||||||
domains.add(0, webViewUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getLongestCookie(domains);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String getLongestCookie(final List<String> domains) {
|
|
||||||
int longestLength = 0;
|
|
||||||
String longestCookie = null;
|
|
||||||
|
|
||||||
for (final String domain : domains) {
|
|
||||||
final String cookie = COOKIE_MANAGER.getCookie(domain);
|
|
||||||
if (cookie != null) {
|
|
||||||
final int cookieLength = cookie.length();
|
|
||||||
if (cookieLength > longestLength) {
|
|
||||||
longestCookie = cookie;
|
|
||||||
longestLength = cookieLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return longestCookie;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeAllAccounts(context: Context?, callback: RepositoryCallback<Void?>?) {
|
||||||
|
val cookieStore = NET_COOKIE_MANAGER.cookieStore ?: return
|
||||||
|
cookieStore.removeAll()
|
||||||
|
try {
|
||||||
|
AccountRepository.getInstance(AccountDataSource.getInstance(context!!))
|
||||||
|
.deleteAllAccounts(callback)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "setupCookies", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUserIdFromCookie(cookies: String?): Long {
|
||||||
|
val dsUserId = getCookieValue(cookies, "ds_user_id") ?: return 0
|
||||||
|
try {
|
||||||
|
return dsUserId.toLong()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
Log.e(TAG, "getUserIdFromCookie: ", e)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCsrfTokenFromCookie(cookies: String?): String? {
|
||||||
|
return getCookieValue(cookies, "csrftoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCookieValue(cookies: String?, name: String): String? {
|
||||||
|
if (cookies == null) return null
|
||||||
|
val pattern = Pattern.compile("$name=(.+?);")
|
||||||
|
val matcher = pattern.matcher(cookies)
|
||||||
|
return if (matcher.find()) {
|
||||||
|
matcher.group(1)
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCookie(webViewUrl: String?): String? {
|
||||||
|
val domains: List<String> = listOfNotNull(
|
||||||
|
if (!TextUtils.isEmpty(webViewUrl)) webViewUrl else null,
|
||||||
|
"https://instagram.com",
|
||||||
|
"https://instagram.com/",
|
||||||
|
"http://instagram.com",
|
||||||
|
"http://instagram.com",
|
||||||
|
"https://www.instagram.com",
|
||||||
|
"https://www.instagram.com/",
|
||||||
|
"http://www.instagram.com",
|
||||||
|
"http://www.instagram.com/",
|
||||||
|
)
|
||||||
|
return getLongestCookie(domains)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLongestCookie(domains: List<String>): String? {
|
||||||
|
var longestLength = 0
|
||||||
|
var longestCookie: String? = null
|
||||||
|
for (domain in domains) {
|
||||||
|
val cookie = COOKIE_MANAGER.getCookie(domain)
|
||||||
|
if (cookie != null) {
|
||||||
|
val cookieLength = cookie.length
|
||||||
|
if (cookieLength > longestLength) {
|
||||||
|
longestCookie = cookie
|
||||||
|
longestLength = cookieLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return longestCookie
|
||||||
|
}
|
@ -8,29 +8,6 @@ public class CubicInterpolation {
|
|||||||
private final int tangentFactor;
|
private final int tangentFactor;
|
||||||
private final int length;
|
private final int length;
|
||||||
|
|
||||||
// constructor: (array, config) ->
|
|
||||||
// @array = array.slice 0 #copy the array
|
|
||||||
// @length = @array.length #cache length
|
|
||||||
|
|
||||||
// class CubicInterpolator extends AbstractInterpolator
|
|
||||||
// constructor: (array, config)->
|
|
||||||
// #clamp cubic tension to [0,1] range
|
|
||||||
// @tangentFactor = 1 - Math.max 0, Math.min 1, config.cubicTension
|
|
||||||
// super
|
|
||||||
//
|
|
||||||
// # Cardinal spline with tension 0.5)
|
|
||||||
// getTangent: (k) -> @tangentFactor*(@getClippedInput(k + 1) - @getClippedInput(k - 1))/2
|
|
||||||
//
|
|
||||||
// interpolate: (t) ->
|
|
||||||
// k = Math.floor t
|
|
||||||
// m = [(@getTangent k), (@getTangent k+1)] #get tangents
|
|
||||||
// p = [(@getClippedInput k), (@getClippedInput k+1)] #get points
|
|
||||||
// #Translate t to interpolate between k and k+1
|
|
||||||
// t -= k
|
|
||||||
// t2 = t*t #t^2
|
|
||||||
// t3 = t*t2 #t^3
|
|
||||||
// #Apply cubic hermite spline formula
|
|
||||||
// return (2*t3 - 3*t2 + 1)*p[0] + (t3 - 2*t2 + t)*m[0] + (-2*t3 + 3*t2)*p[1] + (t3 - t2)*m[1]
|
|
||||||
public CubicInterpolation(final float[] array, final int cubicTension) {
|
public CubicInterpolation(final float[] array, final int cubicTension) {
|
||||||
this.array = Arrays.copyOf(array, array.length);
|
this.array = Arrays.copyOf(array, array.length);
|
||||||
this.length = array.length;
|
this.length = array.length;
|
||||||
@ -55,16 +32,6 @@ public class CubicInterpolation {
|
|||||||
return (2 * t3 - 3 * t2 + 1) * p[0] + (t3 - 2 * t2 + t1) * m[0] + (-2 * t3 + 3 * t2) * p[1] + (t3 - t2) * m[1];
|
return (2 * t3 - 3 * t2 + 1) * p[0] + (t3 - 2 * t2 + t1) * m[0] + (-2 * t3 + 3 * t2) * p[1] + (t3 - t2) * m[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// getClippedInput: (i) ->
|
|
||||||
// #Normal behavior for indexes within bounds
|
|
||||||
// if 0 <= i < @length
|
|
||||||
// @array[i]
|
|
||||||
// else
|
|
||||||
// @clipHelper i
|
|
||||||
//
|
|
||||||
// clipHelperClamp: (i) -> @array[clipClamp i, @length]
|
|
||||||
// clipClamp = (i, n) -> Math.max 0, Math.min i, n - 1
|
|
||||||
|
|
||||||
private float getClippedInput(int i) {
|
private float getClippedInput(int i) {
|
||||||
if (i >= 0 && i < length) {
|
if (i >= 0 && i < length) {
|
||||||
return array[i];
|
return array[i];
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package awais.instagrabber.utils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
public final class DataBox extends SQLiteOpenHelper {
|
|
||||||
private static final String TAG = "DataBox";
|
|
||||||
|
|
||||||
private static DataBox sInstance;
|
|
||||||
|
|
||||||
private final static int VERSION = 3;
|
|
||||||
|
|
||||||
public static synchronized DataBox getInstance(final Context context) {
|
|
||||||
if (sInstance == null) sInstance = new DataBox(context.getApplicationContext());
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataBox(@Nullable final Context context) {
|
|
||||||
super(context, "cookiebox.db", null, VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@NonNull final SQLiteDatabase db) {
|
|
||||||
Log.i(TAG, "Creating tables...");
|
|
||||||
Log.i(TAG, "Tables created!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
|
||||||
Log.i(TAG, String.format("Updating DB from v%d to v%d", oldVersion, newVersion));
|
|
||||||
// switch without break, so that all migrations from a previous version to new are run
|
|
||||||
switch (oldVersion) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
}
|
|
||||||
Log.i(TAG, String.format("DB update from v%d to v%d completed!", oldVersion, newVersion));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +1,29 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import java.util.regex.Pattern
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
object DeepLinkParser {
|
||||||
|
private val TYPE_PATTERN_MAP: Map<DeepLink.Type, DeepLinkPattern> = mapOf(
|
||||||
|
DeepLink.Type.USER to DeepLinkPattern("instagram://user?username="),
|
||||||
|
)
|
||||||
|
|
||||||
import java.util.Map;
|
@JvmStatic
|
||||||
import java.util.regex.Pattern;
|
fun parse(text: String): DeepLink? {
|
||||||
|
for ((key, value) in TYPE_PATTERN_MAP) {
|
||||||
public final class DeepLinkParser {
|
if (text.startsWith(value.patternText)) {
|
||||||
private static final Map<DeepLink.Type, DeepLinkPattern> TYPE_PATTERN_MAP = ImmutableMap
|
return DeepLink(key, value.pattern.matcher(text).replaceAll(""))
|
||||||
.<DeepLink.Type, DeepLinkPattern>builder()
|
|
||||||
.put(DeepLink.Type.USER, new DeepLinkPattern("instagram://user?username="))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static DeepLink parse(@NonNull final String text) {
|
|
||||||
for (final Map.Entry<DeepLink.Type, DeepLinkPattern> entry : TYPE_PATTERN_MAP.entrySet()) {
|
|
||||||
if (text.startsWith(entry.getValue().getPatternText())) {
|
|
||||||
final String value = entry.getValue().getPattern().matcher(text).replaceAll("");
|
|
||||||
return new DeepLink(entry.getKey(), value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DeepLinkPattern {
|
data class DeepLinkPattern(val patternText: String) {
|
||||||
private final String patternText;
|
val pattern: Pattern = Pattern.compile(patternText, Pattern.LITERAL)
|
||||||
private final Pattern pattern;
|
|
||||||
|
|
||||||
public DeepLinkPattern(final String patternText) {
|
|
||||||
this.patternText = patternText;
|
|
||||||
pattern = Pattern.compile(patternText, Pattern.LITERAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPatternText() {
|
|
||||||
return patternText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pattern getPattern() {
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DeepLink {
|
data class DeepLink(val type: Type, val value: String) {
|
||||||
private final Type type;
|
enum class Type {
|
||||||
private final String value;
|
USER
|
||||||
|
|
||||||
public DeepLink(final Type type, final String value) {
|
|
||||||
this.type = type;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
USER,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,91 +1,83 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources;
|
import android.view.ContextThemeWrapper
|
||||||
import android.view.ContextThemeWrapper;
|
import awais.instagrabber.fragments.settings.PreferenceKeys
|
||||||
|
import java.util.*
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
|
||||||
|
|
||||||
// taken from my app TESV Console Codes
|
// taken from my app TESV Console Codes
|
||||||
public final class LocaleUtils {
|
object LocaleUtils {
|
||||||
private static Locale defaultLocale, currentLocale;
|
private var defaultLocale: Locale? = null
|
||||||
|
|
||||||
public static void setLocale(Context baseContext) {
|
@JvmStatic
|
||||||
if (defaultLocale == null) defaultLocale = Locale.getDefault();
|
var currentLocale: Locale? = null
|
||||||
|
private set
|
||||||
|
|
||||||
if (baseContext instanceof ContextThemeWrapper)
|
@JvmStatic
|
||||||
baseContext = ((ContextThemeWrapper) baseContext).getBaseContext();
|
fun setLocale(baseContext: Context) {
|
||||||
|
var baseContext1 = baseContext
|
||||||
if (Utils.settingsHelper == null)
|
if (defaultLocale == null) defaultLocale = Locale.getDefault()
|
||||||
Utils.settingsHelper = new SettingsHelper(baseContext);
|
if (baseContext1 is ContextThemeWrapper) baseContext1 = baseContext1.baseContext
|
||||||
|
if (Utils.settingsHelper == null) Utils.settingsHelper = SettingsHelper(baseContext1)
|
||||||
final String appLanguageSettings = Utils.settingsHelper.getString(PreferenceKeys.APP_LANGUAGE);
|
val appLanguageSettings = Utils.settingsHelper.getString(PreferenceKeys.APP_LANGUAGE)
|
||||||
final String lang = LocaleUtils.getCorrespondingLanguageCode(appLanguageSettings);
|
val lang = getCorrespondingLanguageCode(appLanguageSettings)
|
||||||
|
currentLocale = when {
|
||||||
currentLocale = TextUtils.isEmpty(lang) ? defaultLocale :
|
TextUtils.isEmpty(lang) -> defaultLocale
|
||||||
(lang.contains("_") ? new Locale(lang.split("_")[0], lang.split("_")[1]) : new Locale(lang));
|
lang!!.contains("_") -> {
|
||||||
Locale.setDefault(currentLocale);
|
val split = lang.split("_")
|
||||||
|
Locale(split[0], split[1])
|
||||||
final Resources res = baseContext.getResources();
|
}
|
||||||
final Configuration config = res.getConfiguration();
|
else -> Locale(lang)
|
||||||
|
}
|
||||||
config.locale = currentLocale;
|
currentLocale?.let {
|
||||||
config.setLocale(currentLocale);
|
Locale.setDefault(it)
|
||||||
config.setLayoutDirection(currentLocale);
|
val res = baseContext1.resources
|
||||||
|
val config = res.configuration
|
||||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
// config.locale = currentLocale
|
||||||
}
|
config.setLocale(it)
|
||||||
|
config.setLayoutDirection(it)
|
||||||
public static Locale getCurrentLocale() {
|
res.updateConfiguration(config, res.displayMetrics)
|
||||||
return currentLocale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateConfig(final ContextThemeWrapper wrapper) {
|
|
||||||
if (currentLocale != null) {
|
|
||||||
final Configuration configuration = new Configuration();
|
|
||||||
configuration.locale = currentLocale;
|
|
||||||
configuration.setLocale(currentLocale);
|
|
||||||
wrapper.applyOverrideConfiguration(configuration);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@JvmStatic
|
||||||
public static String getCorrespondingLanguageCode(final String appLanguageSettings) {
|
fun updateConfig(wrapper: ContextThemeWrapper) {
|
||||||
if (TextUtils.isEmpty(appLanguageSettings)) return null;
|
if (currentLocale == null) return
|
||||||
|
val configuration = Configuration()
|
||||||
final int appLanguageIndex = Integer.parseInt(appLanguageSettings);
|
// configuration.locale = currentLocale
|
||||||
switch (appLanguageIndex) {
|
configuration.setLocale(currentLocale)
|
||||||
case 1: return "en";
|
wrapper.applyOverrideConfiguration(configuration)
|
||||||
case 2: return "fr";
|
|
||||||
case 3: return "es";
|
|
||||||
case 4: return "zh_CN";
|
|
||||||
case 5: return "in";
|
|
||||||
case 6: return "it";
|
|
||||||
case 7: return "de";
|
|
||||||
case 8: return "pl";
|
|
||||||
case 9: return "tr";
|
|
||||||
case 10: return "pt";
|
|
||||||
case 11: return "fa";
|
|
||||||
case 12: return "mk";
|
|
||||||
case 13: return "vi";
|
|
||||||
case 14: return "zh_TW";
|
|
||||||
case 15: return "ca";
|
|
||||||
case 16: return "ru";
|
|
||||||
case 17: return "hi";
|
|
||||||
case 18: return "nl";
|
|
||||||
case 19: return "sk";
|
|
||||||
case 20: return "ja";
|
|
||||||
case 21: return "el";
|
|
||||||
case 22: return "eu";
|
|
||||||
case 23: return "sv";
|
|
||||||
case 24: return "ko";
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fun getCorrespondingLanguageCode(appLanguageSettings: String): String? {
|
||||||
|
if (TextUtils.isEmpty(appLanguageSettings)) return null
|
||||||
|
when (appLanguageSettings.toInt()) {
|
||||||
|
1 -> return "en"
|
||||||
|
2 -> return "fr"
|
||||||
|
3 -> return "es"
|
||||||
|
4 -> return "zh_CN"
|
||||||
|
5 -> return "in"
|
||||||
|
6 -> return "it"
|
||||||
|
7 -> return "de"
|
||||||
|
8 -> return "pl"
|
||||||
|
9 -> return "tr"
|
||||||
|
10 -> return "pt"
|
||||||
|
11 -> return "fa"
|
||||||
|
12 -> return "mk"
|
||||||
|
13 -> return "vi"
|
||||||
|
14 -> return "zh_TW"
|
||||||
|
15 -> return "ca"
|
||||||
|
16 -> return "ru"
|
||||||
|
17 -> return "hi"
|
||||||
|
18 -> return "nl"
|
||||||
|
19 -> return "sk"
|
||||||
|
20 -> return "ja"
|
||||||
|
21 -> return "el"
|
||||||
|
22 -> return "eu"
|
||||||
|
23 -> return "sv"
|
||||||
|
24 -> return "ko"
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import awais.instagrabber.models.UploadVideoOptions
|
|||||||
import awais.instagrabber.models.enums.MediaItemType
|
import awais.instagrabber.models.enums.MediaItemType
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
private const val LOWER = 1000000000L
|
private const val LOWER = 1000000000L
|
||||||
@ -109,7 +110,7 @@ fun generateUploadId(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun generateName(uploadId: String): String {
|
fun generateName(uploadId: String): String {
|
||||||
val random = NumberUtils.random(LOWER, UPPER + 1)
|
val random = Random.nextLong(LOWER, UPPER + 1)
|
||||||
return "${uploadId}_0_$random"
|
return "${uploadId}_0_$random"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
@ -15,77 +15,28 @@ package awais.instagrabber.utils;
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.util.ObjectsCompat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container to ease passing around a tuple of two objects. This object provides a sensible
|
* Container to ease passing around a tuple of two objects. This object provides a sensible
|
||||||
* implementation of equals(), returning true if equals() is true on each of the contained
|
* implementation of equals(), returning true if equals() is true on each of the contained
|
||||||
* objects.
|
* objects.
|
||||||
*/
|
*/
|
||||||
public class NullSafePair<F, S> {
|
/**
|
||||||
public final @NonNull
|
* Constructor for a Pair.
|
||||||
F first;
|
*
|
||||||
public final @NonNull
|
* @param first the first object in the Pair
|
||||||
S second;
|
* @param second the second object in the pair
|
||||||
|
*/
|
||||||
/**
|
data class NullSafePair<F, S>(@JvmField val first: F, @JvmField val second: S) {
|
||||||
* Constructor for a Pair.
|
companion object {
|
||||||
*
|
/**
|
||||||
* @param first the first object in the Pair
|
* Convenience method for creating an appropriately typed pair.
|
||||||
* @param second the second object in the pair
|
*
|
||||||
*/
|
* @param a the first object in the Pair
|
||||||
public NullSafePair(@NonNull F first, @NonNull S second) {
|
* @param b the second object in the pair
|
||||||
this.first = first;
|
* @return a Pair that is templatized with the types of a and b
|
||||||
this.second = second;
|
*/
|
||||||
}
|
fun <A, B> create(a: A, b: B): NullSafePair<A, B> {
|
||||||
|
return NullSafePair(a, b)
|
||||||
/**
|
|
||||||
* Checks the two objects for equality by delegating to their respective
|
|
||||||
* {@link Object#equals(Object)} methods.
|
|
||||||
*
|
|
||||||
* @param o the {@link androidx.core.util.Pair} to which this one is to be checked for equality
|
|
||||||
* @return true if the underlying objects of the Pair are both considered
|
|
||||||
* equal
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof androidx.core.util.Pair)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
androidx.core.util.Pair<?, ?> p = (androidx.core.util.Pair<?, ?>) o;
|
|
||||||
return ObjectsCompat.equals(p.first, first) && ObjectsCompat.equals(p.second, second);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Compute a hash code using the hash codes of the underlying objects
|
|
||||||
*
|
|
||||||
* @return a hashcode of the Pair
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return first.hashCode() ^ second.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Pair{" + first + " " + second + "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for creating an appropriately typed pair.
|
|
||||||
*
|
|
||||||
* @param a the first object in the Pair
|
|
||||||
* @param b the second object in the pair
|
|
||||||
* @return a Pair that is templatized with the types of a and b
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public static <A, B> androidx.core.util.Pair<A, B> create(@Nullable A a, @Nullable B b) {
|
|
||||||
return new androidx.core.util.Pair<A, B>(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,149 +1,87 @@
|
|||||||
package awais.instagrabber.utils;
|
@file:JvmName("NumberUtils")
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
package awais.instagrabber.utils
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.*
|
||||||
import java.util.Random;
|
import kotlin.math.ln
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
public final class NumberUtils {
|
fun getResultingHeight(requiredWidth: Int, height: Int, width: Int): Int {
|
||||||
// @NonNull
|
return requiredWidth * height / width
|
||||||
// public static String millisToString(final long timeMs) {
|
|
||||||
// final long totalSeconds = timeMs / 1000;
|
|
||||||
//
|
|
||||||
// final long seconds = totalSeconds % 60;
|
|
||||||
// final long minutes = totalSeconds / 60 % 60;
|
|
||||||
// final long hours = totalSeconds / 3600;
|
|
||||||
//
|
|
||||||
// final String strSec = Long.toString(seconds);
|
|
||||||
// final String strMin = Long.toString(minutes);
|
|
||||||
//
|
|
||||||
// final String strRetSec = strSec.length() > 1 ? strSec : "0" + seconds;
|
|
||||||
// final String strRetMin = strMin.length() > 1 ? strMin : "0" + minutes;
|
|
||||||
//
|
|
||||||
// final String retMinSec = strRetMin + ':' + strRetSec;
|
|
||||||
//
|
|
||||||
// if (hours > 0)
|
|
||||||
// return Long.toString(hours) + ':' + retMinSec;
|
|
||||||
// return retMinSec;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static int getResultingHeight(final int requiredWidth, final int height, final int width) {
|
|
||||||
return requiredWidth * height / width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getResultingWidth(final int requiredHeight, final int height, final int width) {
|
|
||||||
return requiredHeight * width / height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long random(long origin, long bound) {
|
|
||||||
final Random random = new Random();
|
|
||||||
long r = random.nextLong();
|
|
||||||
long n = bound - origin, m = n - 1;
|
|
||||||
if ((n & m) == 0L) // power of two
|
|
||||||
r = (r & m) + origin;
|
|
||||||
else if (n > 0L) { // reject over-represented candidates
|
|
||||||
//noinspection StatementWithEmptyBody
|
|
||||||
for (long u = r >>> 1; // ensure non-negative
|
|
||||||
u + m - (r = u % n) < 0L; // rejection check
|
|
||||||
u = random.nextLong() >>> 1) // retry
|
|
||||||
;
|
|
||||||
r += origin;
|
|
||||||
} else { // range not representable as long
|
|
||||||
while (r < origin || r >= bound)
|
|
||||||
r = random.nextLong();
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static NullSafePair<Integer, Integer> calculateWidthHeight(final int height, final int width, final int maxHeight, final int maxWidth) {
|
|
||||||
if (width > maxWidth) {
|
|
||||||
int tempHeight = getResultingHeight(maxWidth, height, width);
|
|
||||||
int tempWidth = maxWidth;
|
|
||||||
if (tempHeight > maxHeight) {
|
|
||||||
tempWidth = getResultingWidth(maxHeight, tempHeight, tempWidth);
|
|
||||||
tempHeight = maxHeight;
|
|
||||||
}
|
|
||||||
return new NullSafePair<>(tempWidth, tempHeight);
|
|
||||||
}
|
|
||||||
if ((height < maxHeight && width < maxWidth) || (height > maxHeight)) {
|
|
||||||
int tempWidth = getResultingWidth(maxHeight, height, width);
|
|
||||||
int tempHeight = maxHeight;
|
|
||||||
if (tempWidth > maxWidth) {
|
|
||||||
tempHeight = getResultingHeight(maxWidth, tempHeight, tempWidth);
|
|
||||||
tempWidth = maxWidth;
|
|
||||||
}
|
|
||||||
return new NullSafePair<>(tempWidth, tempHeight);
|
|
||||||
}
|
|
||||||
return new NullSafePair<>(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float roundFloat2Decimals(final float value) {
|
|
||||||
return ((int) ((value + (value >= 0 ? 1 : -1) * 0.005f) * 100)) / 100f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String abbreviate(final long number) {
|
|
||||||
return abbreviate(number, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String abbreviate(final long number, @Nullable final AbbreviateOptions options) {
|
|
||||||
// adapted from https://stackoverflow.com/a/9769590/1436766
|
|
||||||
int threshold = 1000;
|
|
||||||
boolean addSpace = false;
|
|
||||||
if (options != null) {
|
|
||||||
threshold = options.getThreshold();
|
|
||||||
addSpace = options.addSpaceBeforePrefix();
|
|
||||||
}
|
|
||||||
if (number < threshold) return "" + number;
|
|
||||||
int exp = (int) (Math.log(number) / Math.log(threshold));
|
|
||||||
return String.format(Locale.US,
|
|
||||||
"%.1f%s%c",
|
|
||||||
number / Math.pow(threshold, exp),
|
|
||||||
addSpace ? " " : "",
|
|
||||||
"kMGTPE".charAt(exp - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class AbbreviateOptions {
|
|
||||||
private final int threshold;
|
|
||||||
private final boolean addSpaceBeforePrefix;
|
|
||||||
|
|
||||||
public static final class Builder {
|
|
||||||
|
|
||||||
private int threshold = 1000;
|
|
||||||
private boolean addSpaceBeforePrefix = false;
|
|
||||||
|
|
||||||
public Builder setThreshold(final int threshold) {
|
|
||||||
this.threshold = threshold;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setAddSpaceBeforePrefix(final boolean addSpaceBeforePrefix) {
|
|
||||||
this.addSpaceBeforePrefix = addSpaceBeforePrefix;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public AbbreviateOptions build() {
|
|
||||||
return new AbbreviateOptions(threshold, addSpaceBeforePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private AbbreviateOptions(final int threshold, final boolean addSpaceBeforePrefix) {
|
|
||||||
this.threshold = threshold;
|
|
||||||
this.addSpaceBeforePrefix = addSpaceBeforePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getThreshold() {
|
|
||||||
return threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addSpaceBeforePrefix() {
|
|
||||||
return addSpaceBeforePrefix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getResultingWidth(requiredHeight: Int, height: Int, width: Int): Int {
|
||||||
|
return requiredHeight * width / height
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Replace all usages with kotlin Random.nextLong() once converted to kotlin
|
||||||
|
fun random(origin: Long, bound: Long): Long {
|
||||||
|
val random = Random()
|
||||||
|
var r = random.nextLong()
|
||||||
|
val n = bound - origin
|
||||||
|
val m = n - 1
|
||||||
|
when {
|
||||||
|
n and m == 0L -> r = (r and m) + origin // power of two
|
||||||
|
n > 0L -> {
|
||||||
|
// reject over-represented candidates
|
||||||
|
var u = r ushr 1 // ensure non-negative
|
||||||
|
while (u + m - u % n.also { r = it } < 0L) { // rejection check
|
||||||
|
// retry
|
||||||
|
u = random.nextLong() ushr 1
|
||||||
|
}
|
||||||
|
r += origin
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// range not representable as long
|
||||||
|
while (r < origin || r >= bound) r = random.nextLong()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateWidthHeight(height: Int, width: Int, maxHeight: Int, maxWidth: Int): NullSafePair<Int, Int> {
|
||||||
|
if (width > maxWidth) {
|
||||||
|
var tempHeight = getResultingHeight(maxWidth, height, width)
|
||||||
|
var tempWidth = maxWidth
|
||||||
|
if (tempHeight > maxHeight) {
|
||||||
|
tempWidth = getResultingWidth(maxHeight, tempHeight, tempWidth)
|
||||||
|
tempHeight = maxHeight
|
||||||
|
}
|
||||||
|
return NullSafePair(tempWidth, tempHeight)
|
||||||
|
}
|
||||||
|
if (height < maxHeight && width < maxWidth || height > maxHeight) {
|
||||||
|
var tempWidth = getResultingWidth(maxHeight, height, width)
|
||||||
|
var tempHeight = maxHeight
|
||||||
|
if (tempWidth > maxWidth) {
|
||||||
|
tempHeight = getResultingHeight(maxWidth, tempHeight, tempWidth)
|
||||||
|
tempWidth = maxWidth
|
||||||
|
}
|
||||||
|
return NullSafePair(tempWidth, tempHeight)
|
||||||
|
}
|
||||||
|
return NullSafePair(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun roundFloat2Decimals(value: Float): Float {
|
||||||
|
return ((value + (if (value >= 0) 1 else -1) * 0.005f) * 100).toInt() / 100f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun abbreviate(number: Long, options: AbbreviateOptions? = null): String {
|
||||||
|
// adapted from https://stackoverflow.com/a/9769590/1436766
|
||||||
|
var threshold = 1000
|
||||||
|
var addSpace = false
|
||||||
|
if (options != null) {
|
||||||
|
threshold = options.threshold
|
||||||
|
addSpace = options.addSpaceBeforePrefix
|
||||||
|
}
|
||||||
|
if (number < threshold) return "" + number
|
||||||
|
val exp = (ln(number.toDouble()) / ln(threshold.toDouble())).toInt()
|
||||||
|
return String.format(
|
||||||
|
Locale.US,
|
||||||
|
"%.1f%s%c",
|
||||||
|
number / threshold.toDouble().pow(exp.toDouble()),
|
||||||
|
if (addSpace) " " else "",
|
||||||
|
"kMGTPE"[exp - 1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AbbreviateOptions(val threshold: Int = 1000, val addSpaceBeforePrefix: Boolean = false)
|
@ -1,69 +1,27 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
|
||||||
import java.time.temporal.ChronoUnit;
|
import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse
|
||||||
import java.util.Collections;
|
import java.time.LocalDateTime
|
||||||
import java.util.List;
|
import java.time.temporal.ChronoUnit
|
||||||
|
|
||||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
object RankedRecipientsCache {
|
||||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse;
|
private var lastUpdatedOn: LocalDateTime? = null
|
||||||
|
var isUpdateInitiated = false
|
||||||
|
var isFailed = false
|
||||||
|
val rankedRecipients: List<RankedRecipient>
|
||||||
|
get() = response?.rankedRecipients ?: emptyList()
|
||||||
|
|
||||||
public class RankedRecipientsCache {
|
var response: RankedRecipientsResponse? = null
|
||||||
private static final Object LOCK = new Object();
|
set(value) {
|
||||||
|
field = value
|
||||||
private static RankedRecipientsCache instance;
|
lastUpdatedOn = LocalDateTime.now()
|
||||||
|
|
||||||
public static RankedRecipientsCache getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new RankedRecipientsCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LocalDateTime lastUpdatedOn;
|
val isExpired: Boolean
|
||||||
private RankedRecipientsResponse response;
|
get() {
|
||||||
private boolean updateInitiated = false;
|
if (lastUpdatedOn == null || response == null) return true
|
||||||
private boolean failed = false;
|
val expiresInSecs = response!!.expires
|
||||||
|
return LocalDateTime.now().isAfter(lastUpdatedOn!!.plus(expiresInSecs, ChronoUnit.SECONDS))
|
||||||
private RankedRecipientsCache() {}
|
|
||||||
|
|
||||||
public List<RankedRecipient> getRankedRecipients() {
|
|
||||||
if (response != null) {
|
|
||||||
return response.getRankedRecipients();
|
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void setRankedRecipientsResponse(final RankedRecipientsResponse response) {
|
|
||||||
this.response = response;
|
|
||||||
lastUpdatedOn = LocalDateTime.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExpired() {
|
|
||||||
if (lastUpdatedOn == null || response == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final long expiresInSecs = response.getExpires();
|
|
||||||
return LocalDateTime.now().isAfter(lastUpdatedOn.plus(expiresInSecs, ChronoUnit.SECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUpdateInitiated() {
|
|
||||||
return updateInitiated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdateInitiated(final boolean updateInitiated) {
|
|
||||||
this.updateInitiated = updateInitiated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFailed() {
|
|
||||||
return failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFailed(final boolean failed) {
|
|
||||||
this.failed = failed;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +1,12 @@
|
|||||||
package awais.instagrabber.utils;
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
import android.util.Pair;
|
import android.util.Pair
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
import java.io.Serializable;
|
/**
|
||||||
|
* Constructor for a Pair.
|
||||||
public class SerializablePair<F, S> extends Pair<F, S> implements Serializable {
|
*
|
||||||
/**
|
* @param first the first object in the Pair
|
||||||
* Constructor for a Pair.
|
* @param second the second object in the pair
|
||||||
*
|
*/
|
||||||
* @param first the first object in the Pair
|
data class SerializablePair<F, S>(@JvmField val first: F, @JvmField val second: S) : Pair<F, S>(first, second), Serializable
|
||||||
* @param second the second object in the pair
|
|
||||||
*/
|
|
||||||
public SerializablePair(final F first, final S second) {
|
|
||||||
super(first, second);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +1,36 @@
|
|||||||
package awais.instagrabber.utils;
|
@file:JvmName("UpdateCheckCommon")
|
||||||
|
|
||||||
import android.content.Context;
|
package awais.instagrabber.utils
|
||||||
import android.content.DialogInterface;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import awais.instagrabber.BuildConfig
|
||||||
|
import awais.instagrabber.R
|
||||||
|
import awais.instagrabber.utils.AppExecutors.mainThread
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
fun shouldShowUpdateDialog(
|
||||||
|
force: Boolean,
|
||||||
import awais.instagrabber.BuildConfig;
|
version: String
|
||||||
import awais.instagrabber.R;
|
): Boolean {
|
||||||
|
val skippedVersion = Utils.settingsHelper.getString(Constants.SKIPPED_VERSION)
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
return force || !BuildConfig.DEBUG && skippedVersion != version
|
||||||
|
|
||||||
public final class UpdateCheckCommon {
|
|
||||||
|
|
||||||
public static boolean shouldShowUpdateDialog(final boolean force,
|
|
||||||
@NonNull final String version) {
|
|
||||||
final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION);
|
|
||||||
return force || (!BuildConfig.DEBUG && !skippedVersion.equals(version));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showUpdateDialog(@NonNull final Context context,
|
|
||||||
@NonNull final String version,
|
|
||||||
@NonNull final DialogInterface.OnClickListener onDownloadClickListener) {
|
|
||||||
AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
|
||||||
new MaterialAlertDialogBuilder(context)
|
|
||||||
.setTitle(context.getString(R.string.update_available, version))
|
|
||||||
.setNeutralButton(R.string.skip_update, (dialog, which) -> {
|
|
||||||
settingsHelper.putString(Constants.SKIPPED_VERSION, version);
|
|
||||||
dialog.dismiss();
|
|
||||||
})
|
|
||||||
.setPositiveButton(R.string.action_download, onDownloadClickListener)
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showUpdateDialog(
|
||||||
|
context: Context,
|
||||||
|
version: String,
|
||||||
|
onDownloadClickListener: DialogInterface.OnClickListener
|
||||||
|
) {
|
||||||
|
mainThread.execute {
|
||||||
|
MaterialAlertDialogBuilder(context).apply {
|
||||||
|
setTitle(context.getString(R.string.update_available, version))
|
||||||
|
setNeutralButton(R.string.skip_update) { dialog: DialogInterface, which: Int ->
|
||||||
|
Utils.settingsHelper.putString(Constants.SKIPPED_VERSION, version)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
setPositiveButton(R.string.action_download, onDownloadClickListener)
|
||||||
|
setNegativeButton(R.string.cancel, null)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
@ -1,85 +1,82 @@
|
|||||||
package awais.instagrabber.utils;
|
@file:JvmName("UserAgentUtils")
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
public class UserAgentUtils {
|
/* GraphQL user agents (which are just standard browser UA"s).
|
||||||
|
* Go to https://www.whatismybrowser.com/guides/the-latest-user-agent/ to update it
|
||||||
|
* Windows first (Assume win64 not wow64): Chrome, Firefox, Edge
|
||||||
|
* Then macOS: Chrome, Firefox, Safari
|
||||||
|
*/
|
||||||
|
@JvmField
|
||||||
|
val browsers = arrayOf(
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.62",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11.3; rv:88.0) Gecko/20100101 Firefox/88.0",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15"
|
||||||
|
)
|
||||||
|
|
||||||
/* GraphQL user agents (which are just standard browser UA"s).
|
// use APKpure, assume arm64-v8a
|
||||||
* Go to https://www.whatismybrowser.com/guides/the-latest-user-agent/ to update it
|
private const val igVersion = "188.0.0.35.124"
|
||||||
* Windows first (Assume win64 not wow64): Chrome, Firefox, Edge
|
private const val igVersionCode = "292080186"
|
||||||
* Then macOS: Chrome, Firefox, Safari
|
|
||||||
*/
|
|
||||||
public static final String[] browsers = {
|
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
|
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0",
|
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.62",
|
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
|
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11.3; rv:88.0) Gecko/20100101 Firefox/88.0",
|
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15"
|
|
||||||
};
|
|
||||||
// use APKpure, assume arm64-v8a
|
|
||||||
private static final String igVersion = "188.0.0.35.124";
|
|
||||||
private static final String igVersionCode = "292080186";
|
|
||||||
// you can pick *any* device as long as you LEAVE OUT the resolution for maximum download quality
|
|
||||||
public static final String[] devices = {
|
|
||||||
// https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json
|
|
||||||
"25/7.1.1; 440dpi; 2880x5884; Xiaomi; Mi Note 3; jason; qcom",
|
|
||||||
"23/6.0.1; 480dpi; 2880x5884; Xiaomi; Redmi Note 3; kenzo; qcom",
|
|
||||||
"23/6.0; 480dpi; 2880x5884; Xiaomi; Redmi Note 4; nikel; mt6797",
|
|
||||||
"24/7.0; 480dpi; 2880x5884; Xiaomi/xiaomi; Redmi Note 4; mido; qcom",
|
|
||||||
"23/6.0; 480dpi; 2880x5884; Xiaomi; Redmi Note 4X; nikel; mt6797",
|
|
||||||
"27/8.1.0; 440dpi; 2880x5884; Xiaomi/xiaomi; Redmi Note 5; whyred; qcom",
|
|
||||||
"23/6.0.1; 480dpi; 2880x5884; Xiaomi; Redmi 4; markw; qcom",
|
|
||||||
"27/8.1.0; 440dpi; 2880x5884; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
|
|
||||||
"25/7.1.2; 440dpi; 2880x5884; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; Xiaomi; MI 5; gemini; qcom",
|
|
||||||
"27/8.1.0; 480dpi; 2880x5884; Xiaomi/xiaomi; Mi A1; tissot_sprout; qcom",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; Xiaomi; MI 6; sagit; qcom",
|
|
||||||
"25/7.1.1; 440dpi; 2880x5884; Xiaomi; MI MAX 2; oxygen; qcom",
|
|
||||||
"24/7.0; 480dpi; 2880x5884; Xiaomi; MI 5s; capricorn; qcom",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-A520F; a5y17lte; samsungexynos7880",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G950F; dreamlte; samsungexynos8895",
|
|
||||||
"26/8.0.0; 640dpi; 2880x5884; samsung; SM-G950F; dreamlte; samsungexynos8895",
|
|
||||||
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-G955F; dream2lte; samsungexynos8895",
|
|
||||||
"26/8.0.0; 560dpi; 2880x5884; samsung; SM-G955F; dream2lte; samsungexynos8895",
|
|
||||||
"24/7.0; 480dpi; 2880x5884; samsung; SM-A510F; a5xelte; samsungexynos7580",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G930F; herolte; samsungexynos8890",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G935F; hero2lte; samsungexynos8890",
|
|
||||||
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-G965F; star2lte; samsungexynos9810",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-A530F; jackpotlte; samsungexynos7885",
|
|
||||||
"24/7.0; 640dpi; 2880x5884; samsung; SM-G925F; zerolte; samsungexynos7420",
|
|
||||||
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-A720F; a7y17lte; samsungexynos7880",
|
|
||||||
"24/7.0; 640dpi; 2880x5884; samsung; SM-G920F; zeroflte; samsungexynos7420",
|
|
||||||
"24/7.0; 420dpi; 2880x5884; samsung; SM-J730FM; j7y17lte; samsungexynos7870",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G960F; starlte; samsungexynos9810",
|
|
||||||
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-N950F; greatlte; samsungexynos8895",
|
|
||||||
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-A730F; jackpot2lte; samsungexynos7885",
|
|
||||||
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-A605FN; a6plte; qcom",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; HUAWEI/HONOR; STF-L09; HWSTF; hi3660",
|
|
||||||
"27/8.1.0; 480dpi; 2880x5884; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; HUAWEI/HONOR; LLD-L31; HWLLD-H; hi6250",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; HUAWEI; ANE-LX1; HWANE; hi6250",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; HUAWEI; FIG-LX1; HWFIG-H; hi6250",
|
|
||||||
"27/8.1.0; 480dpi; 2880x5884; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
|
|
||||||
"26/8.0.0; 480dpi; 2880x5884; HUAWEI/HONOR; BND-L21; HWBND-H; hi6250",
|
|
||||||
"23/6.0.1; 420dpi; 2880x5884; LeMobile/LeEco; Le X527; le_s2_ww; qcom",
|
|
||||||
// https://github.com/mimmi20/BrowserDetector/tree/master
|
|
||||||
"28/9; 560dpi; 2880x5884; samsung; SM-N960F; crownlte; samsungexynos9810",
|
|
||||||
// mgp25
|
|
||||||
"23/6.0.1; 640dpi; 2880x5884; LGE/lge; RS988; h1; h1",
|
|
||||||
"24/7.0; 640dpi; 2880x5884; HUAWEI; LON-L29; HWLON; hi3660",
|
|
||||||
"23/6.0.1; 640dpi; 2880x5884; ZTE; ZTE A2017U; ailsa_ii; qcom",
|
|
||||||
"23/6.0.1; 640dpi; 2880x5884; samsung; SM-G935F; hero2lte; samsungexynos8890",
|
|
||||||
"23/6.0.1; 640dpi; 2880x5884; samsung; SM-G930F; herolte; samsungexynos8890"
|
|
||||||
};
|
|
||||||
|
|
||||||
@NonNull
|
// you can pick *any* device as long as you LEAVE OUT the resolution for maximum download quality
|
||||||
public static String generateBrowserUA(final int code) {
|
// https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json
|
||||||
return browsers[code];
|
@JvmField
|
||||||
}
|
val devices = arrayOf(
|
||||||
|
"25/7.1.1; 440dpi; 2880x5884; Xiaomi; Mi Note 3; jason; qcom",
|
||||||
|
"23/6.0.1; 480dpi; 2880x5884; Xiaomi; Redmi Note 3; kenzo; qcom",
|
||||||
|
"23/6.0; 480dpi; 2880x5884; Xiaomi; Redmi Note 4; nikel; mt6797",
|
||||||
|
"24/7.0; 480dpi; 2880x5884; Xiaomi/xiaomi; Redmi Note 4; mido; qcom",
|
||||||
|
"23/6.0; 480dpi; 2880x5884; Xiaomi; Redmi Note 4X; nikel; mt6797",
|
||||||
|
"27/8.1.0; 440dpi; 2880x5884; Xiaomi/xiaomi; Redmi Note 5; whyred; qcom",
|
||||||
|
"23/6.0.1; 480dpi; 2880x5884; Xiaomi; Redmi 4; markw; qcom",
|
||||||
|
"27/8.1.0; 440dpi; 2880x5884; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
|
||||||
|
"25/7.1.2; 440dpi; 2880x5884; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; Xiaomi; MI 5; gemini; qcom",
|
||||||
|
"27/8.1.0; 480dpi; 2880x5884; Xiaomi/xiaomi; Mi A1; tissot_sprout; qcom",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; Xiaomi; MI 6; sagit; qcom",
|
||||||
|
"25/7.1.1; 440dpi; 2880x5884; Xiaomi; MI MAX 2; oxygen; qcom",
|
||||||
|
"24/7.0; 480dpi; 2880x5884; Xiaomi; MI 5s; capricorn; qcom",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-A520F; a5y17lte; samsungexynos7880",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G950F; dreamlte; samsungexynos8895",
|
||||||
|
"26/8.0.0; 640dpi; 2880x5884; samsung; SM-G950F; dreamlte; samsungexynos8895",
|
||||||
|
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-G955F; dream2lte; samsungexynos8895",
|
||||||
|
"26/8.0.0; 560dpi; 2880x5884; samsung; SM-G955F; dream2lte; samsungexynos8895",
|
||||||
|
"24/7.0; 480dpi; 2880x5884; samsung; SM-A510F; a5xelte; samsungexynos7580",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G930F; herolte; samsungexynos8890",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G935F; hero2lte; samsungexynos8890",
|
||||||
|
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-G965F; star2lte; samsungexynos9810",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-A530F; jackpotlte; samsungexynos7885",
|
||||||
|
"24/7.0; 640dpi; 2880x5884; samsung; SM-G925F; zerolte; samsungexynos7420",
|
||||||
|
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-A720F; a7y17lte; samsungexynos7880",
|
||||||
|
"24/7.0; 640dpi; 2880x5884; samsung; SM-G920F; zeroflte; samsungexynos7420",
|
||||||
|
"24/7.0; 420dpi; 2880x5884; samsung; SM-J730FM; j7y17lte; samsungexynos7870",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; samsung; SM-G960F; starlte; samsungexynos9810",
|
||||||
|
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-N950F; greatlte; samsungexynos8895",
|
||||||
|
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-A730F; jackpot2lte; samsungexynos7885",
|
||||||
|
"26/8.0.0; 420dpi; 2880x5884; samsung; SM-A605FN; a6plte; qcom",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; HUAWEI/HONOR; STF-L09; HWSTF; hi3660",
|
||||||
|
"27/8.1.0; 480dpi; 2880x5884; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; HUAWEI/HONOR; LLD-L31; HWLLD-H; hi6250",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; HUAWEI; ANE-LX1; HWANE; hi6250",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; HUAWEI; FIG-LX1; HWFIG-H; hi6250",
|
||||||
|
"27/8.1.0; 480dpi; 2880x5884; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
|
||||||
|
"26/8.0.0; 480dpi; 2880x5884; HUAWEI/HONOR; BND-L21; HWBND-H; hi6250",
|
||||||
|
"23/6.0.1; 420dpi; 2880x5884; LeMobile/LeEco; Le X527; le_s2_ww; qcom", // https://github.com/mimmi20/BrowserDetector/tree/master
|
||||||
|
"28/9; 560dpi; 2880x5884; samsung; SM-N960F; crownlte; samsungexynos9810", // mgp25
|
||||||
|
"23/6.0.1; 640dpi; 2880x5884; LGE/lge; RS988; h1; h1",
|
||||||
|
"24/7.0; 640dpi; 2880x5884; HUAWEI; LON-L29; HWLON; hi3660",
|
||||||
|
"23/6.0.1; 640dpi; 2880x5884; ZTE; ZTE A2017U; ailsa_ii; qcom",
|
||||||
|
"23/6.0.1; 640dpi; 2880x5884; samsung; SM-G935F; hero2lte; samsungexynos8890",
|
||||||
|
"23/6.0.1; 640dpi; 2880x5884; samsung; SM-G930F; herolte; samsungexynos8890"
|
||||||
|
)
|
||||||
|
|
||||||
@NonNull
|
fun generateBrowserUA(code: Int): String {
|
||||||
public static String generateAppUA(final int code, final String lang) {
|
return browsers[code]
|
||||||
return "Instagram " + igVersion + " Android (" + devices[code] + "; " + lang + "; " + igVersionCode + ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun generateAppUA(code: Int, lang: String): String {
|
||||||
|
return "Instagram " + igVersion + " Android (" + devices[code] + "; " + lang + "; " + igVersionCode + ")"
|
||||||
|
}
|
@ -1,121 +1,117 @@
|
|||||||
package awais.instagrabber.utils;
|
@file:JvmName("ViewUtils")
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
package awais.instagrabber.utils
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.graphics.drawable.GradientDrawable;
|
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
|
||||||
import android.graphics.drawable.shapes.RoundRectShape;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
import android.annotation.SuppressLint
|
||||||
import androidx.annotation.NonNull;
|
import android.content.Context
|
||||||
import androidx.annotation.Nullable;
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.core.content.res.ResourcesCompat;
|
import android.graphics.drawable.GradientDrawable
|
||||||
import androidx.core.util.Pair;
|
import android.graphics.drawable.ShapeDrawable
|
||||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
import android.graphics.drawable.shapes.RoundRectShape
|
||||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
import android.os.Build
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.core.util.Pair
|
||||||
|
import androidx.dynamicanimation.animation.FloatPropertyCompat
|
||||||
|
import androidx.dynamicanimation.animation.SpringAnimation
|
||||||
|
import kotlin.jvm.internal.Intrinsics
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
fun createRoundRectDrawableWithIcon(context: Context, rad: Int, iconRes: Int): Drawable? {
|
||||||
|
val defaultDrawable = ShapeDrawable(RoundRectShape(FloatArray(8) { rad.toFloat() }, null, null))
|
||||||
|
defaultDrawable.paint.color = -0x1
|
||||||
|
val d = ResourcesCompat.getDrawable(context.resources, iconRes, null) ?: return null
|
||||||
|
val drawable = d.mutate()
|
||||||
|
return CombinedDrawable(defaultDrawable, drawable)
|
||||||
|
}
|
||||||
|
|
||||||
import kotlin.jvm.internal.Intrinsics;
|
fun createRoundRectDrawable(rad: Int, defaultColor: Int): Drawable {
|
||||||
|
val defaultDrawable = ShapeDrawable(RoundRectShape(FloatArray(8) { rad.toFloat() }, null, null))
|
||||||
|
defaultDrawable.paint.color = defaultColor
|
||||||
|
return defaultDrawable
|
||||||
|
}
|
||||||
|
|
||||||
public final class ViewUtils {
|
fun createFrame(
|
||||||
|
width: Int,
|
||||||
|
height: Float,
|
||||||
|
gravity: Int,
|
||||||
|
leftMargin: Float,
|
||||||
|
topMargin: Float,
|
||||||
|
rightMargin: Float,
|
||||||
|
bottomMargin: Float
|
||||||
|
): FrameLayout.LayoutParams {
|
||||||
|
val layoutParams = FrameLayout.LayoutParams(getSize(width.toFloat()), getSize(height), gravity)
|
||||||
|
layoutParams.setMargins(
|
||||||
|
Utils.convertDpToPx(leftMargin), Utils.convertDpToPx(topMargin), Utils.convertDpToPx(rightMargin),
|
||||||
|
Utils.convertDpToPx(bottomMargin)
|
||||||
|
)
|
||||||
|
return layoutParams
|
||||||
|
}
|
||||||
|
|
||||||
public static final int MATCH_PARENT = -1;
|
fun createGradientDrawable(
|
||||||
public static final int WRAP_CONTENT = -2;
|
orientation: GradientDrawable.Orientation?,
|
||||||
|
@ColorInt colors: IntArray?
|
||||||
|
): GradientDrawable {
|
||||||
|
val drawable = GradientDrawable(orientation, colors)
|
||||||
|
drawable.shape = GradientDrawable.RECTANGLE
|
||||||
|
return drawable
|
||||||
|
}
|
||||||
|
|
||||||
public static Drawable createRoundRectDrawableWithIcon(final Context context, int rad, int iconRes) {
|
private fun getSize(size: Float): Int {
|
||||||
ShapeDrawable defaultDrawable = new ShapeDrawable(new RoundRectShape(new float[]{rad, rad, rad, rad, rad, rad, rad, rad}, null, null));
|
return if (size < 0) size.toInt() else Utils.convertDpToPx(size)
|
||||||
defaultDrawable.getPaint().setColor(0xffffffff);
|
}
|
||||||
final Drawable d = ResourcesCompat.getDrawable(context.getResources(), iconRes, null);
|
|
||||||
if (d == null) return null;
|
|
||||||
Drawable drawable = d.mutate();
|
|
||||||
return new CombinedDrawable(defaultDrawable, drawable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Drawable createRoundRectDrawable(int rad, int defaultColor) {
|
fun measure(view: View, parent: View): Pair<Int, Int> {
|
||||||
ShapeDrawable defaultDrawable = new ShapeDrawable(new RoundRectShape(new float[]{rad, rad, rad, rad, rad, rad, rad, rad}, null, null));
|
view.measure(
|
||||||
defaultDrawable.getPaint().setColor(defaultColor);
|
View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.UNSPECIFIED),
|
||||||
return defaultDrawable;
|
View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED)
|
||||||
}
|
)
|
||||||
|
return Pair(view.measuredHeight, view.measuredWidth)
|
||||||
|
}
|
||||||
|
|
||||||
public static FrameLayout.LayoutParams createFrame(int width,
|
fun getTextViewValueWidth(textView: TextView, text: String?): Float {
|
||||||
float height,
|
return textView.paint.measureText(text)
|
||||||
int gravity,
|
}
|
||||||
float leftMargin,
|
|
||||||
float topMargin,
|
|
||||||
float rightMargin,
|
|
||||||
float bottomMargin) {
|
|
||||||
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(getSize(width), getSize(height), gravity);
|
|
||||||
layoutParams.setMargins(Utils.convertDpToPx(leftMargin), Utils.convertDpToPx(topMargin), Utils.convertDpToPx(rightMargin),
|
|
||||||
Utils.convertDpToPx(bottomMargin));
|
|
||||||
return layoutParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GradientDrawable createGradientDrawable(final GradientDrawable.Orientation orientation,
|
/**
|
||||||
@ColorInt final int[] colors) {
|
* Creates [SpringAnimation] for object.
|
||||||
final GradientDrawable drawable = new GradientDrawable(orientation, colors);
|
* If finalPosition is not [Float.NaN] then create [SpringAnimation] with
|
||||||
drawable.setShape(GradientDrawable.RECTANGLE);
|
* [SpringForce.mFinalPosition].
|
||||||
return drawable;
|
*
|
||||||
}
|
* @param object Object
|
||||||
|
* @param property object's property to be animated.
|
||||||
|
* @param finalPosition [SpringForce.mFinalPosition] Final position of spring.
|
||||||
|
* @return [SpringAnimation]
|
||||||
|
*/
|
||||||
|
fun springAnimationOf(
|
||||||
|
`object`: Any?,
|
||||||
|
property: FloatPropertyCompat<Any?>?,
|
||||||
|
finalPosition: Float?
|
||||||
|
): SpringAnimation {
|
||||||
|
return finalPosition?.let { SpringAnimation(`object`, property, it) } ?: SpringAnimation(`object`, property)
|
||||||
|
}
|
||||||
|
|
||||||
private static int getSize(float size) {
|
fun suppressLayoutCompat(`$this$suppressLayoutCompat`: ViewGroup, suppress: Boolean) {
|
||||||
return (int) (size < 0 ? size : Utils.convertDpToPx(size));
|
Intrinsics.checkNotNullParameter(`$this$suppressLayoutCompat`, "\$this\$suppressLayoutCompat")
|
||||||
}
|
if (Build.VERSION.SDK_INT >= 29) {
|
||||||
|
`$this$suppressLayoutCompat`.suppressLayout(suppress)
|
||||||
public static Pair<Integer, Integer> measure(@NonNull final View view, @NonNull final View parent) {
|
} else {
|
||||||
view.measure(
|
hiddenSuppressLayout(`$this$suppressLayoutCompat`, suppress)
|
||||||
View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.UNSPECIFIED),
|
|
||||||
View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED)
|
|
||||||
);
|
|
||||||
return new Pair<>(view.getMeasuredHeight(), view.getMeasuredWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float getTextViewValueWidth(final TextView textView, final String text) {
|
|
||||||
return textView.getPaint().measureText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates [SpringAnimation] for object.
|
|
||||||
* If finalPosition is not [Float.NaN] then create [SpringAnimation] with
|
|
||||||
* [SpringForce.mFinalPosition].
|
|
||||||
*
|
|
||||||
* @param object Object
|
|
||||||
* @param property object's property to be animated.
|
|
||||||
* @param finalPosition [SpringForce.mFinalPosition] Final position of spring.
|
|
||||||
* @return [SpringAnimation]
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public static SpringAnimation springAnimationOf(final Object object,
|
|
||||||
final FloatPropertyCompat<Object> property,
|
|
||||||
@Nullable final Float finalPosition) {
|
|
||||||
return finalPosition == null ? new SpringAnimation(object, property) : new SpringAnimation(object, property, finalPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void suppressLayoutCompat(@NotNull ViewGroup $this$suppressLayoutCompat, boolean suppress) {
|
|
||||||
Intrinsics.checkNotNullParameter($this$suppressLayoutCompat, "$this$suppressLayoutCompat");
|
|
||||||
if (Build.VERSION.SDK_INT >= 29) {
|
|
||||||
$this$suppressLayoutCompat.suppressLayout(suppress);
|
|
||||||
} else {
|
|
||||||
hiddenSuppressLayout($this$suppressLayoutCompat, suppress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean tryHiddenSuppressLayout = true;
|
|
||||||
|
|
||||||
@SuppressLint({"NewApi"})
|
|
||||||
private static void hiddenSuppressLayout(ViewGroup group, boolean suppress) {
|
|
||||||
if (tryHiddenSuppressLayout) {
|
|
||||||
try {
|
|
||||||
group.suppressLayout(suppress);
|
|
||||||
} catch (NoSuchMethodError var3) {
|
|
||||||
tryHiddenSuppressLayout = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var tryHiddenSuppressLayout = true
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
private fun hiddenSuppressLayout(group: ViewGroup, suppress: Boolean) {
|
||||||
|
if (tryHiddenSuppressLayout) {
|
||||||
|
try {
|
||||||
|
group.suppressLayout(suppress)
|
||||||
|
} catch (var3: NoSuchMethodError) {
|
||||||
|
tryHiddenSuppressLayout = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package awais.instagrabber.utils.extensions
|
||||||
|
|
||||||
|
val Any.TAG: String
|
||||||
|
get() {
|
||||||
|
return if (!javaClass.isAnonymousClass) {
|
||||||
|
val name = javaClass.simpleName
|
||||||
|
if (name.length <= 23) name else name.substring(0, 23) // first 23 chars
|
||||||
|
} else {
|
||||||
|
val name = javaClass.name
|
||||||
|
if (name.length <= 23) name else name.substring(name.length - 23, name.length) // last 23 chars
|
||||||
|
}
|
||||||
|
}
|
@ -73,7 +73,7 @@ public class UserSearchViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
userService = UserService.getInstance();
|
userService = UserService.getInstance();
|
||||||
directMessagesService = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
|
directMessagesService = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
|
||||||
rankedRecipientsCache = RankedRecipientsCache.getInstance();
|
rankedRecipientsCache = RankedRecipientsCache.INSTANCE;
|
||||||
if ((rankedRecipientsCache.isFailed() || rankedRecipientsCache.isExpired()) && !rankedRecipientsCache.isUpdateInitiated()) {
|
if ((rankedRecipientsCache.isFailed() || rankedRecipientsCache.isExpired()) && !rankedRecipientsCache.isUpdateInitiated()) {
|
||||||
updateRankedRecipientCache();
|
updateRankedRecipientCache();
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ public class UserSearchViewModel extends ViewModel {
|
|||||||
continueSearchIfRequired();
|
continueSearchIfRequired();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rankedRecipientsCache.setRankedRecipientsResponse(response.body());
|
rankedRecipientsCache.setResponse(response.body());
|
||||||
rankedRecipientsCache.setUpdateInitiated(false);
|
rankedRecipientsCache.setUpdateInitiated(false);
|
||||||
continueSearchIfRequired();
|
continueSearchIfRequired();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user