New snackbars

This commit is contained in:
utkabobr
2025-04-02 01:38:45 +03:00
parent 58b24d5137
commit 1976ac4899
17 changed files with 507 additions and 33 deletions
@@ -2,14 +2,20 @@ package ru.ytkab0bp.slicebeam;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Process;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
@@ -28,6 +34,7 @@ import org.json.JSONArray;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -40,23 +47,27 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.zip.ZipFile;
import ru.ytkab0bp.slicebeam.components.BeamAlertDialogBuilder;
import ru.ytkab0bp.slicebeam.components.ChangeLogBottomSheet;
import ru.ytkab0bp.slicebeam.components.UnfoldMenu;
import ru.ytkab0bp.slicebeam.config.ConfigObject;
import ru.ytkab0bp.slicebeam.events.NeedDismissSnackbarEvent;
import ru.ytkab0bp.slicebeam.events.NeedSnackbarEvent;
import ru.ytkab0bp.slicebeam.events.ObjectsListChangedEvent;
import ru.ytkab0bp.slicebeam.fragment.BedFragment;
import ru.ytkab0bp.slicebeam.navigation.MobileNavigationDelegate;
import ru.ytkab0bp.slicebeam.navigation.NavigationDelegate;
import ru.ytkab0bp.slicebeam.slic3r.Model;
import ru.ytkab0bp.slicebeam.slic3r.Slic3rConfigWrapper;
import ru.ytkab0bp.slicebeam.slic3r.Slic3rRuntimeError;
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
import ru.ytkab0bp.slicebeam.utils.IOUtils;
import ru.ytkab0bp.slicebeam.utils.Prefs;
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
import ru.ytkab0bp.slicebeam.view.SnackbarsLayout;
public class MainActivity extends AppCompatActivity {
public final static int REQUEST_CODE_OPEN_FILE = 1, REQUEST_CODE_EXPORT_GCODE = 2,
@@ -496,6 +507,51 @@ public class MainActivity extends AppCompatActivity {
}).start();
}
private void loadFile(File f, boolean autoorient) {
String tag = UUID.randomUUID().toString();
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.MenuFileOpenFileLoading).tag(tag));
IOUtils.IO_POOL.submit(() -> {
Process.setThreadPriority(-20);
if (delegate.getCurrentFragment() instanceof BedFragment) {
BedFragment fragment = (BedFragment) delegate.getCurrentFragment();
try {
boolean gcode = f.getName().endsWith(".gcode");
if (gcode) {
fragment.loadGCode(f);
} else {
fragment.loadModel(f);
}
fragment.getGlView().queueEvent(() -> {
if (!gcode) {
SliceBeam.EVENT_BUS.fireEvent(new ObjectsListChangedEvent());
}
Model model = fragment.getGlView().getRenderer().getModel();
int i = model.getObjectsCount() - 1;
if (autoorient) {
model.autoOrient(i);
fragment.getGlView().getRenderer().invalidateGlModel(i);
fragment.getGlView().requestRender();
}
SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag));
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuFileOpenFileLoaded));
if (model.isBigObject(i)) {
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.WARNING, R.string.MenuFileOpenFileBigObject));
}
});
} catch (Slic3rRuntimeError e) {
Log.e("MainActivity", "Failed to load model", e);
f.delete();
ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this)
.setTitle(R.string.MenuFileOpenFileFailed)
.setMessage(e.toString())
.setPositiveButton(android.R.string.ok, null)
.show());
}
}
});
}
private void loadFile(Uri uri) {
if (uri == null) return;
@@ -534,30 +590,7 @@ public class MainActivity extends AppCompatActivity {
}
fos.close();
in.close();
ViewUtils.postOnMainThread(() -> {
if (delegate.getCurrentFragment() instanceof BedFragment) {
BedFragment fragment = (BedFragment) delegate.getCurrentFragment();
try {
if (f.getName().endsWith(".gcode")) {
fragment.loadGCode(f);
} else {
fragment.loadModel(f);
SliceBeam.EVENT_BUS.fireEvent(new ObjectsListChangedEvent());
}
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuFileOpenFileLoaded));
} catch (Slic3rRuntimeError e) {
Log.e("MainActivity", "Failed to load model", e);
f.delete();
ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this)
.setTitle(R.string.MenuFileOpenFileFailed)
.setMessage(e.toString())
.setPositiveButton(android.R.string.ok, null)
.show());
}
}
});
loadFile(f, false);
} catch (Exception e) {
Log.e("MainActivity", "Failed to write cache file", e);
@@ -0,0 +1,12 @@
package ru.ytkab0bp.slicebeam.events;
import ru.ytkab0bp.eventbus.Event;
@Event
public class NeedDismissSnackbarEvent {
public final String tag;
public NeedDismissSnackbarEvent(String tag) {
this.tag = tag;
}
}
@@ -2,10 +2,18 @@ package ru.ytkab0bp.slicebeam.events;
import ru.ytkab0bp.eventbus.Event;
import ru.ytkab0bp.slicebeam.SliceBeam;
import ru.ytkab0bp.slicebeam.view.SnackbarsLayout;
@Event
public class NeedSnackbarEvent {
public final CharSequence title;
public SnackbarsLayout.Type type = SnackbarsLayout.Type.DONE;
public String tag;
public NeedSnackbarEvent(SnackbarsLayout.Type type, CharSequence title) {
this.type = type;
this.title = title;
}
public NeedSnackbarEvent(CharSequence title) {
this.title = title;
@@ -14,4 +22,14 @@ public class NeedSnackbarEvent {
public NeedSnackbarEvent(int title, Object... args) {
this.title = SliceBeam.INSTANCE.getString(title, args);
}
public NeedSnackbarEvent(SnackbarsLayout.Type type, int title, Object... args) {
this.type = type;
this.title = SliceBeam.INSTANCE.getString(title, args);
}
public NeedSnackbarEvent tag(String tag) {
this.tag = tag;
return this;
}
}
@@ -14,13 +14,11 @@ import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.dynamicanimation.animation.FloatValueHolder;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.google.android.material.navigation.NavigationBarView;
import com.google.android.material.snackbar.Snackbar;
import java.io.File;
@@ -38,6 +36,7 @@ import ru.ytkab0bp.slicebeam.components.bed_menu.SliceMenu;
import ru.ytkab0bp.slicebeam.components.bed_menu.TransformMenu;
import ru.ytkab0bp.slicebeam.config.ConfigObject;
import ru.ytkab0bp.slicebeam.events.FlattenModeResetEvent;
import ru.ytkab0bp.slicebeam.events.NeedDismissSnackbarEvent;
import ru.ytkab0bp.slicebeam.events.NeedSnackbarEvent;
import ru.ytkab0bp.slicebeam.events.SlicingProgressEvent;
import ru.ytkab0bp.slicebeam.navigation.Fragment;
@@ -51,6 +50,7 @@ import ru.ytkab0bp.slicebeam.utils.ViewUtils;
import ru.ytkab0bp.slicebeam.view.BedSwipeDownLayout;
import ru.ytkab0bp.slicebeam.view.DividerView;
import ru.ytkab0bp.slicebeam.view.GLView;
import ru.ytkab0bp.slicebeam.view.SnackbarsLayout;
import ru.ytkab0bp.slicebeam.view.ThemeBottomNavigationView;
import ru.ytkab0bp.slicebeam.view.ThemeRailNavigationView;
@@ -59,7 +59,7 @@ public class BedFragment extends Fragment {
private final static int MENU_SIZE_DP = 80;
private FrameLayout overlayLayout;
private CoordinatorLayout snackbarsLayout;
private SnackbarsLayout snackbarsLayout;
private GLView glView;
private NavigationBarView navigationView;
@@ -126,7 +126,16 @@ public class BedFragment extends Fragment {
@EventHandler(runOnMainThread = true)
public void onNeedSnackbar(NeedSnackbarEvent e) {
Snackbar.make(snackbarsLayout, e.title, Snackbar.LENGTH_SHORT).show();
SnackbarsLayout.Snackbar s = new SnackbarsLayout.Snackbar(e.type, e.title);
if (e.tag != null) {
s.tag(e.tag);
}
snackbarsLayout.show(s);
}
@EventHandler(runOnMainThread = true)
public void onDismissSnackbar(NeedDismissSnackbarEvent e) {
snackbarsLayout.dismiss(e.tag);
}
public void showUnfoldMenu(UnfoldMenu menu, View from) {
@@ -380,7 +389,7 @@ public class BedFragment extends Fragment {
} else {
overlayLayout.addView(contentView = ll);
}
overlayLayout.addView(snackbarsLayout = new CoordinatorLayout(ctx), new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) {{
overlayLayout.addView(snackbarsLayout = new SnackbarsLayout(ctx), new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) {{
if (portrait) {
bottomMargin = ViewUtils.dp(80 * 2);
} else {
@@ -390,7 +399,7 @@ public class BedFragment extends Fragment {
return overlayLayout;
}
public CoordinatorLayout getSnackbarsLayout() {
public SnackbarsLayout getSnackbarsLayout() {
return snackbarsLayout;
}
@@ -498,7 +507,6 @@ public class BedFragment extends Fragment {
}
});
} else {
glView.getRenderer().setModel(model = m);
glView.queueEvent(new Runnable() {
@Override
public void run() {
@@ -507,6 +515,8 @@ public class BedFragment extends Fragment {
ViewUtils.postOnMainThread(()-> glView.queueEvent(this));
return;
}
glView.getRenderer().setModel(model = m);
Vec3d center = bed.getVolumeMin().center(bed.getVolumeMax());
Vec3d objMin = new Vec3d(), objMax = new Vec3d();
Vec3d objTranslate = new Vec3d();
@@ -147,10 +147,22 @@ public class Model {
return list;
}
public int getExtruder(int i) {
return Native.model_get_extruder(pointer, i);
}
public void setExtruder(int i, int extruder) {
Native.model_set_extruder(pointer, i, extruder);
}
public void autoOrient(int i) {
Native.model_auto_orient(pointer, i);
}
public boolean isBigObject(int i) {
return Native.model_is_big_object(pointer, i);
}
public GCodeProcessorResult slice(String configPath, String gcodePath, SliceListener listener) throws Slic3rRuntimeError {
return new GCodeProcessorResult(Native.model_slice(pointer, configPath, gcodePath, listener));
}
@@ -72,6 +72,9 @@ class Native {
static native void model_flatten_rotate(long ptr, int i, long surfacePtr);
static native long[] model_create_flatten_planes(long ptr, int i);
static native void model_auto_orient(long ptr, int i);
static native boolean model_is_big_object(long ptr, int i);
static native int model_get_extruder(long ptr, int i);
static native void model_set_extruder(long ptr, int i, int extruder);
static native long model_slice(long ptr, String configPath, String path, SliceListener listener) throws Slic3rRuntimeError;
static native void model_release(long ptr);
@@ -47,6 +47,12 @@ public class BeamTheme {
colors.put(R.attr.yTrackColor, 0xff00bf00);
colors.put(R.attr.zTrackColor, 0xff0000bf);
colors.put(R.attr.snackbarBase, 0xFFEEEEEE);
colors.put(R.attr.snackbarDone, 0xFF56AB2F);
colors.put(R.attr.snackbarWarning, 0xFFAE660C);
colors.put(R.attr.snackbarInfo, 0xFF009DC6);
colors.put(R.attr.snackbarError, 0xFFDC100E);
colors.put(android.R.attr.textColorPrimary, 0xff000000);
colors.put(android.R.attr.textColorSecondary, 0x99000000);
colors.put(android.R.attr.windowBackground, 0xffffffff);
@@ -73,6 +79,8 @@ public class BeamTheme {
colors.put(R.attr.yTrackColor, 0xff00ee00);
colors.put(R.attr.zTrackColor, 0xff0000ee);
colors.put(R.attr.snackbarBase, 0xFF212121);
colors.put(android.R.attr.textColorPrimary, 0xffffffff);
colors.put(android.R.attr.textColorSecondary, 0x99ffffff);
colors.put(android.R.attr.windowBackground, 0xff121212);
@@ -15,10 +15,15 @@ import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import ru.ytkab0bp.slicebeam.config.ConfigObject;
public class IOUtils {
public static ExecutorService IO_POOL = Executors.newCachedThreadPool();
public static String readString(InputStream in) throws IOException {
return readString(in, false);
}
@@ -0,0 +1,307 @@
package ru.ytkab0bp.slicebeam.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Outline;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import androidx.dynamicanimation.animation.FloatValueHolder;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import java.util.Objects;
import ru.ytkab0bp.slicebeam.R;
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
public class SnackbarsLayout extends FrameLayout {
public SnackbarsLayout(@NonNull Context context) {
super(context);
}
public void show(Snackbar snackbar) {
SnackbarView v = new SnackbarView(getContext()).bind(snackbar);
addView(v);
applyTransforms();
new SpringAnimation(new FloatValueHolder(0))
.setMinimumVisibleChange(1 / 500f)
.setSpring(new SpringForce(1f)
.setStiffness(1000f)
.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY))
.addUpdateListener((animation, value, velocity) -> {
v.progress = value;
applyTransforms();
})
.start();
if (snackbar.lifetime > 0) {
ViewUtils.postOnMainThread(v::dismiss, snackbar.lifetime);
}
}
public void dismiss(String tag) {
for (int i = 0, s = getChildCount(); i < s; i++) {
SnackbarView snackbar = (SnackbarView) getChildAt(i);
if (Objects.equals(snackbar.snackbar.tag, tag)) {
snackbar.dismiss();
}
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
applyTransforms();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
applyTransforms();
}
private void applyTransforms() {
float y = getHeight() - ViewUtils.dp(8);
for (int i = getChildCount() - 1; i >= 0; i--) {
SnackbarView snackbar = (SnackbarView) getChildAt(i);
if (snackbar.getTag() == null) {
snackbar.setAlpha(snackbar.progress);
}
float yOff = snackbar.getAlpha() * snackbar.progress * (snackbar.getHeight() + ViewUtils.dp(8));
y -= yOff;
snackbar.setTranslationY(y);
}
}
private class SnackbarView extends LinearLayout {
private final static int MARGIN_DP = 8;
private ProgressBar progressBar;
private ImageView icon;
private TextView title;
private Snackbar snackbar;
private float progress;
private GestureDetector gestureDetector;
SnackbarView(Context context) {
super(context);
setElevation(ViewUtils.dp(4));
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, getWidth(), getHeight(), ViewUtils.dp(16));
}
});
setAlpha(0f);
setPadding(ViewUtils.dp(10), ViewUtils.dp(10), ViewUtils.dp(10), ViewUtils.dp(10));
setMinimumHeight(ViewUtils.dp(48));
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
FrameLayout fl = new FrameLayout(context);
icon = new ImageView(context);
fl.addView(icon, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
progressBar = new ProgressBar(context);
progressBar.setVisibility(GONE);
fl.addView(progressBar, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
addView(fl, new LinearLayout.LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28)) {{
setMarginStart(ViewUtils.dp(4));
setMarginEnd(ViewUtils.dp(14));
}});
title = new TextView(context);
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
title.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM));
title.setMaxLines(2);
title.setEllipsize(TextUtils.TruncateAt.END);
addView(title);
setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{
leftMargin = topMargin = rightMargin = bottomMargin = ViewUtils.dp(MARGIN_DP);
}});
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(@NonNull MotionEvent e) {
return true;
}
@Override
public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2, float distanceX, float distanceY) {
getParent().requestDisallowInterceptTouchEvent(true);
float off = e2.getX() - e1.getX();
setTranslationX(off);
return true;
}
@Override
public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2, float velocityX, float velocityY) {
if (snackbar.type == Type.LOADING) {
return false;
}
if (Math.abs(velocityX) >= 1500) {
if (velocityX > 0) {
animateTo(getWidth() + ViewUtils.dp(MARGIN_DP), true);
} else {
animateTo(-getWidth() - ViewUtils.dp(MARGIN_DP), true);
}
return true;
}
return false;
}
});
}
private void dismiss() {
setTag(1);
new SpringAnimation(new FloatValueHolder(0))
.setMinimumVisibleChange(1 / 500f)
.setSpring(new SpringForce(1f)
.setStiffness(1000f)
.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY))
.addUpdateListener((animation, value, velocity) -> {
setAlpha(1f - value);
applyTransforms();
})
.addEndListener((animation, canceled, value, velocity) -> {
if (getParent() == null) return;
((ViewGroup) getParent()).removeView(this);
})
.start();
}
private void animateTo(float x, boolean remove) {
if (remove) {
setTag(1);
}
float start = getTranslationX();
new SpringAnimation(new FloatValueHolder(0))
.setMinimumVisibleChange(1 / 500f)
.setSpring(new SpringForce(1f)
.setStiffness(1000f)
.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY))
.addUpdateListener((animation, value, velocity) -> {
setTranslationX(ViewUtils.lerp(start, x, value));
if (remove) {
progress = 1f - value;
applyTransforms();
}
})
.addEndListener((animation, canceled, value, velocity) -> {
if (remove) {
((ViewGroup) getParent()).removeView(SnackbarView.this);
}
})
.start();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if ((event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMasked() == MotionEvent.ACTION_CANCEL) && getTag() == null) {
animateTo(0, false);
}
MotionEvent ev = MotionEvent.obtain(event);
ev.offsetLocation(getTranslationX(), 0);
boolean ret = gestureDetector.onTouchEvent(ev);
ev.recycle();
return ret;
}
SnackbarView bind(Snackbar snackbar) {
this.snackbar = snackbar;
progressBar.setVisibility(snackbar.type == Type.LOADING ? VISIBLE : GONE);
icon.setVisibility(snackbar.type == Type.LOADING ? GONE : VISIBLE);
title.setText(snackbar.title);
switch (snackbar.type) {
case DONE:
icon.setImageResource(R.drawable.done_outline_28);
icon.setImageTintList(ColorStateList.valueOf(ThemesRepo.getColor(R.attr.snackbarDone)));
title.setTextColor(ThemesRepo.getColor(R.attr.snackbarDone));
setBackgroundColor(ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.snackbarBase), ThemesRepo.getColor(R.attr.snackbarDone), 0.15f));
break;
case WARNING:
icon.setImageResource(R.drawable.warning_triangle_outline_28);
icon.setImageTintList(ColorStateList.valueOf(ThemesRepo.getColor(R.attr.snackbarWarning)));
title.setTextColor(ThemesRepo.getColor(R.attr.snackbarWarning));
setBackgroundColor(ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.snackbarBase), ThemesRepo.getColor(R.attr.snackbarWarning), 0.15f));
break;
case LOADING:
progressBar.setIndeterminateTintList(ColorStateList.valueOf(ThemesRepo.getColor(R.attr.snackbarInfo)));
title.setTextColor(ThemesRepo.getColor(R.attr.snackbarInfo));
setBackgroundColor(ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.snackbarBase), ThemesRepo.getColor(R.attr.snackbarInfo), 0.15f));
break;
case INFO:
icon.setImageResource(R.drawable.info_outline_28);
icon.setImageTintList(ColorStateList.valueOf(ThemesRepo.getColor(R.attr.snackbarInfo)));
title.setTextColor(ThemesRepo.getColor(R.attr.snackbarInfo));
setBackgroundColor(ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.snackbarBase), ThemesRepo.getColor(R.attr.snackbarInfo), 0.15f));
break;
case ERROR:
icon.setImageResource(R.drawable.error_outline_28);
icon.setImageTintList(ColorStateList.valueOf(ThemesRepo.getColor(R.attr.snackbarError)));
title.setTextColor(ThemesRepo.getColor(R.attr.snackbarError));
setBackgroundColor(ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.snackbarBase), ThemesRepo.getColor(R.attr.snackbarError), 0.15f));
break;
}
return this;
}
}
public static class Snackbar {
public CharSequence title;
public Type type;
public int lifetime = 2500;
public String tag;
public Snackbar(Type type, CharSequence title) {
this.type = type;
this.title = title;
if (type == Type.WARNING || type == Type.ERROR) {
lifetime = 5000;
}
}
public Snackbar tag(String tag) {
this.lifetime = 0;
this.tag = tag;
return this;
}
}
public enum Type {
DONE, WARNING, INFO, ERROR,
LOADING // Must use tag
}
}