mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(android): edge-to-edge
Squashed from feat/edge-to-edge and resolved conflicts
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
package org.nativescript.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -29,18 +29,22 @@ public class GridLayout extends LayoutBase {
|
||||
private final HashMap<View, MeasureSpecs> map = new HashMap<>();
|
||||
|
||||
public GridLayout(Context context) {
|
||||
this(context, (AttributeSet)null);
|
||||
this(context, (AttributeSet) null);
|
||||
}
|
||||
|
||||
public GridLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public GridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public GridLayout(Context context, String rows) {
|
||||
this(context);
|
||||
this.addRowsFromJSON(rows);
|
||||
}
|
||||
|
||||
public GridLayout(Context context, String rows, String columns) {
|
||||
this(context, rows);
|
||||
this.addColumnsFromJSON(rows);
|
||||
@@ -92,7 +96,7 @@ public class GridLayout extends LayoutBase {
|
||||
return;
|
||||
}
|
||||
JSONArray rows = new JSONArray(value);
|
||||
for (int i = 0; i < rows.length() ; i++) {
|
||||
for (int i = 0; i < rows.length(); i++) {
|
||||
JSONObject row = rows.getJSONObject(i);
|
||||
addRow(row.getInt("value"), GridUnitType.values()[row.getInt("type")]);
|
||||
}
|
||||
@@ -101,13 +105,14 @@ public class GridLayout extends LayoutBase {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void addColumnsFromJSON(String value) {
|
||||
try {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
JSONArray columns = new JSONArray(value);
|
||||
for (int i = 0; i < columns.length() ; i++) {
|
||||
for (int i = 0; i < columns.length(); i++) {
|
||||
JSONObject column = columns.getJSONObject(i);
|
||||
addColumn(column.getInt("value"), GridUnitType.values()[column.getInt("type")]);
|
||||
}
|
||||
@@ -116,6 +121,7 @@ public class GridLayout extends LayoutBase {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void addRowsAndColumnsFromJSON(String rowsString, String jsonString) {
|
||||
addRowsFromJSON(rowsString);
|
||||
addColumnsFromJSON(jsonString);
|
||||
@@ -223,7 +229,7 @@ public class GridLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
private ItemSpec getColumnSpec(CommonLayoutParams lp) {
|
||||
if (this._cols.size() == 0) {
|
||||
if (this._cols.isEmpty()) {
|
||||
return this.helper.singleColumn;
|
||||
}
|
||||
|
||||
@@ -232,7 +238,7 @@ public class GridLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
private ItemSpec getRowSpec(CommonLayoutParams lp) {
|
||||
if (this._rows.size() == 0) {
|
||||
if (this._rows.isEmpty()) {
|
||||
return this.helper.singleRow;
|
||||
}
|
||||
|
||||
@@ -241,7 +247,7 @@ public class GridLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
private int getColumnSpan(CommonLayoutParams lp, int columnIndex) {
|
||||
if (this._cols.size() == 0) {
|
||||
if (this._cols.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -249,7 +255,7 @@ public class GridLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
private int getRowSpan(CommonLayoutParams lp, int rowIndex) {
|
||||
if (this._rows.size() == 0) {
|
||||
if (this._rows.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -344,8 +350,10 @@ public class GridLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
MeasureSpecs measureSpecs = this.map.get(child);
|
||||
this.updateMeasureSpecs(child, measureSpecs);
|
||||
this.helper.addMeasureSpec(measureSpecs);
|
||||
if (measureSpecs != null) {
|
||||
this.updateMeasureSpecs(child, measureSpecs);
|
||||
this.helper.addMeasureSpec(measureSpecs);
|
||||
}
|
||||
}
|
||||
|
||||
this.helper.measure();
|
||||
@@ -1145,7 +1153,7 @@ class MeasureHelper {
|
||||
}
|
||||
|
||||
if (remainingSpace > 0) {
|
||||
this.minRowStarValue = Math.max(remainingSpace / measureSpec.starRowsCount, this.minRowStarValue);
|
||||
this.minRowStarValue = Math.max((float) remainingSpace / measureSpec.starRowsCount, this.minRowStarValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1165,7 +1173,7 @@ class MeasureHelper {
|
||||
}
|
||||
|
||||
if (remainingSpace > 0) {
|
||||
this.minColumnStarValue = Math.max(remainingSpace / measureSpec.starColumnsCount, this.minColumnStarValue);
|
||||
this.minColumnStarValue = Math.max((float) remainingSpace / measureSpec.starColumnsCount, this.minColumnStarValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,20 +6,305 @@ import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
/**
|
||||
* @author hhristov
|
||||
*/
|
||||
public abstract class LayoutBase extends ViewGroup {
|
||||
private boolean passThroughParent;
|
||||
boolean applyingEdges;
|
||||
|
||||
public static final int OverflowEdgeNone = 0;
|
||||
public static final int OverflowEdgeLeft = 1;
|
||||
public static final int OverflowEdgeTop = 1 << 1;
|
||||
public static final int OverflowEdgeRight = 1 << 2;
|
||||
public static final int OverflowEdgeBottom = 1 << 3;
|
||||
public static final int OverflowEdgeDontApply = 1 << 4;
|
||||
public static final int OverflowEdgeLeftDontConsume = 1 << 5;
|
||||
public static final int OverflowEdgeTopDontConsume = 1 << 6;
|
||||
public static final int OverflowEdgeRightDontConsume = 1 << 7;
|
||||
public static final int OverflowEdgeBottomDontConsume = 1 << 8;
|
||||
public static final int OverflowEdgeAllButLeft = 1 << 9;
|
||||
public static final int OverflowEdgeAllButTop = 1 << 10;
|
||||
public static final int OverflowEdgeAllButRight = 1 << 11;
|
||||
public static final int OverflowEdgeAllButBottom = 1 << 12;
|
||||
|
||||
public static final class BufferOffset {
|
||||
public static final int INSET_LEFT = 0;
|
||||
public static final int INSET_TOP = 4;
|
||||
public static final int INSET_RIGHT = 8;
|
||||
public static final int INSET_BOTTOM = 12;
|
||||
|
||||
public static final int INSET_LEFT_CONSUMED = 16;
|
||||
public static final int INSET_TOP_CONSUMED = 20;
|
||||
public static final int INSET_RIGHT_CONSUMED = 24;
|
||||
public static final int INSET_BOTTOM_CONSUMED = 28;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
int mPaddingLeft = 0;
|
||||
int mPaddingTop = 0;
|
||||
int mPaddingRight = 0;
|
||||
int mPaddingBottom = 0;
|
||||
|
||||
Insets edgeInsets = Insets.NONE;
|
||||
|
||||
int overflowEdge = OverflowEdgeNone;
|
||||
|
||||
private final ByteBuffer insetBuffer = ByteBuffer.allocateDirect(32);
|
||||
|
||||
private WindowInsetListener insetListener = null;
|
||||
|
||||
public void setInsetListener(@Nullable WindowInsetListener insetListener) {
|
||||
this.insetListener = insetListener;
|
||||
}
|
||||
|
||||
public interface WindowInsetListener {
|
||||
void onApplyWindowInsets(ByteBuffer inset);
|
||||
}
|
||||
|
||||
private static final byte[] EMPTY_INSETS = new byte[32];
|
||||
|
||||
|
||||
private boolean pendingInsetApply = false;
|
||||
private final OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(@NonNull View v) {
|
||||
if (pendingInsetApply) {
|
||||
pendingInsetApply = false;
|
||||
removeOnAttachStateChangeListener(onAttachStateChangeListener);
|
||||
ViewCompat.requestApplyInsets(v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull View v) {
|
||||
}
|
||||
};
|
||||
|
||||
public LayoutBase(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
insetBuffer.order(ByteOrder.nativeOrder());
|
||||
// if incoming inset is empty and previous inset is empty return consumed
|
||||
// an incoming empty inset is one way to detect a consumed inset e.g multiple views consumed top/bottom
|
||||
androidx.core.view.OnApplyWindowInsetsListener windowInsetsListener = new androidx.core.view.OnApplyWindowInsetsListener() {
|
||||
@NonNull
|
||||
@Override
|
||||
public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowInsetsCompat insets) {
|
||||
if (insets.isConsumed()) {
|
||||
return insets;
|
||||
}
|
||||
if (v instanceof LayoutBase) {
|
||||
LayoutBase base = (LayoutBase) v;
|
||||
|
||||
Insets statusBar = insets.getInsets(WindowInsetsCompat.Type.statusBars());
|
||||
Insets navBar = insets.getInsets(WindowInsetsCompat.Type.navigationBars());
|
||||
Insets ime = insets.getInsets(WindowInsetsCompat.Type.ime());
|
||||
|
||||
int insetLeft = navBar.left;
|
||||
int insetRight = navBar.right;
|
||||
int insetBottom = Math.max(navBar.bottom, ime.bottom);
|
||||
|
||||
insetBuffer.put(EMPTY_INSETS, 0, 32);
|
||||
insetBuffer.rewind();
|
||||
|
||||
if (overflowEdge == OverflowEdgeNone) {
|
||||
base.applyingEdges = true;
|
||||
v.setPadding(mPaddingLeft + insetLeft, mPaddingTop + statusBar.top, mPaddingRight + insetRight, mPaddingBottom + insetBottom);
|
||||
edgeInsets = Insets.of(insetLeft, statusBar.top, insetRight, insetBottom);
|
||||
base.applyingEdges = false;
|
||||
return WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
|
||||
if (base.insetListener != null) {
|
||||
if (overflowEdge == OverflowEdgeDontApply) {
|
||||
// if incoming inset is empty and previous inset is empty return consumed
|
||||
// an incoming empty inset is one way to detect a consumed inset e.g multiple views consumed top/bottom
|
||||
if (Insets.NONE.equals(statusBar) && Insets.NONE.equals(navBar) && Insets.NONE.equals(ime) && Insets.NONE.equals(edgeInsets)) {
|
||||
return WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
|
||||
IntBuffer insetData = insetBuffer.asIntBuffer();
|
||||
|
||||
boolean leftPreviouslyConsumed = insetLeft == 0;
|
||||
boolean topPreviouslyConsumed = statusBar.top == 0;
|
||||
boolean rightPreviouslyConsumed = insetRight == 0;
|
||||
boolean bottomPreviouslyConsumed = insetBottom == 0;
|
||||
|
||||
|
||||
insetData.put(0, insetLeft).put(1, statusBar.top).put(2, insetRight).put(3, insetBottom).put(4, leftPreviouslyConsumed ? 1 : 0).put(5, topPreviouslyConsumed ? 1 : 0).put(6, rightPreviouslyConsumed ? 1 : 0).put(7, bottomPreviouslyConsumed ? 1 : 0);
|
||||
|
||||
base.insetListener.onApplyWindowInsets(insetBuffer);
|
||||
|
||||
int leftInset = insetData.get(0);
|
||||
int topInset = insetData.get(1);
|
||||
int rightInset = insetData.get(2);
|
||||
int bottomInset = insetData.get(3);
|
||||
|
||||
boolean leftConsumed = insetData.get(4) > 0;
|
||||
boolean topConsumed = insetData.get(5) > 0;
|
||||
boolean rightConsumed = insetData.get(6) > 0;
|
||||
boolean bottomConsumed = insetData.get(7) > 0;
|
||||
|
||||
if (leftConsumed && topConsumed && rightConsumed && bottomConsumed) {
|
||||
edgeInsets = Insets.of(leftInset, topInset, rightInset, bottomInset);
|
||||
base.setPadding(leftInset, topInset, rightInset, bottomInset);
|
||||
return new WindowInsetsCompat.Builder().setInsets(WindowInsetsCompat.Type.systemBars(), Insets.NONE).build();
|
||||
}
|
||||
|
||||
base.setPadding(leftPreviouslyConsumed ? 0 : leftInset, topPreviouslyConsumed ? 0 : topInset, rightPreviouslyConsumed ? 0 : rightInset, bottomPreviouslyConsumed ? 0 : bottomInset);
|
||||
|
||||
// restore inset edge if not consumed
|
||||
|
||||
if (!(leftPreviouslyConsumed || leftConsumed)) {
|
||||
leftInset = insetLeft;
|
||||
}
|
||||
|
||||
if (!(topPreviouslyConsumed || topConsumed)) {
|
||||
topInset = statusBar.top;
|
||||
}
|
||||
|
||||
if (!(rightPreviouslyConsumed || rightConsumed)) {
|
||||
rightInset = insetRight;
|
||||
}
|
||||
|
||||
if (!(bottomPreviouslyConsumed || bottomConsumed)) {
|
||||
bottomInset = insetBottom;
|
||||
}
|
||||
|
||||
edgeInsets = Insets.of(leftPreviouslyConsumed ? 0 : leftInset, topPreviouslyConsumed ? 0 : topInset, rightPreviouslyConsumed ? 0 : rightInset, bottomPreviouslyConsumed ? 0 : bottomInset);
|
||||
|
||||
return new WindowInsetsCompat.Builder().setInsets(WindowInsetsCompat.Type.systemBars(), Insets.of(leftPreviouslyConsumed || leftConsumed ? 0 : leftInset, topPreviouslyConsumed || topConsumed ? 0 : topInset, rightPreviouslyConsumed || rightConsumed ? 0 : rightInset, bottomPreviouslyConsumed || bottomConsumed ? 0 : bottomInset)).build();
|
||||
}
|
||||
}
|
||||
|
||||
boolean overflowLeftConsume = (overflowEdge & OverflowEdgeLeft) == OverflowEdgeLeft;
|
||||
boolean overflowTopConsume = (overflowEdge & OverflowEdgeTop) == OverflowEdgeTop;
|
||||
boolean overflowRightConsume = (overflowEdge & OverflowEdgeRight) == OverflowEdgeRight;
|
||||
boolean overflowBottomConsume = (overflowEdge & OverflowEdgeBottom) == OverflowEdgeBottom;
|
||||
|
||||
boolean overflowLeft = (overflowEdge & OverflowEdgeLeftDontConsume) == OverflowEdgeLeftDontConsume;
|
||||
boolean overflowTop = (overflowEdge & OverflowEdgeTopDontConsume) == OverflowEdgeTopDontConsume;
|
||||
boolean overflowRight = (overflowEdge & OverflowEdgeRightDontConsume) == OverflowEdgeRightDontConsume;
|
||||
boolean overflowBottom = (overflowEdge & OverflowEdgeBottomDontConsume) == OverflowEdgeBottomDontConsume;
|
||||
|
||||
|
||||
boolean overflowAllButLeft = (overflowEdge & OverflowEdgeAllButLeft) == OverflowEdgeAllButLeft;
|
||||
boolean overflowAllButTop = (overflowEdge & OverflowEdgeAllButTop) == OverflowEdgeAllButTop;
|
||||
boolean overflowAllButRight = (overflowEdge & OverflowEdgeAllButRight) == OverflowEdgeAllButRight;
|
||||
boolean overflowAllButBottom = (overflowEdge & OverflowEdgeAllButBottom) == OverflowEdgeAllButBottom;
|
||||
|
||||
|
||||
WindowInsetsCompat ret = insets;
|
||||
base.applyingEdges = true;
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
|
||||
|
||||
if (overflowAllButLeft || overflowAllButTop || overflowAllButRight || overflowAllButBottom) {
|
||||
Insets newInset;
|
||||
if (overflowAllButLeft) {
|
||||
left = mPaddingLeft + insetLeft;
|
||||
edgeInsets = Insets.of(insetLeft, 0, 0, 0);
|
||||
newInset = Insets.of(0, statusBar.top, insetRight, insetBottom);
|
||||
} else if (overflowAllButTop) {
|
||||
top = mPaddingTop + statusBar.top;
|
||||
edgeInsets = Insets.of(0, statusBar.top, 0, 0);
|
||||
newInset = Insets.of(insetLeft, 0, insetRight, insetBottom);
|
||||
} else if (overflowAllButRight) {
|
||||
right = mPaddingRight + insetRight;
|
||||
edgeInsets = Insets.of(0, 0, insetRight, 0);
|
||||
newInset = Insets.of(insetLeft, statusBar.top, 0, insetBottom);
|
||||
} else {
|
||||
bottom = mPaddingBottom + insetBottom;
|
||||
edgeInsets = Insets.of(0, 0, 0, insetBottom);
|
||||
newInset = Insets.of(insetLeft, statusBar.top, insetRight, 0);
|
||||
}
|
||||
|
||||
ret = new WindowInsetsCompat.Builder().setInsets(WindowInsetsCompat.Type.systemBars(), newInset).build();
|
||||
base.setPadding(left, top, right, bottom);
|
||||
base.applyingEdges = false;
|
||||
if (newInset == Insets.NONE) {
|
||||
return WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (overflowLeftConsume || overflowLeft) {
|
||||
top = mPaddingTop + statusBar.top;
|
||||
right = mPaddingRight + insetRight;
|
||||
bottom = mPaddingBottom + insetBottom;
|
||||
edgeInsets = Insets.of(insetLeft, statusBar.top, insetRight, insetBottom);
|
||||
if (overflowRightConsume) {
|
||||
ret = WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
}
|
||||
if (overflowTopConsume || overflowTop) {
|
||||
left = mPaddingLeft + insetLeft;
|
||||
right = mPaddingRight + insetRight;
|
||||
bottom = mPaddingBottom + insetBottom;
|
||||
edgeInsets = Insets.of(insetLeft, statusBar.top, insetRight, insetBottom);
|
||||
if (overflowTopConsume) {
|
||||
ret = WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
}
|
||||
if (overflowRightConsume || overflowRight) {
|
||||
left = mPaddingLeft + insetLeft;
|
||||
top = mPaddingTop + statusBar.top;
|
||||
bottom = mPaddingBottom + insetBottom;
|
||||
edgeInsets = Insets.of(insetLeft, statusBar.top, insetRight, insetBottom);
|
||||
if (overflowRightConsume) {
|
||||
ret = WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
}
|
||||
if (overflowBottomConsume || overflowBottom) {
|
||||
left = mPaddingLeft + insetLeft;
|
||||
top = mPaddingTop + statusBar.top;
|
||||
right = mPaddingRight + insetRight;
|
||||
edgeInsets = Insets.of(insetLeft, statusBar.top, insetRight, insetBottom);
|
||||
if (overflowBottomConsume) {
|
||||
ret = WindowInsetsCompat.CONSUMED;
|
||||
}
|
||||
}
|
||||
|
||||
base.setPadding(left, top, right, bottom);
|
||||
|
||||
base.applyingEdges = false;
|
||||
return ret;
|
||||
}
|
||||
return insets;
|
||||
}
|
||||
};
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this, windowInsetsListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
public LayoutBase(Context context) {
|
||||
super(context);
|
||||
|
||||
}
|
||||
|
||||
public Insets getEdgeInsets() {
|
||||
return edgeInsets;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,4 +380,32 @@ public abstract class LayoutBase extends ViewGroup {
|
||||
public void setPassThroughParent(boolean value) {
|
||||
this.passThroughParent = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
if (!applyingEdges) {
|
||||
mPaddingLeft = left;
|
||||
mPaddingTop = top;
|
||||
mPaddingRight = right;
|
||||
mPaddingBottom = bottom;
|
||||
}
|
||||
super.setPadding(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public void setOverflowEdge(int value) {
|
||||
overflowEdge = value;
|
||||
if (pendingInsetApply) {
|
||||
return;
|
||||
}
|
||||
if (isAttachedToWindow()) {
|
||||
ViewCompat.requestApplyInsets(this);
|
||||
} else {
|
||||
pendingInsetApply = true;
|
||||
addOnAttachStateChangeListener(onAttachStateChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
public int getOverflowEdge() {
|
||||
return overflowEdge;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.nativescript.widgets;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
@@ -23,6 +24,9 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.activity.SystemBarStyle;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
@@ -38,8 +42,53 @@ import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
public class Utils {
|
||||
|
||||
public interface HandleDarkMode {
|
||||
boolean onHandle(int bar, Resources resources);
|
||||
}
|
||||
|
||||
enum HandleDarkModeBar {
|
||||
status(0),
|
||||
navigation(1);
|
||||
|
||||
private final int mValue;
|
||||
|
||||
HandleDarkModeBar(int i) {
|
||||
this.mValue = i;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return this.mValue;
|
||||
}
|
||||
}
|
||||
|
||||
// The light scrim color used in the platform API 29+
|
||||
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/policy/DecorView.java;drc=6ef0f022c333385dba2c294e35b8de544455bf19;l=142
|
||||
static final int DefaultLightScrim = Color.argb(0xe6, 0xFF, 0xFF, 0xFF);
|
||||
|
||||
// The dark scrim color used in the platform.
|
||||
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/res/color/system_bar_background_semi_transparent.xml
|
||||
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/remote_color_resources_res/values/colors.xml;l=67
|
||||
static final int DefaultDarkScrim = Color.argb(0x80, 0x1b, 0x1b, 0x1b);
|
||||
|
||||
public static void enableEdgeToEdge(ComponentActivity activity) {
|
||||
androidx.activity.EdgeToEdge.enable(activity);
|
||||
}
|
||||
|
||||
public static void enableEdgeToEdge(ComponentActivity activity, HandleDarkMode handleDarkMode) {
|
||||
androidx.activity.EdgeToEdge.enable(activity, SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT, resources -> handleDarkMode.onHandle(HandleDarkModeBar.status.getValue(), resources)), SystemBarStyle.auto(DefaultLightScrim, DefaultDarkScrim, resources -> handleDarkMode.onHandle(HandleDarkModeBar.navigation.getValue(), resources)));
|
||||
}
|
||||
|
||||
public static void enableEdgeToEdge(ComponentActivity activity, @ColorInt Integer statusBarLight, @ColorInt Integer statusBarDark, @ColorInt Integer navigationBarLight, @ColorInt Integer navigationBarDark) {
|
||||
androidx.activity.EdgeToEdge.enable(activity, SystemBarStyle.auto(statusBarLight, statusBarDark), SystemBarStyle.auto(navigationBarLight, navigationBarDark));
|
||||
}
|
||||
|
||||
public static void enableEdgeToEdge(ComponentActivity activity, @ColorInt Integer statusBarLight, @ColorInt Integer statusBarDark, @ColorInt Integer navigationBarLight, @ColorInt Integer navigationBarDark, HandleDarkMode handleDarkMode) {
|
||||
androidx.activity.EdgeToEdge.enable(activity, SystemBarStyle.auto(statusBarLight, statusBarDark, resources -> handleDarkMode.onHandle(HandleDarkModeBar.status.getValue(), resources)), SystemBarStyle.auto(navigationBarLight, navigationBarDark, resources -> handleDarkMode.onHandle(HandleDarkModeBar.navigation.getValue(), resources)));
|
||||
}
|
||||
|
||||
public static Drawable getDrawable(String uri, Context context) {
|
||||
int resId = 0;
|
||||
int resPrefixLength = "res://".length();
|
||||
@@ -426,10 +475,7 @@ public class Utils {
|
||||
|
||||
Bitmap.CompressFormat targetFormat = getTargetFormat(format);
|
||||
|
||||
try (
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
Base64OutputStream base64Stream = new Base64OutputStream(outputStream, android.util.Base64.NO_WRAP)
|
||||
) {
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Base64OutputStream base64Stream = new Base64OutputStream(outputStream, android.util.Base64.NO_WRAP)) {
|
||||
bitmap.compress(targetFormat, quality, base64Stream);
|
||||
result = outputStream.toString();
|
||||
} catch (Exception e) {
|
||||
@@ -460,9 +506,7 @@ public class Utils {
|
||||
return new Pair<>((int) width, (int) height);
|
||||
}
|
||||
|
||||
return new Pair<>(
|
||||
Math.round((maxSize * width) / height)
|
||||
, (int) maxSize);
|
||||
return new Pair<>(Math.round((maxSize * width) / height), (int) maxSize);
|
||||
}
|
||||
|
||||
if (width <= maxSize) {
|
||||
|
||||
Reference in New Issue
Block a user