From 0dbe47ad3be47155e8e48bc7220548fa791116b5 Mon Sep 17 00:00:00 2001 From: lucasroyerdev Date: Sat, 31 Jan 2026 16:09:37 +0100 Subject: [PATCH] feat: manage color change and upgrade save_data method with List instead of map --- app/build.gradle | 4 +- app/src/main/assets/editor.html | 51 +++++++---- .../main/java/com/stock/pignon/Category.java | 4 + .../java/com/stock/pignon/ControlServer.java | 91 +++++++++++++------ .../java/com/stock/pignon/DataLoader.java | 37 ++++---- 5 files changed, 119 insertions(+), 68 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index eb53af2..02d9541 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.stock.pignon" minSdkVersion 17 targetSdkVersion 36 - versionCode 7 - versionName "0.5.2" + versionCode 8 + versionName "0.6.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/assets/editor.html b/app/src/main/assets/editor.html index 9350d42..45e1a6d 100644 --- a/app/src/main/assets/editor.html +++ b/app/src/main/assets/editor.html @@ -155,7 +155,7 @@ background: transparent !important; color: #555 !important; width: auto; - max-width: 70%; + max-width: 20%; border-bottom: 1px dashed #ccc !important; outline: none; } @@ -175,10 +175,10 @@
- +
@@ -187,24 +187,32 @@ var t = document.getElementById('table-' + cat); var r = t.insertRow(-1); var id = Date.now(); - r.innerHTML = '' + - '' + - '' + + + r.innerHTML = '' + + '' + + '' + + '' + + '' + '' + '' + '' + ''; } - function uImg(el) { - var f = el.files[0]; + function uImg(element) { + var f = element.files[0]; if (!f) return; - var row = el.parentNode.parentNode; - var id = f.name.split('.').slice(0, -1).join('.'); - row.querySelector('input[type="hidden"]').value = id; - var fd = new FormData(); - fd.append('images', f); - fetch('/upload_images', { method: 'POST', body: fd }).then(function () { alert('Image envoyée : ' + id); }); + + var td = element.parentNode; + var imgTag = td.querySelector('.img-p'); + var hiddenInput = td.querySelector('input[type="hidden"]'); + + var reader = new FileReader(); + reader.onload = function(e) { + imgTag.src = e.target.result; + hiddenInput.value = e.target.result; + }; + reader.readAsDataURL(f); } function handleCancel(e) { @@ -229,6 +237,12 @@ container.innerHTML = '

' + '' + + '
' + + 'Fond:
' + + '
' + + '
' + + 'Texte:
' + + '
' + ' ' + '

' + '' + @@ -253,12 +267,17 @@ // Browse showed categories const catOrder = []; document.querySelectorAll('.card').forEach((card, catIdx) => { - const catInput = card.querySelector('input[name^="cat|"]'); + let techId = card.querySelector('input[name^="cat|"]')?.name.split('|')[1] || "c" + catIdx; // c0, c1 but avoid globals + catOrder.push(techId); + + const catInput = card.querySelector('input[name$="|name"]'); + const bgInput = card.querySelector('input[name$="|bgColor"]'); + const textInput = card.querySelector('input[name$="|textColor"]'); if (!catInput) return; - const techId = "c" + catIdx; // c0, c1... - catOrder.push(techId); data.items["cat|" + techId + "|name"] = catInput.value; + data.items["cat|" + techId + "|bgColor"] = bgInput ? bgInput.value : "#0049AF"; + data.items["cat|" + techId + "|textColor"] = textInput ? textInput.value : "#FFFFFF"; // Browse each line card.querySelectorAll('table tr').forEach((row, itemIdx) => { diff --git a/app/src/main/java/com/stock/pignon/Category.java b/app/src/main/java/com/stock/pignon/Category.java index 07f9360..7dc6979 100644 --- a/app/src/main/java/com/stock/pignon/Category.java +++ b/app/src/main/java/com/stock/pignon/Category.java @@ -31,4 +31,8 @@ public class Category { public String getBgColor() { return bgColor; } public String getTextColor() { return textColor; } public List getItems() { return items != null ? items : new ArrayList<>(); } + + // Setters + public void setBgColor(String bgColor) { this.bgColor = bgColor; } + public void setTextColor(String textColor) { this.textColor = textColor; } } \ No newline at end of file diff --git a/app/src/main/java/com/stock/pignon/ControlServer.java b/app/src/main/java/com/stock/pignon/ControlServer.java index d2bca87..113a00f 100644 --- a/app/src/main/java/com/stock/pignon/ControlServer.java +++ b/app/src/main/java/com/stock/pignon/ControlServer.java @@ -13,15 +13,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.ByteArrayOutputStream; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Scanner; -import java.util.Iterator; /** * Create a web server to remote management of app assets. @@ -110,26 +107,31 @@ public class ControlServer extends NanoHTTPD { * Read from asset and return html file */ private String fillEditor() { - // Get data for assets + // Get data from assets DataLoader.loadData(); // Create an html string to fill the template StringBuilder html = new StringBuilder(); // Save categories order List orderList = new ArrayList<>(); + + // Globals + String globalId = "global"; + Category globalCat = new Category("global", DataLoader.getGlobalItems()); + html.append(renderCategorySection(globalId, globalCat)); + orderList.add(globalId); + + // Browser categories int index = 0; + for (Category cat : DataLoader.getCategories()) { + // cat_0, cat_1... + String techId = "cat_" + index; - // Browse map : 'id' for categories name, 'items' for items list - for (Map.Entry> section : DataLoader.getAllSections().entrySet()) { - String technicalId = "cat_" + index; - String displayName = section.getKey(); - List items = section.getValue(); + html.append(renderCategorySection(techId, cat)); + orderList.add(techId); - orderList.add(technicalId); - - // For each category, render a HTML card - html.append(renderCategorySection(technicalId, displayName, items)); index++; } + String orderField = ""; @@ -139,7 +141,9 @@ public class ControlServer extends NanoHTTPD { /** * Generate HTML section for each category */ - private String renderCategorySection(String techId, String displayName, List items) { + private String renderCategorySection(String techId, Category cat) { + String displayName = cat.getName(); + List items = cat.getItems(); StringBuilder sb = new StringBuilder(); sb.append("
"); @@ -147,19 +151,28 @@ public class ControlServer extends NanoHTTPD { if ("global".equals(displayName)) { sb.append("Articles globaux"); - // Hidden input to mark cat for server - sb.append(""); + sb.append(""); techId = "global"; } else { - // Copy H2 theme - sb.append(""); + // Nom + sb.append(""); - // Delete category button + // Couleur de Fond (on utilise cat.getBgColor()) + sb.append("
"); + sb.append("
Fond
"); + sb.append(""); + sb.append("
"); + + // Couleur de Texte (on utilise cat.getTextColor()) + sb.append("
"); + sb.append("
Texte
"); + sb.append(""); + sb.append("
"); + + // Bouton supprimer sb.append(" "); + .append("onclick=\"if(confirm('Supprimer cette catégorie?')) this.closest('.card').remove()\">×"); } - sb.append(""); // Build table @@ -236,18 +249,15 @@ public class ControlServer extends NanoHTTPD { // Get categories order String[] orderedIds = fullJson.getString("cat_order_list").split(","); - // LinkedHashMap to keep order - Map> finalData = new LinkedHashMap<>(); + List finalData = new ArrayList<>(); // For each category for (String techId : orderedIds) { - // Create awaited label String catNameKey = "cat|" + techId + "|name"; // Does it exist if (!allFields.has(catNameKey)) continue; - - // Get data - String realCatName = allFields.getString(catNameKey); + + String name = allFields.getString(catNameKey); List itemsInCategory = new ArrayList<>(); // Browse and create items @@ -257,17 +267,38 @@ public class ControlServer extends NanoHTTPD { // On vérifie si l'item suivant existe (via son champ name) if (!allFields.has(itemBase + "name")) break; + // Manage image + String imgVal = allFields.optString(itemBase + "img", ""); + if (imgVal.startsWith("data:image")) { + try { + String newImgName = "img_" + System.currentTimeMillis() + "_" + i; + String base64Data = imgVal.split(",")[1]; + byte[] decoded = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT); + + File imageFile = new File(imagesDir, newImgName + ".jpg"); + try (FileOutputStream fos = new FileOutputStream(imageFile)) { + fos.write(decoded); + } + imgVal = newImgName; // Replace base64 with name of created jpg file + } catch (Exception e) { Log.e("ControlServer", "Img Error", e); } + } + itemsInCategory.add(new Item( // Mandatory allFields.getString(itemBase + "name"), // Not mandatory - allFields.optString(itemBase + "img", ""), + imgVal, parseSafely(allFields.optString(itemBase + "min", "0")), parseSafely(allFields.optString(itemBase + "max", "0")) )); i++; } - finalData.put(realCatName, itemsInCategory); + + // Create category with items and colors + Category cat = new Category(name, itemsInCategory); + cat.setBgColor(allFields.optString("cat|" + techId + "|bgColor", "#0049AF")); + cat.setTextColor(allFields.optString("cat|" + techId + "|textColor", "#FFFFFF")); + finalData.add(cat); } DataLoader.saveData(finalData); diff --git a/app/src/main/java/com/stock/pignon/DataLoader.java b/app/src/main/java/com/stock/pignon/DataLoader.java index 717f796..73bd6c5 100644 --- a/app/src/main/java/com/stock/pignon/DataLoader.java +++ b/app/src/main/java/com/stock/pignon/DataLoader.java @@ -102,6 +102,9 @@ public class DataLoader { public static List getCategories() { return cachedCategories; } + public static List getGlobalItems() { + return cachedGlobals; + } /** * Internal class for GSON @@ -114,36 +117,30 @@ public class DataLoader { /** * Write JSON from online editor data */ - public static void saveData(Map> sections) throws Exception { - File dir = new File(Environment.getExternalStorageDirectory(), EXTERNAL_DIR); - File jsonFile = new File(dir, PIECES_FILE); - - // To respect original format, we use the same format as GSON - List globalList = sections.get("global"); - if (globalList == null) { - globalList = new ArrayList<>(); - } - + public static void saveData(List categoriesList) throws Exception { CategoriesWrapper wrapper = new CategoriesWrapper(); - wrapper.globalItems = globalList; wrapper.categories = new ArrayList<>(); + wrapper.globalItems = new ArrayList<>(); - // Fill each category - for (Map.Entry> entry : sections.entrySet()) { - if (!"global".equals(entry.getKey())) { - wrapper.categories.add(new Category(entry.getKey(), entry.getValue())); + // Browse category + for (Category cat : categoriesList) { + if ("global".equals(cat.getName())) { + wrapper.globalItems = cat.getItems(); + } else { + wrapper.categories.add(cat); } } - // Convert to pretty JSON, human readable + // Create JSON Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); String jsonString = gson.toJson(wrapper); - // Write to disk - try (FileOutputStream fos = new FileOutputStream(jsonFile); - OutputStreamWriter writer = new OutputStreamWriter(fos, "UTF-8")) { + File dir = new File(Environment.getExternalStorageDirectory(), Config.EXTERNAL_DIR_NAME); + File jsonFile = new File(dir, Config.INPUT_JSON_NAME); + + // Write JSON + try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(jsonFile), "UTF-8")) { writer.write(jsonString); - writer.flush(); } // Update app cache