mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-30 19:15:35 +00:00 
			
		
		
		
	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.settingsHelper; | ||||
| 
 | ||||
| //import awaisomereport.LogCollector; | ||||
| //import static awais.instagrabber.utils.Utils.logCollector; | ||||
| 
 | ||||
| public final class InstaGrabberApplication extends Application { | ||||
|     private static final String TAG = "InstaGrabberApplication"; | ||||
| 
 | ||||
| @ -56,7 +53,7 @@ public final class InstaGrabberApplication extends Application { | ||||
|                 Log.e(TAG, "Error", e); | ||||
|             } | ||||
|         } | ||||
|        | ||||
| 
 | ||||
|         // final Set<RequestListener> requestListeners = new HashSet<>(); | ||||
|         // requestListeners.add(new RequestLoggingListener()); | ||||
|         final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig | ||||
|  | ||||
| @ -153,7 +153,7 @@ public class FormattedNumberTextView extends AppCompatTextView { | ||||
|                 return; | ||||
|             } | ||||
|             if (showAbbreviation) { | ||||
|                 setText(NumberUtils.abbreviate(number)); | ||||
|                 setText(NumberUtils.abbreviate(number, null)); | ||||
|                 return; | ||||
|             } | ||||
|             setText(String.valueOf(number)); | ||||
|  | ||||
| @ -16,6 +16,8 @@ import awais.instagrabber.utils.AppExecutors; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awais.instagrabber.utils.ViewUtils; | ||||
| 
 | ||||
| import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; | ||||
| 
 | ||||
