mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-02 16:49:02 +00:00
New snackbars
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -817,6 +817,24 @@ extern "C" {
|
||||
orientation::orient(obj);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1is_1big_1object(JNIEnv* env, jclass, jlong ptr, jint i) {
|
||||
ModelRef* model = (ModelRef*) (intptr_t) ptr;
|
||||
ModelObject* obj = model->model.objects[i];
|
||||
return obj->volumes.size() == 1 && obj->volumes.front()->mesh().its.indices.size() >= 100000;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1get_1extruder(JNIEnv* env, jclass, jlong ptr, jint i) {
|
||||
ModelRef* model = (ModelRef*) (intptr_t) ptr;
|
||||
ModelObject* obj = model->model.objects[i];
|
||||
return obj->config.has("extruder") ? obj->config.opt_int("extruder") : -1;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1set_1extruder(JNIEnv* env, jclass, jlong ptr, jint i, jint extruder) {
|
||||
ModelRef* model = (ModelRef*) (intptr_t) ptr;
|
||||
ModelObject* obj = model->model.objects[i];
|
||||
obj->config.set("extruder", extruder);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1slice(JNIEnv* env, jclass, jlong ptr, jstring configPath, jstring path, jobject listener) {
|
||||
try {
|
||||
ModelRef* model = (ModelRef*) (intptr_t) ptr;
|
||||
@@ -1453,6 +1471,7 @@ extern "C" {
|
||||
|
||||
ref->data = libvgcode_convert_input_data(resultRef->result, resultRef->result.extruder_colors, resultRef->result.extruder_colors, ref->viewer);
|
||||
ref->viewer.load(std::move(ref->data));
|
||||
ref->viewer.set_time_mode(libvgcode::ETimeMode::Normal);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_vgcode_1reset(JNIEnv* env, jclass, jlong ptr) {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28dp"
|
||||
android:height="28dp"
|
||||
android:viewportWidth="28"
|
||||
android:viewportHeight="28">
|
||||
<path
|
||||
android:pathData="M11,18.586L5.707,13.293C5.317,12.902 4.683,12.902 4.293,13.293C3.902,13.683 3.902,14.317 4.293,14.707L10.293,20.707C10.683,21.098 11.317,21.098 11.707,20.707L23.707,8.707C24.098,8.317 24.098,7.683 23.707,7.293C23.317,6.902 22.683,6.902 22.293,7.293L11,18.586Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#000"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28dp"
|
||||
android:height="28dp"
|
||||
android:viewportWidth="28"
|
||||
android:viewportHeight="28">
|
||||
<path
|
||||
android:pathData="M3,14C3,7.928 7.928,3 14,3C20.072,3 25,7.928 25,14C25,20.072 20.072,25 14,25C7.928,25 3,20.072 3,14ZM14,4.8C8.922,4.8 4.8,8.922 4.8,14C4.8,19.078 8.922,23.2 14,23.2C19.078,23.2 23.2,19.078 23.2,14C23.2,8.922 19.078,4.8 14,4.8ZM13,14.5L13,9.5C13,8.948 13.448,8.5 14,8.5C14.552,8.5 15,8.948 15,9.5L15,14.5C15,15.052 14.552,15.5 14,15.5C13.448,15.5 13,15.052 13,14.5ZM12.75,18.25C12.75,17.56 13.31,17 14,17L14,17C14.69,17 15.25,17.56 15.25,18.25C15.25,18.94 14.69,19.5 14,19.5L14,19.5C13.31,19.5 12.75,18.94 12.75,18.25Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#000"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28dp"
|
||||
android:height="28dp"
|
||||
android:viewportWidth="28"
|
||||
android:viewportHeight="28">
|
||||
<path
|
||||
android:pathData="M10.702,7.212C11.523,5.79 11.934,5.079 12.401,4.739C13.354,4.047 14.646,4.047 15.599,4.739C16.066,5.079 16.477,5.79 17.298,7.212L23.693,18.288C24.513,19.71 24.924,20.421 24.984,20.996C25.108,22.168 24.462,23.286 23.385,23.765C22.857,24 22.037,24 20.395,24H7.605C5.964,24 5.143,24 4.614,23.765C3.538,23.286 2.893,22.168 3.016,20.996C3.076,20.421 3.487,19.71 4.307,18.288L10.702,7.212Z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000"/>
|
||||
<path
|
||||
android:pathData="M14,9.5C13.448,9.5 13,9.948 13,10.5L13,15.5C13,16.052 13.448,16.5 14,16.5C14.552,16.5 15,16.052 15,15.5V10.5C15,9.948 14.552,9.5 14,9.5ZM14,18.3C13.337,18.3 12.8,18.837 12.8,19.5C12.8,20.163 13.337,20.7 14,20.7C14.663,20.7 15.2,20.163 15.2,19.5C15.2,18.837 14.663,18.3 14,18.3Z"
|
||||
android:fillColor="#000"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -10,8 +10,11 @@
|
||||
<string name="SlotAppSettingsTooltip">Настройки приложения</string>
|
||||
<string name="MenuFile">Файл</string>
|
||||
<string name="MenuFileOpen">Открыть модель</string>
|
||||
<string name="MenuFileOpenFileLoaded">Файл загружен.</string>
|
||||
<string name="MenuFileOpenFileFailed">Не удалось открыть модель</string>
|
||||
<string name="MenuFileOpenFileFailedNullName">Не удалось определить имя файла.</string>
|
||||
<string name="MenuFileOpenFileBigObject">Файл содержит более 100к треугольников. Нарезка может быть очень медленной.</string>
|
||||
<string name="MenuFileOpenFileLoading">Загрузка файла…</string>
|
||||
<string name="MenuFileDelete">Убрать модель</string>
|
||||
<string name="MenuFileCalibrations">Калибров.</string>
|
||||
<string name="MenuFileCalibrationsLA">K3D Linear Advance</string>
|
||||
@@ -28,7 +31,6 @@
|
||||
<string name="MenuFileCalibrationsModelsCylinder">Цилиндр</string>
|
||||
<string name="MenuFileCalibrationsModelsPyramid">Пирамида</string>
|
||||
<string name="MenuFileCalibrationsModelsSphere">Сфера</string>
|
||||
<string name="MenuFileOpenFileLoaded">Файл загружен.</string>
|
||||
<string name="MenuFileImportProfiles">Импорт. профилей</string>
|
||||
<string name="MenuFileImportProfilesFailed">Не удалось импортировать</string>
|
||||
<string name="MenuFileImportProfilesFailedNotIni">Не файл .ini</string>
|
||||
|
||||
@@ -34,4 +34,9 @@
|
||||
<attr name="yTrackColor" format="reference|color"/>
|
||||
<attr name="zTrackColor" format="reference|color"/>
|
||||
<attr name="textColorNegative" format="reference|color"/>
|
||||
<attr name="snackbarBase" format="reference|color"/>
|
||||
<attr name="snackbarDone" format="reference|color"/>
|
||||
<attr name="snackbarWarning" format="reference|color"/>
|
||||
<attr name="snackbarInfo" format="reference|color"/>
|
||||
<attr name="snackbarError" format="reference|color"/>
|
||||
</resources>
|
||||
@@ -14,6 +14,8 @@
|
||||
<string name="MenuFileOpenFileLoaded">File loaded.</string>
|
||||
<string name="MenuFileOpenFileFailed">Failed to open model</string>
|
||||
<string name="MenuFileOpenFileFailedNullName">Failed to resolve file name.</string>
|
||||
<string name="MenuFileOpenFileBigObject">File has more than 100k triangles. Processing could be really slow.</string>
|
||||
<string name="MenuFileOpenFileLoading">Loading file…</string>
|
||||
<string name="MenuFileDelete">Remove model</string>
|
||||
<string name="MenuFileCalibrations">Calibrat.</string>
|
||||
<string name="MenuFileCalibrationsLA">K3D Linear Advance</string>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.SliceBeam" parent="Theme.Material3.Light.NoActionBar">
|
||||
<item name="android:windowBackground">#FFF</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon" tools:targetApi="s">@drawable/icon_adaptive_foreground</item>
|
||||
|
||||
Reference in New Issue
Block a user