560 lines
23 KiB
Java
560 lines
23 KiB
Java
package awais.instagrabber.utils;
|
|
|
|
import android.app.Activity;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.ClipData;
|
|
import android.content.ClipboardManager;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Color;
|
|
import android.graphics.Point;
|
|
import android.graphics.Rect;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.net.Uri;
|
|
import android.os.Build;
|
|
import android.os.Environment;
|
|
import android.os.storage.StorageManager;
|
|
import android.provider.Browser;
|
|
import android.provider.DocumentsContract;
|
|
import android.util.DisplayMetrics;
|
|
import android.util.Log;
|
|
import android.util.Pair;
|
|
import android.util.TypedValue;
|
|
import android.view.Display;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.Window;
|
|
import android.view.WindowManager;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import android.webkit.MimeTypeMap;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.annotation.DrawableRes;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.appcompat.app.ActionBar;
|
|
import androidx.appcompat.app.AppCompatActivity;
|
|
import androidx.core.content.ContextCompat;
|
|
import androidx.documentfile.provider.DocumentFile;
|
|
import androidx.lifecycle.LiveData;
|
|
import androidx.lifecycle.MediatorLiveData;
|
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
|
|
|
|
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
|
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
|
|
|
import org.json.JSONObject;
|
|
|
|
import java.io.File;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import awais.instagrabber.R;
|
|
import awais.instagrabber.models.PostsLayoutPreferences;
|
|
import awais.instagrabber.models.enums.FavoriteType;
|
|
|
|
public final class Utils {
|
|
private static final String TAG = "Utils";
|
|
private static final int VIDEO_CACHE_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
|
// public static LogCollector logCollector;
|
|
public static SettingsHelper settingsHelper;
|
|
public static boolean sessionVolumeFull = false;
|
|
public static final MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
|
|
public static final DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
|
|
public static ClipboardManager clipboardManager;
|
|
public static SimpleCache simpleCache;
|
|
private static int statusBarHeight;
|
|
private static int actionBarHeight;
|
|
public static String cacheDir;
|
|
private static int defaultStatusBarColor;
|
|
private static Object[] volumes;
|
|
|
|
public static int convertDpToPx(final float dp) {
|
|
return Math.round((dp * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT);
|
|
}
|
|
|
|
public static void copyText(@NonNull final Context context, final CharSequence string) {
|
|
if (clipboardManager == null) {
|
|
clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
}
|
|
int toastMessage = R.string.clipboard_error;
|
|
if (clipboardManager != null) {
|
|
try {
|
|
clipboardManager.setPrimaryClip(ClipData.newPlainText(context.getString(R.string.app_name), string));
|
|
toastMessage = R.string.clipboard_copied;
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "copyText: ", e);
|
|
}
|
|
}
|
|
Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show();
|
|
}
|
|
|
|
public static Map<String, String> sign(final Map<String, Object> form) {
|
|
// final String signed = sign(Constants.SIGNATURE_KEY, new JSONObject(form).toString());
|
|
// if (signed == null) {
|
|
// return null;
|
|
// }
|
|
final Map<String, String> map = new HashMap<>();
|
|
// map.put("ig_sig_key_version", Constants.SIGNATURE_VERSION);
|
|
// map.put("signed_body", signed);
|
|
map.put("signed_body", "SIGNATURE." + new JSONObject(form).toString());
|
|
return map;
|
|
}
|
|
|
|
// public static String sign(final String key, final String message) {
|
|
// try {
|
|
// final Mac hasher = Mac.getInstance("HmacSHA256");
|
|
// hasher.init(new SecretKeySpec(key.getBytes(), "HmacSHA256"));
|
|
// byte[] hash = hasher.doFinal(message.getBytes());
|
|
// final StringBuilder hexString = new StringBuilder();
|
|
// for (byte b : hash) {
|
|
// final String hex = Integer.toHexString(0xff & b);
|
|
// if (hex.length() == 1) hexString.append('0');
|
|
// hexString.append(hex);
|
|
// }
|
|
// return hexString.toString() + "." + message;
|
|
// } catch (Exception e) {
|
|
// Log.e(TAG, "Error signing", e);
|
|
// return null;
|
|
// }
|
|
// }
|
|
|
|
public static String getMimeType(@NonNull final Uri uri, final ContentResolver contentResolver) {
|
|
String mimeType;
|
|
final String scheme = uri.getScheme();
|
|
final String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri.toString());
|
|
if (TextUtils.isEmpty(scheme)) {
|
|
mimeType = mimeTypeMap.getMimeTypeFromExtension(fileExtension.toLowerCase());
|
|
} else {
|
|
if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
|
|
mimeType = contentResolver.getType(uri);
|
|
} else {
|
|
mimeType = mimeTypeMap.getMimeTypeFromExtension(fileExtension.toLowerCase());
|
|
}
|
|
}
|
|
if (mimeType == null) return null;
|
|
return mimeType.toLowerCase();
|
|
}
|
|
|
|
public static SimpleCache getSimpleCacheInstance(final Context context) {
|
|
if (context == null) {
|
|
return null;
|
|
}
|
|
final ExoDatabaseProvider exoDatabaseProvider = new ExoDatabaseProvider(context);
|
|
final File cacheDir = context.getCacheDir();
|
|
if (simpleCache == null && cacheDir != null) {
|
|
simpleCache = new SimpleCache(cacheDir, new LeastRecentlyUsedCacheEvictor(VIDEO_CACHE_MAX_BYTES), exoDatabaseProvider);
|
|
}
|
|
return simpleCache;
|
|
}
|
|
|
|
@Nullable
|
|
public static Pair<FavoriteType, String> migrateOldFavQuery(final String queryText) {
|
|
if (queryText.startsWith("@")) {
|
|
return new Pair<>(FavoriteType.USER, queryText.substring(1));
|
|
} else if (queryText.contains("/")) {
|
|
return new Pair<>(FavoriteType.LOCATION, queryText.substring(0, queryText.indexOf("/")));
|
|
} else if (queryText.startsWith("#")) {
|
|
return new Pair<>(FavoriteType.HASHTAG, queryText.substring(1));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static int getStatusBarHeight(final Context context) {
|
|
if (statusBarHeight > 0) {
|
|
return statusBarHeight;
|
|
}
|
|
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
|
if (resourceId > 0) {
|
|
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
|
|
}
|
|
return statusBarHeight;
|
|
}
|
|
|
|
public static int getActionBarHeight(@NonNull final Context context) {
|
|
if (actionBarHeight > 0) {
|
|
return actionBarHeight;
|
|
}
|
|
final TypedValue tv = new TypedValue();
|
|
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
|
|
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, displayMetrics);
|
|
}
|
|
return actionBarHeight;
|
|
}
|
|
|
|
public static void openURL(final Context context, final String url) {
|
|
if (context == null || TextUtils.isEmpty(url)) {
|
|
return;
|
|
}
|
|
try {
|
|
String url1 = url;
|
|
// add http:// if string doesn't have http:// or https://
|
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
url1 = "http://" + url;
|
|
}
|
|
final Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url1));
|
|
i.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
|
i.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
|
|
context.startActivity(i);
|
|
} catch (ActivityNotFoundException e) {
|
|
Log.e(TAG, "openURL: No activity found to handle URLs", e);
|
|
Toast.makeText(context, context.getString(R.string.no_external_app_url), Toast.LENGTH_LONG).show();
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "openURL", e);
|
|
}
|
|
}
|
|
|
|
public static void openEmailAddress(final Context context, final String emailAddress) {
|
|
if (context == null || TextUtils.isEmpty(emailAddress)) {
|
|
return;
|
|
}
|
|
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + emailAddress));
|
|
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "");
|
|
emailIntent.putExtra(Intent.EXTRA_TEXT, "");
|
|
context.startActivity(emailIntent);
|
|
}
|
|
|
|
public static void displayToastAboveView(@NonNull final Context context,
|
|
@NonNull final View view,
|
|
@NonNull final String text) {
|
|
final Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
|
|
toast.setGravity(Gravity.TOP | Gravity.START,
|
|
view.getLeft(),
|
|
view.getTop());
|
|
toast.show();
|
|
}
|
|
|
|
public static PostsLayoutPreferences getPostsLayoutPreferences(final String layoutPreferenceKey) {
|
|
PostsLayoutPreferences layoutPreferences = PostsLayoutPreferences.fromJson(settingsHelper.getString(layoutPreferenceKey));
|
|
if (layoutPreferences == null) {
|
|
layoutPreferences = PostsLayoutPreferences.builder().build();
|
|
settingsHelper.putString(layoutPreferenceKey, layoutPreferences.getJson());
|
|
}
|
|
return layoutPreferences;
|
|
}
|
|
|
|
private static Field mAttachInfoField;
|
|
private static Field mStableInsetsField;
|
|
|
|
public static int getViewInset(View view) {
|
|
if (view == null
|
|
|| view.getHeight() == displayMetrics.heightPixels
|
|
|| view.getHeight() == displayMetrics.widthPixels - getStatusBarHeight(view.getContext())) {
|
|
return 0;
|
|
}
|
|
try {
|
|
if (mAttachInfoField == null) {
|
|
//noinspection JavaReflectionMemberAccess
|
|
mAttachInfoField = View.class.getDeclaredField("mAttachInfo");
|
|
mAttachInfoField.setAccessible(true);
|
|
}
|
|
Object mAttachInfo = mAttachInfoField.get(view);
|
|
if (mAttachInfo != null) {
|
|
if (mStableInsetsField == null) {
|
|
mStableInsetsField = mAttachInfo.getClass().getDeclaredField("mStableInsets");
|
|
mStableInsetsField.setAccessible(true);
|
|
}
|
|
Rect insets = (Rect) mStableInsetsField.get(mAttachInfo);
|
|
if (insets == null) {
|
|
return 0;
|
|
}
|
|
return insets.bottom;
|
|
}
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "getViewInset", e);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static int getThemeAccentColor(Context context) {
|
|
int colorAttr;
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
colorAttr = android.R.attr.colorAccent;
|
|
} else {
|
|
//Get colorAccent defined for AppCompat
|
|
colorAttr = context.getResources().getIdentifier("colorAccent", "attr", context.getPackageName());
|
|
}
|
|
TypedValue outValue = new TypedValue();
|
|
context.getTheme().resolveAttribute(colorAttr, outValue, true);
|
|
return outValue.data;
|
|
}
|
|
|
|
public static int getAttrValue(@NonNull final Context context, final int attr) {
|
|
final TypedValue outValue = new TypedValue();
|
|
context.getTheme().resolveAttribute(attr, outValue, true);
|
|
return outValue.data;
|
|
}
|
|
|
|
public static int getAttrResId(@NonNull final Context context, final int attr) {
|
|
final TypedValue outValue = new TypedValue();
|
|
context.getTheme().resolveAttribute(attr, outValue, true);
|
|
return outValue.resourceId;
|
|
}
|
|
|
|
public static void transparentStatusBar(final Activity activity,
|
|
final boolean enable,
|
|
final boolean fullscreen) {
|
|
if (activity == null) return;
|
|
final ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
|
|
final Window window = activity.getWindow();
|
|
final View decorView = window.getDecorView();
|
|
if (enable) {
|
|
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
|
if (actionBar != null) {
|
|
actionBar.hide();
|
|
}
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
defaultStatusBarColor = window.getStatusBarColor();
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
|
// FOR TRANSPARENT NAVIGATION BAR
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
|
window.setStatusBarColor(Color.TRANSPARENT);
|
|
Log.d(TAG, "Setting Color Transparent " + Color.TRANSPARENT + " Default Color " + defaultStatusBarColor);
|
|
return;
|
|
}
|
|
Log.d(TAG, "Setting Color Trans " + Color.TRANSPARENT);
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
|
return;
|
|
}
|
|
if (fullscreen) {
|
|
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
|
|
decorView.setSystemUiVisibility(uiOptions);
|
|
return;
|
|
}
|
|
if (actionBar != null) {
|
|
actionBar.show();
|
|
}
|
|
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
window.setStatusBarColor(defaultStatusBarColor);
|
|
return;
|
|
}
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
|
}
|
|
|
|
// public static void mediaScanFile(@NonNull final Context context,
|
|
// @NonNull File file,
|
|
// @NonNull final OnScanCompletedListener callback) {
|
|
// //noinspection UnstableApiUsage
|
|
// final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(Files.getFileExtension(file.getName()));
|
|
// MediaScannerConnection.scanFile(
|
|
// context,
|
|
// new String[]{file.getAbsolutePath()},
|
|
// new String[]{mimeType},
|
|
// callback
|
|
// );
|
|
// }
|
|
|
|
public static void showKeyboard(@NonNull final View view) {
|
|
try {
|
|
final Context context = view.getContext();
|
|
if (context == null) return;
|
|
final InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
if (imm == null) return;
|
|
view.requestFocus();
|
|
final boolean shown = imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
|
if (!shown) {
|
|
Log.e(TAG, "showKeyboard: System did not display the keyboard");
|
|
}
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "showKeyboard: ", e);
|
|
}
|
|
}
|
|
|
|
public static void hideKeyboard(final View view) {
|
|
if (view == null) return;
|
|
final Context context = view.getContext();
|
|
if (context == null) return;
|
|
try {
|
|
final InputMethodManager manager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
|
|
if (manager == null) return;
|
|
manager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "hideKeyboard: ", e);
|
|
}
|
|
}
|
|
|
|
public static Drawable getAnimatableDrawable(@NonNull final Context context,
|
|
@DrawableRes final int drawableResId) {
|
|
final Drawable drawable;
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
drawable = ContextCompat.getDrawable(context, drawableResId);
|
|
} else {
|
|
drawable = AnimatedVectorDrawableCompat.create(context, drawableResId);
|
|
}
|
|
return drawable;
|
|
}
|
|
|
|
public static void enabledKeepScreenOn(@NonNull final Activity activity) {
|
|
final Window window = activity.getWindow();
|
|
if (window == null) return;
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
}
|
|
|
|
public static void disableKeepScreenOn(@NonNull final Activity activity) {
|
|
final Window window = activity.getWindow();
|
|
if (window == null) return;
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
}
|
|
|
|
public static <T> void moveItem(int sourceIndex, int targetIndex, List<T> list) {
|
|
if (sourceIndex <= targetIndex) {
|
|
Collections.rotate(list.subList(sourceIndex, targetIndex + 1), -1);
|
|
} else {
|
|
Collections.rotate(list.subList(targetIndex, sourceIndex + 1), 1);
|
|
}
|
|
}
|
|
|
|
// public static void scanDocumentFile(@NonNull final Context context,
|
|
// @NonNull final DocumentFile documentFile,
|
|
// @NonNull final OnScanCompletedListener callback) {
|
|
// if (!documentFile.isFile() || !documentFile.exists()) {
|
|
// Log.d(TAG, "scanDocumentFile: " + documentFile);
|
|
// callback.onScanCompleted(null, null);
|
|
// return;
|
|
// }
|
|
// File file = null;
|
|
// try {
|
|
// file = getDocumentFileRealPath(context, documentFile);
|
|
// } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
|
// Log.e(TAG, "scanDocumentFile: ", e);
|
|
// }
|
|
// if (file == null) return;
|
|
// MediaScannerConnection.scanFile(context,
|
|
// new String[]{file.getAbsolutePath()},
|
|
// new String[]{documentFile.getType()},
|
|
// callback);
|
|
// }
|
|
|
|
public static File getDocumentFileRealPath(@NonNull final Context context,
|
|
@NonNull final DocumentFile documentFile)
|
|
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
|
final String docId = DocumentsContract.getDocumentId(documentFile.getUri());
|
|
final String[] split = docId.split(":");
|
|
final String type = split[0];
|
|
|
|
if (type.equalsIgnoreCase("primary")) {
|
|
return new File(Environment.getExternalStorageDirectory(), split[1]);
|
|
} else if (type.equalsIgnoreCase("raw")) {
|
|
return new File(split[1]);
|
|
} else {
|
|
if (volumes == null) {
|
|
final StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
|
if (sm == null) return null;
|
|
final Method getVolumeListMethod = sm.getClass().getMethod("getVolumeList");
|
|
volumes = (Object[]) getVolumeListMethod.invoke(sm);
|
|
}
|
|
if (volumes == null) return null;
|
|
for (Object volume : volumes) {
|
|
final Method getUuidMethod = volume.getClass().getMethod("getUuid");
|
|
final String uuid = (String) getUuidMethod.invoke(volume);
|
|
|
|
if (uuid != null && uuid.equalsIgnoreCase(type)) {
|
|
final Method getPathMethod = volume.getClass().getMethod("getPath");
|
|
final String path = (String) getPathMethod.invoke(volume);
|
|
return new File(path, split[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static void setupSelectedDir(@NonNull final Context context,
|
|
@NonNull final Intent intent) throws DownloadUtils.ReselectDocumentTreeException {
|
|
final Uri dirUri = intent.getData();
|
|
Log.d(TAG, "onActivityResult: " + dirUri);
|
|
if (dirUri == null) return;
|
|
final int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
context.getContentResolver().takePersistableUriPermission(dirUri, takeFlags);
|
|
// re-init DownloadUtils
|
|
DownloadUtils.init(context, dirUri.toString());
|
|
}
|
|
|
|
@NonNull
|
|
public static Point getNavigationBarSize(@NonNull Context context) {
|
|
Point appUsableSize = getAppUsableScreenSize(context);
|
|
Point realScreenSize = getRealScreenSize(context);
|
|
|
|
// navigation bar on the right
|
|
if (appUsableSize.x < realScreenSize.x) {
|
|
return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
|
|
}
|
|
|
|
// navigation bar at the bottom
|
|
if (appUsableSize.y < realScreenSize.y) {
|
|
return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
|
|
}
|
|
|
|
// navigation bar is not present
|
|
return new Point();
|
|
}
|
|
|
|
@NonNull
|
|
public static Point getAppUsableScreenSize(@NonNull Context context) {
|
|
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
|
Display display = windowManager.getDefaultDisplay();
|
|
Point size = new Point();
|
|
display.getSize(size);
|
|
return size;
|
|
}
|
|
|
|
@NonNull
|
|
public static Point getRealScreenSize(@NonNull Context context) {
|
|
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
|
Display display = windowManager.getDefaultDisplay();
|
|
Point size = new Point();
|
|
display.getRealSize(size);
|
|
return size;
|
|
}
|
|
|
|
public static <F, S> LiveData<Pair<F, S>> zipLiveData(@NonNull final LiveData<F> firstLiveData,
|
|
@NonNull final LiveData<S> secondLiveData) {
|
|
final ZippedLiveData<F, S> zippedLiveData = new ZippedLiveData<>();
|
|
zippedLiveData.addFirstSource(firstLiveData);
|
|
zippedLiveData.addSecondSource(secondLiveData);
|
|
return zippedLiveData;
|
|
}
|
|
|
|
public static class ZippedLiveData<F, S> extends MediatorLiveData<Pair<F, S>> {
|
|
private F lastF;
|
|
private S lastS;
|
|
|
|
private void update() {
|
|
F localLastF = lastF;
|
|
S localLastS = lastS;
|
|
if (localLastF != null && localLastS != null) {
|
|
setValue(new Pair<>(localLastF, localLastS));
|
|
}
|
|
}
|
|
|
|
public void addFirstSource(@NonNull final LiveData<F> firstLiveData) {
|
|
addSource(firstLiveData, f -> {
|
|
lastF = f;
|
|
update();
|
|
});
|
|
}
|
|
|
|
public void addSecondSource(@NonNull final LiveData<S> secondLiveData) {
|
|
addSource(secondLiveData, s -> {
|
|
lastS = s;
|
|
update();
|
|
});
|
|
}
|
|
}
|
|
}
|