| public class Tooltip extends AppCompatTextView { | ||||
| 
 | ||||
|     private View anchor; | ||||
| @ -40,8 +42,7 @@ public class Tooltip extends AppCompatTextView { | ||||
|         setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); | ||||
|         setPadding(Utils.convertDpToPx(8), Utils.convertDpToPx(7), Utils.convertDpToPx(8), Utils.convertDpToPx(7)); | ||||
|         setGravity(Gravity.CENTER_VERTICAL); | ||||
|         parentView.addView(this, ViewUtils.createFrame( | ||||
|                 ViewUtils.WRAP_CONTENT, ViewUtils.WRAP_CONTENT, Gravity.START | Gravity.TOP, 5, 0, 5, 3)); | ||||
|         parentView.addView(this, ViewUtils.createFrame(WRAP_CONTENT, WRAP_CONTENT, Gravity.START | Gravity.TOP, 5, 0, 5, 3)); | ||||
|         setVisibility(GONE); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,185 +1,157 @@ | ||||
| package awais.instagrabber.utils;/* | ||||
| /* | ||||
|  * This is the source code of Telegram for Android v. 5.x.x. | ||||
|  * It is licensed under GNU GPL v. 2 or later. | ||||
|  * You should have received a copy of the license in this archive (see LICENSE). | ||||
|  * | ||||
|  * <p> | ||||
|  * Copyright Nikolai Kudashov, 2013-2018. | ||||
|  */ | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.ColorFilter; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.graphics.Canvas | ||||
| import android.graphics.ColorFilter | ||||
| 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 { | ||||
| 
 | ||||
|     private final Drawable background; | ||||
|     private final Drawable icon; | ||||
|     private int left; | ||||
|     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; | ||||
|     constructor(backgroundDrawable: Drawable, iconDrawable: Drawable?, leftOffset: Int, topOffset: Int) { | ||||
|         background = backgroundDrawable | ||||
|         icon = iconDrawable | ||||
|         left = leftOffset | ||||
|         top = topOffset | ||||
|         if (iconDrawable != null) { | ||||
|             iconDrawable.setCallback(this); | ||||
|             iconDrawable.callback = this | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public CombinedDrawable(Drawable backgroundDrawable, Drawable iconDrawable) { | ||||
|         background = backgroundDrawable; | ||||
|         icon = iconDrawable; | ||||
|     constructor(backgroundDrawable: Drawable, iconDrawable: Drawable?) { | ||||
|         background = backgroundDrawable | ||||
|         icon = iconDrawable | ||||
|         if (iconDrawable != null) { | ||||
|             iconDrawable.setCallback(this); | ||||
|             iconDrawable.callback = this | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void setIconSize(int width, int height) { | ||||
|         iconWidth = width; | ||||
|         iconHeight = height; | ||||
|     fun setIconSize(width: Int, height: Int) { | ||||
|         iconWidth = width | ||||
|         iconHeight = height | ||||
|     } | ||||
| 
 | ||||
|     public void setCustomSize(int width, int height) { | ||||
|         backWidth = width; | ||||
|         backHeight = height; | ||||
|     fun setCustomSize(width: Int, height: Int) { | ||||
|         backWidth = width | ||||
|         backHeight = height | ||||
|     } | ||||
| 
 | ||||
|     public void setIconOffset(int x, int y) { | ||||
|         offsetX = x; | ||||
|         offsetY = y; | ||||
|     fun setIconOffset(x: Int, y: Int) { | ||||
|         offsetX = x | ||||
|         offsetY = y | ||||
|     } | ||||
| 
 | ||||
|     public Drawable getIcon() { | ||||
|         return icon; | ||||
|     fun setFullsize(value: Boolean) { | ||||
|         fullSize = value | ||||
|     } | ||||
| 
 | ||||
|     public Drawable getBackground() { | ||||
|         return background; | ||||
|     override fun setColorFilter(colorFilter: ColorFilter?) { | ||||
|         icon?.colorFilter = colorFilter | ||||
|     } | ||||
| 
 | ||||
|     public void setFullsize(boolean value) { | ||||
|         fullSize = value; | ||||
|     override fun isStateful(): Boolean { | ||||
|         return icon?.isStateful ?: false | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setColorFilter(ColorFilter colorFilter) { | ||||
|         icon.setColorFilter(colorFilter); | ||||
|     override fun setState(stateSet: IntArray): Boolean { | ||||
|         icon?.state = stateSet | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isStateful() { | ||||
|         return icon.isStateful(); | ||||
|     override fun getState(): IntArray { | ||||
|         return icon?.state ?: super.getState() | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean setState(@NonNull int[] stateSet) { | ||||
|         icon.setState(stateSet); | ||||
|         return true; | ||||
|     override fun onStateChange(state: IntArray): Boolean { | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public int[] getState() { | ||||
|         return icon.getState(); | ||||
|     override fun jumpToCurrentState() { | ||||
|         icon?.jumpToCurrentState() | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected boolean onStateChange(int[] state) { | ||||
|         return true; | ||||
|     override fun getConstantState(): ConstantState? { | ||||
|         return icon?.constantState | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void jumpToCurrentState() { | ||||
|         icon.jumpToCurrentState(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ConstantState getConstantState() { | ||||
|         return icon.getConstantState(); | ||||
|     } | ||||
| 
 | ||||
|     @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); | ||||
|                 } | ||||
|     override fun draw(canvas: Canvas) { | ||||
|         background.bounds = bounds | ||||
|         background.draw(canvas) | ||||
|         if (icon == null) return | ||||
|         if (fullSize) { | ||||
|             val bounds = bounds | ||||
|             if (left != 0) { | ||||
|                 icon.setBounds(bounds.left + left, bounds.top + top, bounds.right - left, bounds.bottom - top) | ||||
|             } else { | ||||
|                 int x; | ||||
|                 int y; | ||||
|                 if (iconWidth != 0) { | ||||
|                     x = getBounds().centerX() - iconWidth / 2 + left + offsetX; | ||||
|                     y = getBounds().centerY() - iconHeight / 2 + top + offsetY; | ||||
|                     icon.setBounds(x, y, x + iconWidth, y + iconHeight); | ||||
|                 } else { | ||||
|                     x = getBounds().centerX() - icon.getIntrinsicWidth() / 2 + left; | ||||
|                     y = getBounds().centerY() - icon.getIntrinsicHeight() / 2 + top; | ||||
|                     icon.setBounds(x, y, x + icon.getIntrinsicWidth(), y + icon.getIntrinsicHeight()); | ||||
|                 } | ||||
|                 icon.bounds = bounds | ||||
|             } | ||||
|         } else { | ||||
|             val x: Int | ||||
|             val y: Int | ||||
|             if (iconWidth != 0) { | ||||
|                 x = bounds.centerX() - iconWidth / 2 + left + offsetX | ||||
|                 y = bounds.centerY() - iconHeight / 2 + top + offsetY | ||||
|                 icon.setBounds(x, y, x + iconWidth, y + iconHeight) | ||||
|             } 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 | ||||
|     public void setAlpha(int alpha) { | ||||
|         icon.setAlpha(alpha); | ||||
|         background.setAlpha(alpha); | ||||
|     override fun setAlpha(alpha: Int) { | ||||
|         icon?.alpha = alpha | ||||
|         background.alpha = alpha | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getIntrinsicWidth() { | ||||
|         return backWidth != 0 ? backWidth : background.getIntrinsicWidth(); | ||||
|     override fun getIntrinsicWidth(): Int { | ||||
|         return if (backWidth != 0) backWidth else background.intrinsicWidth | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getIntrinsicHeight() { | ||||
|         return backHeight != 0 ? backHeight : background.getIntrinsicHeight(); | ||||
|     override fun getIntrinsicHeight(): Int { | ||||
|         return if (backHeight != 0) backHeight else background.intrinsicHeight | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getMinimumWidth() { | ||||
|         return backWidth != 0 ? backWidth : background.getMinimumWidth(); | ||||
|     override fun getMinimumWidth(): Int { | ||||
|         return if (backWidth != 0) backWidth else background.minimumWidth | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getMinimumHeight() { | ||||
|         return backHeight != 0 ? backHeight : background.getMinimumHeight(); | ||||
|     override fun getMinimumHeight(): Int { | ||||
|         return if (backHeight != 0) backHeight else background.minimumHeight | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getOpacity() { | ||||
|         return icon.getOpacity(); | ||||
|     override fun getOpacity(): Int { | ||||
|         return icon?.opacity ?: PixelFormat.UNKNOWN | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void invalidateDrawable(@NonNull Drawable who) { | ||||
|         invalidateSelf(); | ||||
|     override fun invalidateDrawable(who: Drawable) { | ||||
|         invalidateSelf() | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { | ||||
|         scheduleSelf(what, when); | ||||
|     override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) { | ||||
|         scheduleSelf(what, `when`) | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { | ||||
|         unscheduleSelf(what); | ||||
|     override fun unscheduleDrawable(who: Drawable, what: Runnable) { | ||||
|         unscheduleSelf(what) | ||||
|     } | ||||
| } | ||||
| } | ||||
| @ -1,139 +1,114 @@ | ||||
| package awais.instagrabber.utils; | ||||
| @file:JvmName("CookieUtils") | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.util.Log; | ||||
| import android.webkit.CookieManager; | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| 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; | ||||
| import java.net.CookieStore; | ||||
| 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; | ||||
| private const val TAG = "CookieUtils" | ||||
| private val COOKIE_MANAGER = CookieManager.getInstance() | ||||
| 
 | ||||
| import awais.instagrabber.BuildConfig; | ||||
| import awais.instagrabber.db.datasources.AccountDataSource; | ||||
| import awais.instagrabber.db.repositories.AccountRepository; | ||||
| import awais.instagrabber.db.repositories.RepositoryCallback; | ||||
| //import awaisomereport.LogCollector; | ||||
| @JvmField | ||||
| val NET_COOKIE_MANAGER = java.net.CookieManager(null, CookiePolicy.ACCEPT_ALL) | ||||
| 
 | ||||
| public final class CookieUtils { | ||||
|     private static final String TAG = CookieUtils.class.getSimpleName(); | ||||
|     public static final CookieManager COOKIE_MANAGER = CookieManager.getInstance(); | ||||
|     public static final java.net.CookieManager NET_COOKIE_MANAGER = new java.net.CookieManager(null, CookiePolicy.ACCEPT_ALL); | ||||
| 
 | ||||
|     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); | ||||
|         } | ||||
| fun setupCookies(cookieRaw: String) { | ||||
|     val cookieStore = NET_COOKIE_MANAGER.cookieStore | ||||
|     if (cookieStore == null || TextUtils.isEmpty(cookieRaw)) { | ||||
|         return | ||||
|     } | ||||
| 
 | ||||
|     public static void removeAllAccounts(final Context context, final RepositoryCallback<Void> callback) { | ||||
|         final CookieStore cookieStore = NET_COOKIE_MANAGER.getCookieStore(); | ||||
|         if (cookieStore == null) return; | ||||
|         cookieStore.removeAll(); | ||||
|         try { | ||||
|             AccountRepository.getInstance(AccountDataSource.getInstance(context)) | ||||
|                              .deleteAllAccounts(callback); | ||||
|         } catch (Exception e) { | ||||
|             Log.e(TAG, "setupCookies", e); | ||||
|         } | ||||
|     if (cookieRaw == "LOGOUT") { | ||||
|         cookieStore.removeAll() | ||||
|         return | ||||
|     } | ||||
| 
 | ||||
|     public static long getUserIdFromCookie(final String cookies) { | ||||
|         final String dsUserId = getCookieValue(cookies, "ds_user_id"); | ||||
|         if (dsUserId == null) { | ||||
|             return 0; | ||||
|     try { | ||||
|         val uri1 = URI("https://instagram.com") | ||||
|         val uri2 = URI("https://instagram.com/") | ||||
|         val uri3 = URI("https://i.instagram.com/") | ||||
|         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 { | ||||
|             return Long.parseLong(dsUserId); | ||||
|         } 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; | ||||
|     } catch (e: URISyntaxException) { | ||||
|         Log.e(TAG, "", e) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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 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) { | ||||
|         this.array = Arrays.copyOf(array, 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]; | ||||
|     } | ||||
| 
 | ||||
|     // 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) { | ||||
|         if (i >= 0 && i < length) { | ||||
|             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 androidx.annotation.Nullable; | ||||
| import java.util.regex.Pattern | ||||
| 
 | ||||
| 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; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| public final class DeepLinkParser { | ||||
|     private static final Map<DeepLink.Type, DeepLinkPattern> TYPE_PATTERN_MAP = ImmutableMap | ||||
|             .<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); | ||||
|     @JvmStatic | ||||
|     fun parse(text: String): DeepLink? { | ||||
|         for ((key, value) in TYPE_PATTERN_MAP) { | ||||
|             if (text.startsWith(value.patternText)) { | ||||
|                 return DeepLink(key, value.pattern.matcher(text).replaceAll("")) | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|         return null | ||||
|     } | ||||
| 
 | ||||
|     public static class DeepLinkPattern { | ||||
|         private final String patternText; | ||||
|         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; | ||||
|         } | ||||
|     data class DeepLinkPattern(val patternText: String) { | ||||
|         val pattern: Pattern = Pattern.compile(patternText, Pattern.LITERAL) | ||||
|     } | ||||
| 
 | ||||
|     public static class DeepLink { | ||||
|         private final Type type; | ||||
|         private final String value; | ||||
| 
 | ||||
|         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, | ||||
|     data class DeepLink(val type: Type, val value: String) { | ||||
|         enum class Type { | ||||
|             USER | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| @ -1,91 +1,83 @@ | ||||
| package awais.instagrabber.utils; | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.res.Configuration; | ||||
| import android.content.res.Resources; | ||||
| import android.view.ContextThemeWrapper; | ||||
| 
 | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import java.util.Locale; | ||||
| 
 | ||||
| import awais.instagrabber.fragments.settings.PreferenceKeys; | ||||
| import android.content.Context | ||||
| import android.content.res.Configuration | ||||
| import android.view.ContextThemeWrapper | ||||
| import awais.instagrabber.fragments.settings.PreferenceKeys | ||||
| import java.util.* | ||||
| 
 | ||||
| // taken from my app TESV Console Codes | ||||
| public final class LocaleUtils { | ||||
|     private static Locale defaultLocale, currentLocale; | ||||
| object LocaleUtils { | ||||
|     private var defaultLocale: Locale? = null | ||||
| 
 | ||||
|     public static void setLocale(Context baseContext) { | ||||
|         if (defaultLocale == null) defaultLocale = Locale.getDefault(); | ||||
|     @JvmStatic | ||||
|     var currentLocale: Locale? = null | ||||
|         private set | ||||
| 
 | ||||
|         if (baseContext instanceof ContextThemeWrapper) | ||||
|             baseContext = ((ContextThemeWrapper) baseContext).getBaseContext(); | ||||
| 
 | ||||
|         if (Utils.settingsHelper == null) | ||||
|             Utils.settingsHelper = new SettingsHelper(baseContext); | ||||
| 
 | ||||
|         final String appLanguageSettings = Utils.settingsHelper.getString(PreferenceKeys.APP_LANGUAGE); | ||||
|         final String lang = LocaleUtils.getCorrespondingLanguageCode(appLanguageSettings); | ||||
| 
 | ||||
|         currentLocale = TextUtils.isEmpty(lang) ? defaultLocale : | ||||
|                         (lang.contains("_") ? new Locale(lang.split("_")[0], lang.split("_")[1]) : new Locale(lang)); | ||||
|         Locale.setDefault(currentLocale); | ||||
| 
 | ||||
|         final Resources res = baseContext.getResources(); | ||||
|         final Configuration config = res.getConfiguration(); | ||||
| 
 | ||||
|         config.locale = currentLocale; | ||||
|         config.setLocale(currentLocale); | ||||
|         config.setLayoutDirection(currentLocale); | ||||
| 
 | ||||
|         res.updateConfiguration(config, res.getDisplayMetrics()); | ||||
|     } | ||||
| 
 | ||||
|     public static Locale getCurrentLocale() { | ||||
|         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); | ||||
|     @JvmStatic | ||||
|     fun setLocale(baseContext: Context) { | ||||
|         var baseContext1 = baseContext | ||||
|         if (defaultLocale == null) defaultLocale = Locale.getDefault() | ||||
|         if (baseContext1 is ContextThemeWrapper) baseContext1 = baseContext1.baseContext | ||||
|         if (Utils.settingsHelper == null) Utils.settingsHelper = SettingsHelper(baseContext1) | ||||
|         val appLanguageSettings = Utils.settingsHelper.getString(PreferenceKeys.APP_LANGUAGE) | ||||
|         val lang = getCorrespondingLanguageCode(appLanguageSettings) | ||||
|         currentLocale = when { | ||||
|             TextUtils.isEmpty(lang) -> defaultLocale | ||||
|             lang!!.contains("_") -> { | ||||
|                 val split = lang.split("_") | ||||
|                 Locale(split[0], split[1]) | ||||
|             } | ||||
|             else -> Locale(lang) | ||||
|         } | ||||
|         currentLocale?.let { | ||||
|             Locale.setDefault(it) | ||||
|             val res = baseContext1.resources | ||||
|             val config = res.configuration | ||||
|             // config.locale = currentLocale | ||||
|             config.setLocale(it) | ||||
|             config.setLayoutDirection(it) | ||||
|             res.updateConfiguration(config, res.displayMetrics) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     public static String getCorrespondingLanguageCode(final String appLanguageSettings) { | ||||
|         if (TextUtils.isEmpty(appLanguageSettings)) return null; | ||||
| 
 | ||||
|         final int appLanguageIndex = Integer.parseInt(appLanguageSettings); | ||||
|         switch (appLanguageIndex) { | ||||
|             case 1: return "en"; | ||||
|             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; | ||||
|     @JvmStatic | ||||
|     fun updateConfig(wrapper: ContextThemeWrapper) { | ||||
|         if (currentLocale == null) return | ||||
|         val configuration = Configuration() | ||||
|         // configuration.locale = currentLocale | ||||
|         configuration.setLocale(currentLocale) | ||||
|         wrapper.applyOverrideConfiguration(configuration) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     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 org.json.JSONObject | ||||
| import java.util.* | ||||
| import kotlin.random.Random | ||||
| 
 | ||||
| 
 | ||||
| private const val LOWER = 1000000000L | ||||
| @ -109,7 +110,7 @@ fun generateUploadId(): String { | ||||
| } | ||||
| 
 | ||||
| fun generateName(uploadId: String): String { | ||||
|     val random = NumberUtils.random(LOWER, UPPER + 1) | ||||
|     val random = Random.nextLong(LOWER, UPPER + 1) | ||||
|     return "${uploadId}_0_$random" | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| package awais.instagrabber.utils; | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| /* | ||||
|  * 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 | ||||
|  * 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 | ||||
|  * implementation of equals(), returning true if equals() is true on each of the contained | ||||
|  * objects. | ||||
|  */ | ||||
| public class NullSafePair<F, S> { | ||||
|     public final @NonNull | ||||
|     F first; | ||||
|     public final @NonNull | ||||
|     S second; | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor for a Pair. | ||||
|      * | ||||
|      * @param first  the first object in the Pair | ||||
|      * @param second the second object in the pair | ||||
|      */ | ||||
|     public NullSafePair(@NonNull F first, @NonNull S second) { | ||||
|         this.first = first; | ||||
|         this.second = second; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 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; | ||||
| /** | ||||
|  * Constructor for a Pair. | ||||
|  * | ||||
|  * @param first  the first object in the Pair | ||||
|  * @param second the second object in the pair | ||||
|  */ | ||||
| data class NullSafePair<F, S>(@JvmField val first: F, @JvmField val second: S) { | ||||
|     companion object { | ||||
|         /** | ||||
|          * 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 | ||||
|          */ | ||||
|         fun <A, B> create(a: A, b: B): NullSafePair<A, B> { | ||||
|             return NullSafePair(a, b) | ||||
|         } | ||||
|         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; | ||||
| import androidx.annotation.Nullable; | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| import java.util.Locale; | ||||
| import java.util.Random; | ||||
| import java.util.* | ||||
| import kotlin.math.ln | ||||
| import kotlin.math.pow | ||||
| 
 | ||||
| public final class NumberUtils { | ||||
|     // @NonNull | ||||
|     // 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 getResultingHeight(requiredWidth: Int, height: Int, width: Int): Int { | ||||
|     return requiredWidth * height / width | ||||
| } | ||||
| 
 | ||||
| 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 java.time.temporal.ChronoUnit; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipient | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse | ||||
| import java.time.LocalDateTime | ||||
| import java.time.temporal.ChronoUnit | ||||
| 
 | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; | ||||
| import awais.instagrabber.repositories.responses.directmessages.RankedRecipientsResponse; | ||||
| object RankedRecipientsCache { | ||||
|     private var lastUpdatedOn: LocalDateTime? = null | ||||
|     var isUpdateInitiated = false | ||||
|     var isFailed = false | ||||
|     val rankedRecipients: List<RankedRecipient> | ||||
|         get() = response?.rankedRecipients ?: emptyList() | ||||
| 
 | ||||
| public class RankedRecipientsCache { | ||||
|     private static final Object LOCK = new Object(); | ||||
| 
 | ||||
|     private static RankedRecipientsCache instance; | ||||
| 
 | ||||
|     public static RankedRecipientsCache getInstance() { | ||||
|         if (instance == null) { | ||||
|             synchronized (LOCK) { | ||||
|                 if (instance == null) { | ||||
|                     instance = new RankedRecipientsCache(); | ||||
|                 } | ||||
|             } | ||||
|     var response: RankedRecipientsResponse? = null | ||||
|         set(value) { | ||||
|             field = value | ||||
|             lastUpdatedOn = LocalDateTime.now() | ||||
|         } | ||||
|         return instance; | ||||
|     } | ||||
| 
 | ||||
|     private LocalDateTime lastUpdatedOn; | ||||
|     private RankedRecipientsResponse response; | ||||
|     private boolean updateInitiated = false; | ||||
|     private boolean failed = false; | ||||
| 
 | ||||
|     private RankedRecipientsCache() {} | ||||
| 
 | ||||
|     public List<RankedRecipient> getRankedRecipients() { | ||||
|         if (response != null) { | ||||
|             return response.getRankedRecipients(); | ||||
|     val isExpired: Boolean | ||||
|         get() { | ||||
|             if (lastUpdatedOn == null || response == null) return true | ||||
|             val expiresInSecs = response!!.expires | ||||
|             return LocalDateTime.now().isAfter(lastUpdatedOn!!.plus(expiresInSecs, ChronoUnit.SECONDS)) | ||||
|         } | ||||
|         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; | ||||
| 
 | ||||
| public class SerializablePair<F, S> extends Pair<F, S> implements Serializable { | ||||
|     /** | ||||
|      * Constructor for a Pair. | ||||
|      * | ||||
|      * @param first  the first object in the Pair | ||||
|      * @param second the second object in the pair | ||||
|      */ | ||||
|     public SerializablePair(final F first, final S second) { | ||||
|         super(first, second); | ||||
|     } | ||||
| } | ||||
| /** | ||||
|  * Constructor for a Pair. | ||||
|  * | ||||
|  * @param first  the first object in the Pair | ||||
|  * @param second the second object in the pair | ||||
|  */ | ||||
| data class SerializablePair<F, S>(@JvmField val first: F, @JvmField val second: S) : Pair<F, S>(first, second), Serializable | ||||
| @ -1,38 +1,36 @@ | ||||
| package awais.instagrabber.utils; | ||||
| @file:JvmName("UpdateCheckCommon") | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| import awais.instagrabber.BuildConfig; | ||||
| import awais.instagrabber.R; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| public final class UpdateCheckCommon { | ||||
| 
 | ||||
|     public static boolean shouldShowUpdateDialog(final boolean force, | ||||
|                                                  @NonNull final String version) { | ||||
|         final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION); | ||||
|         return force || (!BuildConfig.DEBUG && !skippedVersion.equals(version)); | ||||
|     } | ||||
| 
 | ||||
|     public static void showUpdateDialog(@NonNull final Context context, | ||||
|                                         @NonNull final String version, | ||||
|                                         @NonNull final DialogInterface.OnClickListener onDownloadClickListener) { | ||||
|         AppExecutors.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 shouldShowUpdateDialog( | ||||
|     force: Boolean, | ||||
|     version: String | ||||
| ): Boolean { | ||||
|     val skippedVersion = Utils.settingsHelper.getString(Constants.SKIPPED_VERSION) | ||||
|     return force || !BuildConfig.DEBUG && skippedVersion != version | ||||
| } | ||||
| 
 | ||||
| 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). | ||||
|      * 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 | ||||
|      */ | ||||
|     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" | ||||
|     }; | ||||
| // use APKpure, assume arm64-v8a | ||||
| private const val igVersion = "188.0.0.35.124" | ||||
| private const val igVersionCode = "292080186" | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static String generateBrowserUA(final int code) { | ||||
|         return browsers[code]; | ||||
|     } | ||||
| // you can pick *any* device as long as you LEAVE OUT the resolution for maximum download quality | ||||
| // https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json | ||||
| @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 | ||||
|     public static String generateAppUA(final int code, final String lang) { | ||||
|         return "Instagram " + igVersion + " Android (" + devices[code] + "; " + lang + "; " + igVersionCode + ")"; | ||||
|     } | ||||
| fun generateBrowserUA(code: Int): String { | ||||
|     return browsers[code] | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 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; | ||||
| package awais.instagrabber.utils | ||||
| 
 | ||||
| import androidx.annotation.ColorInt; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.core.content.res.ResourcesCompat; | ||||
| import androidx.core.util.Pair; | ||||
| import androidx.dynamicanimation.animation.FloatPropertyCompat; | ||||
| import androidx.dynamicanimation.animation.SpringAnimation; | ||||
| import android.annotation.SuppressLint | ||||
| 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 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; | ||||
|     public static final int WRAP_CONTENT = -2; | ||||
| fun createGradientDrawable( | ||||
|     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) { | ||||
|         ShapeDrawable defaultDrawable = new ShapeDrawable(new RoundRectShape(new float[]{rad, rad, rad, rad, rad, rad, rad, rad}, null, null)); | ||||
|         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); | ||||
|     } | ||||
| private fun getSize(size: Float): Int { | ||||
|     return if (size < 0) size.toInt() else Utils.convertDpToPx(size) | ||||
| } | ||||
| 
 | ||||
|     public static Drawable createRoundRectDrawable(int rad, int defaultColor) { | ||||
|         ShapeDrawable defaultDrawable = new ShapeDrawable(new RoundRectShape(new float[]{rad, rad, rad, rad, rad, rad, rad, rad}, null, null)); | ||||
|         defaultDrawable.getPaint().setColor(defaultColor); | ||||
|         return defaultDrawable; | ||||
|     } | ||||
| fun measure(view: View, parent: View): Pair<Int, Int> { | ||||
|     view.measure( | ||||
|         View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.UNSPECIFIED), | ||||
|         View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED) | ||||
|     ) | ||||
|     return Pair(view.measuredHeight, view.measuredWidth) | ||||
| } | ||||
| 
 | ||||
|     public static FrameLayout.LayoutParams createFrame(int width, | ||||
|                                                        float height, | ||||
|                                                        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; | ||||
|     } | ||||
| fun getTextViewValueWidth(textView: TextView, text: String?): Float { | ||||
|     return textView.paint.measureText(text) | ||||
| } | ||||
| 
 | ||||
|     public static GradientDrawable createGradientDrawable(final GradientDrawable.Orientation orientation, | ||||
|                                                           @ColorInt final int[] colors) { | ||||
|         final GradientDrawable drawable = new GradientDrawable(orientation, colors); | ||||
|         drawable.setShape(GradientDrawable.RECTANGLE); | ||||
|         return drawable; | ||||
|     } | ||||
| /** | ||||
|  * 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] | ||||
|  */ | ||||
| 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) { | ||||
|         return (int) (size < 0 ? size : Utils.convertDpToPx(size)); | ||||
|     } | ||||
| 
 | ||||
|     public static Pair<Integer, Integer> measure(@NonNull final View view, @NonNull final View parent) { | ||||
|         view.measure( | ||||
|                 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; | ||||
|             } | ||||
|         } | ||||
| fun suppressLayoutCompat(`$this$suppressLayoutCompat`: ViewGroup, suppress: Boolean) { | ||||
|     Intrinsics.checkNotNullParameter(`$this$suppressLayoutCompat`, "\$this\$suppressLayoutCompat") | ||||
|     if (Build.VERSION.SDK_INT >= 29) { | ||||
|         `$this$suppressLayoutCompat`.suppressLayout(suppress) | ||||
|     } else { | ||||
|         hiddenSuppressLayout(`$this$suppressLayoutCompat`, suppress) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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(); | ||||
|         directMessagesService = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid); | ||||
|         rankedRecipientsCache = RankedRecipientsCache.getInstance(); | ||||
|         rankedRecipientsCache = RankedRecipientsCache.INSTANCE; | ||||
|         if ((rankedRecipientsCache.isFailed() || rankedRecipientsCache.isExpired()) && !rankedRecipientsCache.isUpdateInitiated()) { | ||||
|             updateRankedRecipientCache(); | ||||
|         } | ||||
| @ -113,7 +113,7 @@ public class UserSearchViewModel extends ViewModel { | ||||
|                     continueSearchIfRequired(); | ||||
|                     return; | ||||
|                 } | ||||
|                 rankedRecipientsCache.setRankedRecipientsResponse(response.body()); | ||||
|                 rankedRecipientsCache.setResponse(response.body()); | ||||
|                 rankedRecipientsCache.setUpdateInitiated(false); | ||||
|                 continueSearchIfRequired(); | ||||
|             } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user