From df09f8ef3939683cb8e3f569921e4e21652592e6 Mon Sep 17 00:00:00 2001 From: utkabobr Date: Wed, 2 Apr 2025 14:14:35 +0300 Subject: [PATCH] Convert variables in converted profiles. Small snackbar changes --- .../ru/ytkab0bp/slicebeam/MainActivity.java | 480 ++++++++++-------- .../slicebeam/components/UnfoldMenu.java | 5 +- .../components/bed_menu/CameraMenu.java | 4 +- .../components/bed_menu/SliceMenu.java | 12 +- .../ru/ytkab0bp/slicebeam/utils/IOUtils.java | 133 ++++- .../ru/ytkab0bp/slicebeam/utils/Prefs.java | 4 + .../slicebeam/view/SnackbarsLayout.java | 2 +- .../drawable/rectangle_hand_point_up_28.xml | 13 + app/src/main/res/values-ru/strings.xml | 8 +- app/src/main/res/values/strings.xml | 6 +- 10 files changed, 435 insertions(+), 232 deletions(-) create mode 100644 app/src/main/res/drawable/rectangle_hand_point_up_28.xml diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/MainActivity.java b/app/src/main/java/ru/ytkab0bp/slicebeam/MainActivity.java index 0ee0f3a..58a4d7b 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/MainActivity.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/MainActivity.java @@ -249,25 +249,14 @@ public class MainActivity extends AppCompatActivity { OutputStream out = getContentResolver().openOutputStream(data.getData()); out.write(w.serialize().getBytes(StandardCharsets.UTF_8)); out.close(); + + SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuFileExportProfilesSuccess)); } catch (IOException e) { throw new RuntimeException(e); } } else if (requestCode == MainActivity.REQUEST_CODE_IMPORT_PROFILES) { Uri uri = data.getData(); - ContentResolver resolver = getContentResolver(); - - String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; - Cursor metaCursor = resolver.query(uri, projection, null, null, null); - String fileName = null; - if (metaCursor != null) { - try { - if (metaCursor.moveToFirst()) { - fileName = metaCursor.getString(0); - } - } finally { - metaCursor.close(); - } - } + String fileName = IOUtils.getDisplayName(uri); if (fileName == null) { new BeamAlertDialogBuilder(this) @@ -279,136 +268,7 @@ public class MainActivity extends AppCompatActivity { } if (fileName.endsWith(".orca_printer")) { - Toast.makeText(MainActivity.this, R.string.OrcaConversionPleaseWait, Toast.LENGTH_SHORT).show(); - - File f = new File(SliceBeam.getModelCacheDir(), "orca_conv.zip"); - new Thread(()->{ - try { - InputStream in = resolver.openInputStream(uri); - FileOutputStream fos = new FileOutputStream(f); - byte[] buffer = new byte[10240]; int c; - while ((c = in.read(buffer)) != -1) { - fos.write(buffer, 0, c); - } - fos.close(); - in.close(); - - ZipFile zf = new ZipFile(f); - JSONObject bundle = new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry("bundle_structure.json")))); - if (!bundle.get("bundle_type").equals("printer config bundle")) { - zf.close(); - - ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this) - .setTitle(R.string.MenuFileImportProfilesFailed) - .setMessage(R.string.OrcaConversionNotAConfigBundle) - .setPositiveButton(android.R.string.ok, null) - .show()); - - return; - } - - Slic3rConfigWrapper w = new Slic3rConfigWrapper(); - if (bundle.has("process_config")) { - JSONArray arr = bundle.getJSONArray("process_config"); - List names = new ArrayList<>(); - List stripped = new ArrayList<>(); - for (int i = 0; i < arr.length(); i++) { - String v = arr.getString(i); - names.add(v); - stripped.add(v.substring(v.indexOf('/') + 1, v.length() - 5)); - } - - for (String name : names) { - w.printConfigs.add(IOUtils.configJsonToIni(new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry(name)))), "process", Slic3rConfigWrapper.PRINT_CONFIG_KEYS, stripped)); - } - for (ConfigObject obj : w.printConfigs) { - String inherit = obj.get("inherits"); - while (inherit != null) { - ConfigObject _obj = w.findPrint(inherit); - if (_obj == null) throw new IOUtils.MissingProfileException(inherit); - - obj.values.remove("inherits"); - HashMap newMap = new HashMap<>(); - newMap.putAll(_obj.values); - newMap.putAll(obj.values); - obj.values = newMap; - - inherit = obj.values.get("inherits"); - } - } - } - if (bundle.has("filament_config")) { - JSONArray arr = bundle.getJSONArray("filament_config"); - List names = new ArrayList<>(); - List stripped = new ArrayList<>(); - for (int i = 0; i < arr.length(); i++) { - String v = arr.getString(i); - names.add(v); - stripped.add(v.substring(v.indexOf('/') + 1, v.length() - 5)); - } - - for (String name : names) { - w.filamentConfigs.add(IOUtils.configJsonToIni(new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry(name)))), "filament", Slic3rConfigWrapper.FILAMENT_CONFIG_KEYS, stripped)); - } - for (ConfigObject obj : w.filamentConfigs) { - String inherit = obj.get("inherits"); - while (inherit != null) { - ConfigObject _obj = w.findFilament(inherit); - if (_obj == null) throw new IOUtils.MissingProfileException(inherit); - - obj.values.remove("inherits"); - HashMap newMap = new HashMap<>(); - newMap.putAll(_obj.values); - newMap.putAll(obj.values); - obj.values = newMap; - - inherit = obj.values.get("inherits"); - } - } - } - if (bundle.has("printer_config")) { - JSONArray arr = bundle.getJSONArray("printer_config"); - List names = new ArrayList<>(); - List stripped = new ArrayList<>(); - for (int i = 0; i < arr.length(); i++) { - String v = arr.getString(i); - names.add(v); - stripped.add(v.substring(v.indexOf('/') + 1)); - } - - for (String name : names) { - w.printerConfigs.add(IOUtils.configJsonToIni(new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry(name)))), "machine", Slic3rConfigWrapper.PRINTER_CONFIG_KEYS, stripped)); - } - for (ConfigObject obj : w.printerConfigs) { - String inherit = obj.get("inherits"); - while (inherit != null) { - ConfigObject _obj = w.findPrinter(inherit); - if (_obj == null) throw new IOUtils.MissingProfileException(inherit); - - obj.values.remove("inherits"); - HashMap newMap = new HashMap<>(); - newMap.putAll(_obj.values); - newMap.putAll(obj.values); - obj.values = newMap; - - inherit = obj.values.get("inherits"); - } - } - } - - zf.close(); - - loadIniForImport(new ByteArrayInputStream(w.serialize().getBytes(StandardCharsets.UTF_8))); - } catch (Exception e) { - ViewUtils.postOnMainThread(() -> { - new BeamAlertDialogBuilder(this) - .setTitle(R.string.MenuFileImportProfilesFailed) - .setMessage(e.toString()) - .setPositiveButton(android.R.string.ok, null) - .show(); - }); - } - }).start(); + loadConvertedProfile(uri); return; } @@ -421,6 +281,164 @@ public class MainActivity extends AppCompatActivity { return; } + try { + loadIniForImport(getContentResolver().openInputStream(uri)); + } catch (FileNotFoundException e) { + new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileImportProfilesFailed) + .setMessage(e.toString()) + .setPositiveButton(android.R.string.ok, null) + .show(); + } + } + } + } + + private void loadConvertedProfile(Uri uri) { + String tag = UUID.randomUUID().toString(); + SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.OrcaConversionPleaseWait).tag(tag)); + File f = new File(SliceBeam.getModelCacheDir(), "orca_conv.zip"); + IOUtils.IO_POOL.submit(()->{ + try { + InputStream in = getContentResolver().openInputStream(uri); + FileOutputStream fos = new FileOutputStream(f); + byte[] buffer = new byte[10240]; + int c; + while ((c = in.read(buffer)) != -1) { + fos.write(buffer, 0, c); + } + fos.close(); + in.close(); + + ZipFile zf = new ZipFile(f); + JSONObject bundle = new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry("bundle_structure.json")))); + if (!bundle.get("bundle_type").equals("printer config bundle")) { + zf.close(); + + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); + ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileImportProfilesFailed) + .setMessage(R.string.OrcaConversionNotAConfigBundle) + .setPositiveButton(android.R.string.ok, null) + .show()); + + return; + } + + Slic3rConfigWrapper w = new Slic3rConfigWrapper(); + if (bundle.has("process_config")) { + JSONArray arr = bundle.getJSONArray("process_config"); + List names = new ArrayList<>(); + List stripped = new ArrayList<>(); + for (int i = 0; i < arr.length(); i++) { + String v = arr.getString(i); + names.add(v); + stripped.add(v.substring(v.indexOf('/') + 1, v.length() - 5)); + } + + for (String name : names) { + w.printConfigs.add(IOUtils.configJsonToIni(new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry(name)))), "process", Slic3rConfigWrapper.PRINT_CONFIG_KEYS, stripped)); + } + for (ConfigObject obj : w.printConfigs) { + String inherit = obj.get("inherits"); + while (inherit != null) { + ConfigObject _obj = w.findPrint(inherit); + if (_obj == null) throw new IOUtils.MissingProfileException(inherit); + + obj.values.remove("inherits"); + HashMap newMap = new HashMap<>(); + newMap.putAll(_obj.values); + newMap.putAll(obj.values); + obj.values = newMap; + + inherit = obj.values.get("inherits"); + } + } + } + if (bundle.has("filament_config")) { + JSONArray arr = bundle.getJSONArray("filament_config"); + List names = new ArrayList<>(); + List stripped = new ArrayList<>(); + for (int i = 0; i < arr.length(); i++) { + String v = arr.getString(i); + names.add(v); + stripped.add(v.substring(v.indexOf('/') + 1, v.length() - 5)); + } + + for (String name : names) { + w.filamentConfigs.add(IOUtils.configJsonToIni(new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry(name)))), "filament", Slic3rConfigWrapper.FILAMENT_CONFIG_KEYS, stripped)); + } + for (ConfigObject obj : w.filamentConfigs) { + String inherit = obj.get("inherits"); + while (inherit != null) { + ConfigObject _obj = w.findFilament(inherit); + if (_obj == null) throw new IOUtils.MissingProfileException(inherit); + + obj.values.remove("inherits"); + HashMap newMap = new HashMap<>(); + newMap.putAll(_obj.values); + newMap.putAll(obj.values); + obj.values = newMap; + + inherit = obj.values.get("inherits"); + } + } + } + if (bundle.has("printer_config")) { + JSONArray arr = bundle.getJSONArray("printer_config"); + List names = new ArrayList<>(); + List stripped = new ArrayList<>(); + for (int i = 0; i < arr.length(); i++) { + String v = arr.getString(i); + names.add(v); + stripped.add(v.substring(v.indexOf('/') + 1)); + } + + for (String name : names) { + w.printerConfigs.add(IOUtils.configJsonToIni(new JSONObject(IOUtils.readString(zf.getInputStream(zf.getEntry(name)))), "machine", Slic3rConfigWrapper.PRINTER_CONFIG_KEYS, stripped)); + } + for (ConfigObject obj : w.printerConfigs) { + String inherit = obj.get("inherits"); + while (inherit != null) { + ConfigObject _obj = w.findPrinter(inherit); + if (_obj == null) throw new IOUtils.MissingProfileException(inherit); + + obj.values.remove("inherits"); + HashMap newMap = new HashMap<>(); + newMap.putAll(_obj.values); + newMap.putAll(obj.values); + obj.values = newMap; + + inherit = obj.values.get("inherits"); + } + } + } + + zf.close(); + + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); + loadIniForImport(new ByteArrayInputStream(w.serialize().getBytes(StandardCharsets.UTF_8))); + } catch (IOUtils.MissingProfileException ep) { + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); + ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileImportProfilesFailed) + .setMessage(getString(R.string.MenuFileImportProfilesFailedBaseProfileNotFound, ep.profile)) + .setPositiveButton(android.R.string.ok, null) + .show()); + } catch (Exception e) { + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); + ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileImportProfilesFailed) + .setMessage(e.toString()) + .setPositiveButton(android.R.string.ok, null) + .show()); + } + }); + } + .show(); + return; + } + try { loadIniForImport(resolver.openInputStream(uri)); } catch (FileNotFoundException e) { @@ -435,7 +453,7 @@ public class MainActivity extends AppCompatActivity { } private void loadIniForImport(InputStream in) { - new Thread(()->{ + IOUtils.IO_POOL.submit(()->{ try { Slic3rConfigWrapper w = new Slic3rConfigWrapper(in); @@ -461,39 +479,68 @@ public class MainActivity extends AppCompatActivity { enabledPrinters[i] = true; } - new BeamAlertDialogBuilder(this) - .setTitle(R.string.MenuFileExportProfilesPrints) - .setMultiChoiceItems(prints, enabledPrints, (dialog, which, isChecked) -> enabledPrints[which] = isChecked) - .setPositiveButton(android.R.string.ok, (d1, w1) -> new BeamAlertDialogBuilder(this) - .setTitle(R.string.MenuFileExportProfilesFilaments) - .setMultiChoiceItems(filaments, enabledFilaments, (dialog, which, isChecked) -> enabledFilaments[which] = isChecked) - .setPositiveButton(android.R.string.ok, (d2, w2) -> new BeamAlertDialogBuilder(this) - .setTitle(R.string.MenuFileExportProfilesPrinters) - .setMultiChoiceItems(printers, enabledPrinters, (dialog, which, isChecked) -> enabledPrinters[which] = isChecked) - .setPositiveButton(android.R.string.ok, (d3, w3) -> { - for (int i = 0; i < enabledPrints.length; i++) { - if (enabledPrints[i]) { - SliceBeam.CONFIG.importPrint(w.printConfigs.get(i)); - } - } - for (int i = 0; i < enabledFilaments.length; i++) { - if (enabledFilaments[i]) { - SliceBeam.CONFIG.importFilament(w.filamentConfigs.get(i)); - } - } - for (int i = 0; i < enabledPrinters.length; i++) { - if (enabledPrinters[i]) { - SliceBeam.CONFIG.importPrinter(w.printerConfigs.get(i)); - } - } - SliceBeam.saveConfig(); - }) - .setNegativeButton(android.R.string.cancel, null) - .show()) - .setNegativeButton(android.R.string.cancel, null) - .show()) - .setNegativeButton(android.R.string.cancel, null) - .show(); + if (prints.length == 0 && filaments.length == 0 && printers.length == 0) { + ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileImportProfilesFailed) + .setMessage(R.string.MenuFileImportProfilesFailedEmpty) + .setPositiveButton(android.R.string.ok, null) + .show()); + return; + } + + Runnable finish = () -> { + for (int i = 0; i < enabledPrints.length; i++) { + if (enabledPrints[i]) { + SliceBeam.CONFIG.importPrint(w.printConfigs.get(i)); + } + } + for (int i = 0; i < enabledFilaments.length; i++) { + if (enabledFilaments[i]) { + SliceBeam.CONFIG.importFilament(w.filamentConfigs.get(i)); + } + } + for (int i = 0; i < enabledPrinters.length; i++) { + if (enabledPrinters[i]) { + SliceBeam.CONFIG.importPrinter(w.printerConfigs.get(i)); + } + } + SliceBeam.saveConfig(); + }; + Runnable printersRun = () -> { + if (printers.length == 0) { + finish.run(); + return; + } + + new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileExportProfilesPrinters) + .setMultiChoiceItems(printers, enabledPrinters, (dialog, which, isChecked) -> enabledPrinters[which] = isChecked) + .setPositiveButton(android.R.string.ok, (d3, w3) -> finish.run()) + .setNegativeButton(android.R.string.cancel, null) + .show(); + }; + Runnable filamentsRun = () -> { + if (filaments.length == 0) { + printersRun.run(); + return; + } + new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileExportProfilesFilaments) + .setMultiChoiceItems(filaments, enabledFilaments, (dialog, which, isChecked) -> enabledFilaments[which] = isChecked) + .setPositiveButton(android.R.string.ok, (d2, w2) -> printersRun.run()) + .setNegativeButton(android.R.string.cancel, null) + .show(); + }; + if (prints.length == 0) { + filamentsRun.run(); + } else { + new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileExportProfilesPrints) + .setMultiChoiceItems(prints, enabledPrints, (dialog, which, isChecked) -> enabledPrints[which] = isChecked) + .setPositiveButton(android.R.string.ok, (d1, w1) -> filamentsRun.run()) + .setNegativeButton(android.R.string.cancel, null) + .show(); + } }); } catch (Exception e) { Log.e("MainActivity", "Failed to read file", e); @@ -504,7 +551,7 @@ public class MainActivity extends AppCompatActivity { .setPositiveButton(android.R.string.ok, null) .show()); } - }).start(); + }); } private void loadFile(File f, boolean autoorient) { @@ -521,27 +568,36 @@ public class MainActivity extends AppCompatActivity { } 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)); + fragment.getGlView().queueEvent(new Runnable() { + @Override + public void run() { + Model model = fragment.getGlView().getRenderer().getModel(); + if (model == null || fragment.getGlView().getRenderer().getBed() == null) { + fragment.getGlView().queueEvent(this); + return; + } + + if (!gcode) { + SliceBeam.EVENT_BUS.fireEvent(new ObjectsListChangedEvent()); + } + 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(); + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(this) .setTitle(R.string.MenuFileOpenFileFailed) .setMessage(e.toString()) @@ -556,20 +612,7 @@ public class MainActivity extends AppCompatActivity { if (uri == null) return; ContentResolver resolver = getContentResolver(); - - String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; - Cursor metaCursor = resolver.query(uri, projection, null, null, null); - String fileName = null; - if (metaCursor != null) { - try { - if (metaCursor.moveToFirst()) { - fileName = metaCursor.getString(0); - } - } finally { - metaCursor.close(); - } - } - + String fileName = IOUtils.getDisplayName(uri); if (fileName == null) { new BeamAlertDialogBuilder(this) .setTitle(R.string.MenuFileOpenFileFailed) @@ -578,9 +621,26 @@ public class MainActivity extends AppCompatActivity { .show(); return; } + if (fileName.endsWith(".orca_printer")) { + loadConvertedProfile(uri); + return; + } + if (fileName.endsWith(".ini")) { + try { + loadIniForImport(resolver.openInputStream(uri)); + } catch (FileNotFoundException e) { + new BeamAlertDialogBuilder(this) + .setTitle(R.string.MenuFileImportProfilesFailed) + .setMessage(e.toString()) + .setPositiveButton(android.R.string.ok, null) + .show(); + } + return; + } + File f = new File(SliceBeam.getModelCacheDir(), fileName); // TODO: Check if file already exists - new Thread(()->{ + IOUtils.IO_POOL.submit(()->{ try { InputStream in = resolver.openInputStream(uri); FileOutputStream fos = new FileOutputStream(f); @@ -601,7 +661,7 @@ public class MainActivity extends AppCompatActivity { .setPositiveButton(android.R.string.ok, null) .show()); } - }).start(); + }); } @Override diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/components/UnfoldMenu.java b/app/src/main/java/ru/ytkab0bp/slicebeam/components/UnfoldMenu.java index 123526a..8059b99 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/components/UnfoldMenu.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/components/UnfoldMenu.java @@ -204,10 +204,13 @@ public abstract class UnfoldMenu { } fragment.getGlView().invalidate(); } - }); + }) + .addEndListener((animation, canceled, value, velocity) -> onShown()); spring.start(); } + protected void onShown() {} + public void relayout() { FrameLayout into = containerLayout; boolean portrait = into.getWidth() < into.getHeight(); diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/CameraMenu.java b/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/CameraMenu.java index e14b431..5d9573d 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/CameraMenu.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/CameraMenu.java @@ -124,10 +124,10 @@ public class CameraMenu extends ListBedMenu { animateTo(toOrigin, toPosition); }), new SpaceItem(portrait ? ViewUtils.dp(8) : 0, portrait ? 0 : ViewUtils.dp(8)), - new BedMenuItem(R.string.MenuCameraControlMode, R.drawable.hand_point_up_outline_28).onClick(v -> { + new BedMenuItem(R.string.MenuCameraControlMode, R.drawable.rectangle_hand_point_up_28).onClick(v -> { Context ctx = v.getContext(); new BeamAlertDialogBuilder(v.getContext()) - .setTitle(R.string.MenuCameraControlMode) + .setTitle(R.string.MenuCameraControlModeFull) .setSingleChoiceItems(new CharSequence[] { ctx.getString(R.string.MenuCameraControlModeOne), ctx.getString(R.string.MenuCameraControlModeTwo), diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/SliceMenu.java b/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/SliceMenu.java index aef3932..27a8fd7 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/SliceMenu.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/components/bed_menu/SliceMenu.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.UUID; import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.entity.ContentType; @@ -52,6 +53,7 @@ import ru.ytkab0bp.slicebeam.SliceBeam; import ru.ytkab0bp.slicebeam.components.BeamAlertDialogBuilder; 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.fragment.BedFragment; import ru.ytkab0bp.slicebeam.recycler.SimpleRecyclerItem; @@ -64,13 +66,14 @@ import ru.ytkab0bp.slicebeam.utils.ViewUtils; import ru.ytkab0bp.slicebeam.view.DividerView; import ru.ytkab0bp.slicebeam.view.PositionScrollView; import ru.ytkab0bp.slicebeam.view.SegmentsView; +import ru.ytkab0bp.slicebeam.view.SnackbarsLayout; public class SliceMenu extends ListBedMenu { private AsyncHttpClient client = new AsyncHttpClient(); { client.setLoggingEnabled(true); - client.setMaxRetriesAndTimeout(0, 5000); + client.setMaxRetriesAndTimeout(0, 10000); } private final static List SUPPORTED_SEND = Collections.singletonList("octoprint"); @@ -132,7 +135,8 @@ public class SliceMenu extends ListBedMenu { if (!host.startsWith("http://")) { host = "http://" + host; } - SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuSliceSendToPrinterStarted)); + String tag = UUID.randomUUID().toString(); + SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.MenuSliceSendToPrinterLoading).tag(tag)); Header[] headers = TextUtils.isEmpty(apiKey) ? new Header[0] : new Header[] {new BasicHeader("X-Api-Key", apiKey)}; RequestParams params = new RequestParams(); try { @@ -151,7 +155,8 @@ public class SliceMenu extends ListBedMenu { if (!obj.has("action") && !obj.has("files")) { throw new JSONException(obj.toString()); } - SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(print ? R.string.MenuSliceSendToPrinterPrintStarted : R.string.MenuSliceSendToPrinterOK)); + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); + SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(print ? SnackbarsLayout.Type.INFO : SnackbarsLayout.Type.DONE, print ? R.string.MenuSliceSendToPrinterPrintStarted : R.string.MenuSliceSendToPrinterOK)); } catch (JSONException e) { onFailure(statusCode, headers, responseBody, e); } @@ -159,6 +164,7 @@ public class SliceMenu extends ListBedMenu { @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + SliceBeam.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(tag)); ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(fragment.getContext()) .setTitle(R.string.MenuSliceSendToPrinterFailed) .setMessage(error.toString()) diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/utils/IOUtils.java b/app/src/main/java/ru/ytkab0bp/slicebeam/utils/IOUtils.java index efe9cda..c256a9a 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/utils/IOUtils.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/utils/IOUtils.java @@ -1,5 +1,9 @@ package ru.ytkab0bp.slicebeam.utils; +import android.content.ContentResolver; +import android.database.Cursor; +import android.net.Uri; +import android.provider.MediaStore; import android.text.TextUtils; import org.json.JSONArray; @@ -9,21 +13,39 @@ import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; 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.SliceBeam; import ru.ytkab0bp.slicebeam.config.ConfigObject; public class IOUtils { public static ExecutorService IO_POOL = Executors.newCachedThreadPool(); + public static String getDisplayName(Uri uri) { + ContentResolver resolver = SliceBeam.INSTANCE.getContentResolver(); + + String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; + Cursor metaCursor = resolver.query(uri, projection, null, null, null); + String fileName = null; + if (metaCursor != null) { + try { + if (metaCursor.moveToFirst()) { + fileName = metaCursor.getString(0); + } + } finally { + metaCursor.close(); + } + } + return fileName; + } public static String readString(InputStream in) throws IOException { return readString(in, false); } @@ -54,10 +76,13 @@ public class IOUtils { } } - private static ConfigObject downloadProfilesRecursively(String vendor, String type, String profile, List supportedKeys) throws IOException, JSONException { + private static ConfigObject downloadProfilesRecursively(String vendor, String type, String profile, List supportedKeys) throws IOException, JSONException, MissingProfileException { ConfigObject cfg = new ConfigObject(); - URLConnection con = new URL(String.format("https://raw.githubusercontent.com/SoftFever/OrcaSlicer/main/resources/profiles/%s/%s/%s.json", vendor, type, profile)).openConnection(); + HttpURLConnection con = (HttpURLConnection) new URL(String.format("https://raw.githubusercontent.com/SoftFever/OrcaSlicer/main/resources/profiles/%s/%s/%s.json", vendor, type, profile)).openConnection(); + if (con.getResponseCode() == 404) { + throw new MissingProfileException(profile); + } JSONObject obj = new JSONObject(readString(con.getInputStream())); if (!TextUtils.isEmpty(obj.optString("inherits", null))) { ConfigObject o = downloadProfilesRecursively(vendor, type, obj.getString("inherits"), supportedKeys); @@ -116,19 +141,103 @@ public class IOUtils { ConfigObject _obj = downloadProfilesRecursively(vendor, type, inherit, supportedKeys); for (Map.Entry en : _obj.values.entrySet()) { - if (supportedKeys.contains(en.getKey())) { - if (en.getKey().equals("printable_area")) { - cfg.values.put("bed_shape", en.getValue()); - } else if (en.getKey().equals("ironing_type") && en.getValue().equals("no ironing")) { + String key = en.getKey(); + switch (key) { + case "machine_start_gcode": + key = "start_gcode"; + break; + case "machine_end_gcode": + key = "end_gcode"; + break; + case "printable_area": + key = "bed_shape"; + break; + case "printable_height": + key = "max_print_height"; + break; + case "layer_change_gcode": + key = "layer_gcode"; + break; + case "before_layer_change_gcode": + key = "before_layer_gcode"; + break; + case "filament_start_gcode": + key = "start_filament_gcode"; + break; + case "filament_end_gcode": + key = "end_filament_gcode"; + break; + case "retraction_minimum_level": + key = "retract_before_travel"; + break; + case "retraction_length": + key = "retract_length"; + break; + case "retraction_speed": + key = "retract_speed"; + break; + case "deretraction_speed": + key = "deretract_speed"; + break; + case "change_filament_gcode": + key = "pause_print_gcode"; + break; + case "nozzle_temperature": + key = "temperature"; + break; + case "nozzle_temperature_initial_layer": + key = "first_layer_temperature"; + break; + case "filament_flow_ratio": + key = "extrusion_multiplier"; + break; + case "chamber_temperatures": + key = "chamber_temperature"; + break; + case "fan_max_speed": + key = "max_fan_speed"; + break; + case "fan_min_speed": + key = "min_fan_speed"; + break; + case "overhang_fan_speed": + key = "bridge_fan_speed"; + break; + case "slow_down_layer_time": + key = "slowdown_below_layer_time"; + break; + case "slow_down_min_speed": + key = "min_print_speed"; + break; + } + + if (key.equals("pressure_advance")) { + StringBuilder sb = new StringBuilder("SET_PRESSURE_ADVANCE ADVANCE=").append(en.getValue()); + if (cfg.values.containsKey("start_filament_gcode")) { + sb.append("\n").append(cfg.get("start_filament_gcode")); + } + cfg.values.put("start_filament_gcode", sb.toString()); + } + + if (supportedKeys.contains(key)) { + if (key.equals("ironing_type") && en.getValue().equals("no ironing")) { cfg.values.put("ironing", "0"); cfg.values.put("ironing_type", "top"); - } if (en.getKey().equals("start_filament_gcode") || en.getKey().equals("end_filament_gcode") || - en.getKey().equals("start_gcode") || en.getKey().equals("end_gcode")) { + } + if (key.equals("start_filament_gcode") || key.equals("end_filament_gcode") || + key.equals("start_gcode") || key.equals("end_gcode")) { - cfg.values.put(en.getKey(), en.getValue().replaceAll("(\\{|\\[)nozzle_temperature_initial_layer(\\[\\d+]|)(}|])", "$1first_layer_temperature$2$3") + String val = en.getValue(); + if (key.equals("start_filament_gcode")) { + if (cfg.values.containsKey("start_filament_gcode")) { + val = cfg.get("start_filament_gcode") + "\n" + val; + } + } + + cfg.values.put(key, val.replaceAll("(\\{|\\[)nozzle_temperature_initial_layer(\\[\\d+]|)(}|])", "$1first_layer_temperature$2$3") .replaceAll("(\\{|\\[)bed_temperature_initial_layer_single(\\[\\d+]|)(}|])", "$1first_layer_bed_temperature$2$3")); - } else if (!en.getKey().equals("thumbnails")) { - cfg.values.put(en.getKey(), en.getValue()); + } else if (!key.equals("thumbnails")) { + cfg.values.put(key, en.getValue()); } } } diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/utils/Prefs.java b/app/src/main/java/ru/ytkab0bp/slicebeam/utils/Prefs.java index 64bb7d5..7f20aeb 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/utils/Prefs.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/utils/Prefs.java @@ -9,6 +9,10 @@ import ru.ytkab0bp.slicebeam.R; import ru.ytkab0bp.slicebeam.SetupActivity; public class Prefs { + public final static int CAMERA_CONTROL_MODE_ROTATE_MOVE = 0, + CAMERA_CONTROL_MODE_MOVE_ROTATE = 1, + CAMERA_CONTROL_MODE_MOVE_ONLY = 2; + private static SharedPreferences mPrefs; public static void init(Application ctx) { diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java b/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java index a9b01be..72b6e3f 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/view/SnackbarsLayout.java @@ -215,7 +215,7 @@ public class SnackbarsLayout extends FrameLayout { } }) .addEndListener((animation, canceled, value, velocity) -> { - if (remove) { + if (remove && getParent() != null) { ((ViewGroup) getParent()).removeView(SnackbarView.this); } }) diff --git a/app/src/main/res/drawable/rectangle_hand_point_up_28.xml b/app/src/main/res/drawable/rectangle_hand_point_up_28.xml new file mode 100644 index 0000000..ecafc16 --- /dev/null +++ b/app/src/main/res/drawable/rectangle_hand_point_up_28.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6f12a99..89cbb49 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -33,12 +33,15 @@ Сфера Импорт. профилей Не удалось импортировать + Родительский профиль не найден: %s Не файл .ini + Файл не содержит профилей Экспорт. профилей Профили печати Филаменты Принтеры Не выбрано ни одного профиля. + Профили успешно экспортированы. Камера Изомет.\nвид Вид\nсверху @@ -48,7 +51,8 @@ Вид\nслева Вид\nсправа Ортог. проекц. - Режим управ. + Режим управл. + Режим управления Один палец - поворот, два пальца - перемещение Один палец - перемещение, два пальца - поворот Только перемещение @@ -99,7 +103,7 @@ Отправка Отправ. на принтер Отправ. на печать - Загрузка началась… + Отправка… Файл отправлен на принтер. Файл отправлен, начало печати… Не удалось отправить файл diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 67c78bd..9947a9e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,12 +35,15 @@ Sphere Import profiles Import failed + Parent profile not found: %s Not an .ini file + File does not contain profiles Export profiles Print configs Filaments Printers No profiles selected. + Exported profiles successfully. Camera Isom. view Top view @@ -51,6 +54,7 @@ Right view Orth. project. Control mode + Control mode One finger - rotation, two fingers - movement One finger - movement, two fingers - rotation Only movement @@ -101,7 +105,7 @@ Share Send to printer Send and print - Upload started… + Uploading… File sent to printer. File sent, starting print… Failed to send file