From d928fe78cfac198ce7f9f71288a3855467c2ae31 Mon Sep 17 00:00:00 2001 From: Astatin3 <77305074+Astatin3@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:53:23 -0600 Subject: [PATCH] Almost completely make the field editor TODO: - Add delete button - Add "revert version" button --- .../types/input/tallyType.java | 2 +- .../scoutingapp2025/types/input/textType.java | 3 +- .../ui/data/FieldEditorHelper.java | 140 ++++++-- .../ui/data/FieldsFragment.java | 327 ++++++++++++++++-- .../main/res/layout/fragment_data_fields.xml | 12 +- .../main/res/navigation/mobile_navigation.xml | 3 + 6 files changed, 427 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java index 9298fea..fec81d5 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java @@ -30,7 +30,7 @@ public class tallyType extends inputType { public dataType.valueTypes getValueType(){return dataType.valueTypes.NUM;} public Object get_fallback_value(){return 0;} public tallyType(){} - public String get_type_name(){return "Dropdown";} + public String get_type_name(){return "Tally";} public tallyType(String name, int default_value){ super(name); this.default_value = default_value; diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java index 34cc7be..7126deb 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java @@ -88,8 +88,7 @@ public class textType extends inputType { }); return text; - - }; + } public void setViewValue(Object value) { if(text == null) return; if(stringType.isNull((String) value)){ diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldEditorHelper.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldEditorHelper.java index 124c414..5ded172 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldEditorHelper.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldEditorHelper.java @@ -1,7 +1,10 @@ package com.astatin3.scoutingapp2025.ui.data; +import static android.text.InputType.TYPE_CLASS_NUMBER; + import android.content.Context; import android.view.View; +import android.widget.EditText; import android.widget.TableLayout; import android.widget.TextView; @@ -10,6 +13,8 @@ import com.astatin3.scoutingapp2025.types.input.inputType; import com.astatin3.scoutingapp2025.types.input.sliderType; import com.astatin3.scoutingapp2025.types.input.tallyType; import com.astatin3.scoutingapp2025.types.input.textType; +import com.astatin3.scoutingapp2025.utility.AlertManager; +import com.google.android.material.textfield.TextInputEditText; public class FieldEditorHelper { private enum parameterTypeEnum { @@ -26,7 +31,7 @@ public class FieldEditorHelper { public static class paramNumber extends parameterType{ public int val; public paramNumber(String name, int val){ - this.name = name; + this.name = name + " (Number)"; this.val = val; this.id = parameterTypeEnum.paramNumber; } @@ -35,7 +40,7 @@ public class FieldEditorHelper { public static class paramString extends parameterType { public String val; public paramString(String name, String val){ - this.name = name; + this.name = name + " (String)"; this.val = val; this.id = parameterTypeEnum.paramString; } @@ -44,25 +49,25 @@ public class FieldEditorHelper { public static class paramStringArray extends parameterType{ public String[] val; public paramStringArray(String name, String[] val){ - this.name = name; + this.name = name + " (String array)"; this.val = val; this.id = parameterTypeEnum.paramStringArray; } } - private static final parameterType[] defaultSliderParams = new parameterType[]{ + public static final parameterType[] defaultSliderParams = new parameterType[]{ new paramNumber("Min", 0), new paramNumber("Max", 10), new paramNumber("Default Value", 5) }; - private static final parameterType[] defaultDropdownParams = new parameterType[]{ + public static final parameterType[] defaultDropdownParams = new parameterType[]{ new paramStringArray("Default Value", new String[]{"Zero","One","Two","Three"}), new paramNumber("Default Option", 0), }; - private static final parameterType[] defaultTextParams = new parameterType[]{ + public static final parameterType[] defaultTextParams = new parameterType[]{ new paramString("Default Value", "") }; - private static final parameterType[] defaultTallyParams = new parameterType[]{ + public static final parameterType[] defaultTallyParams = new parameterType[]{ new paramNumber("Default Value", 0) }; @@ -96,6 +101,44 @@ public class FieldEditorHelper { + public static void setSliderParams(sliderType s, parameterType[] types){ + s.min = ((paramNumber) types[0]).val; + s.max = ((paramNumber) types[1]).val; + s.default_value = ((paramNumber) types[2]).val; + } + + public static void setDropdownParams(dropdownType s, parameterType[] types){ + s.text_options = ((paramStringArray) types[0]).val; + s.default_value = ((paramNumber) types[1]).val; + } + + public static void setTextParams(textType s, parameterType[] types){ + s.default_value = ((paramString) types[0]).val; + } + + public static void setTallyParams(tallyType s, parameterType[] types){ + s.default_value = ((paramNumber) types[0]).val; + } + + private static void setInputParameter(inputType t, parameterType[] types){ + switch (t.getInputType()){ + case TALLY: + setTallyParams((tallyType) t, types); + break; + case SLIDER: + setSliderParams((sliderType) t, types); + break; + case DROPDOWN: + setDropdownParams((dropdownType) t, types); + break; + case NOTES_INPUT: + setTextParams((textType) t, types); + break; + } + } + + + private static parameterType[] getParamsFromInputType(inputType t){ switch (t.getInputType()){ case TALLY: @@ -112,40 +155,74 @@ public class FieldEditorHelper { - private static View createNumberEdit(Context c){ - TextView tv = new TextView(c); - tv.setText("Number edit"); - return tv; + private static View createNumberEdit(Context c, int value){ + EditText text = new EditText(c); + text.setInputType(TYPE_CLASS_NUMBER); + text.setText(String.valueOf(value)); + return text; } - private static View createStringEdit(Context c){ - TextView tv = new TextView(c); - tv.setText("String edit"); - return tv; + private static View createStringEdit(Context c, String value){ + EditText text = new EditText(c); + text.setText(value); + return text; } - private static View createStringArrayEdit(Context c){ - TextView tv = new TextView(c); - tv.setText("String Array edit"); - return tv; + private static View createStringArrayEdit(Context c, String[] value){ + EditText text = new EditText(c); + text.setText(String.join("\n", value)); + return text; } private static View createEdit(Context c, parameterType t){ switch (t.id){ case paramNumber: - return createNumberEdit(c); + return createNumberEdit(c, ((paramNumber) t).val); case paramString: - return createStringEdit(c); + return createStringEdit(c, ((paramString) t).val); case paramStringArray: - return createStringArrayEdit(c); + return createStringArrayEdit(c, ((paramStringArray) t).val); } return null; } + + private static boolean readEdit(View v, parameterType t){ + try{ + String val; + switch (t.id) { + case paramNumber: + val = ((EditText) v).getText().toString(); + if(val.isEmpty() || val.isBlank()) return false; + ((paramNumber) t).val = Integer.parseInt(val); + break; + case paramString: + val = ((EditText) v).getText().toString(); + //if(val.isEmpty() || val.isBlank()) return false; + ((paramString) t).val = val; + break; + case paramStringArray: + val = ((EditText) v).getText().toString(); + if(val.isEmpty() || val.isBlank()) return false; + ((paramStringArray) t).val = val.split("\n"); + break; + } + } catch (Exception e) { + AlertManager.error(e); + return false; + } + + return true; + } + + private parameterType[] types; private View[] views; - public FieldEditorHelper(Context c, inputType t, TableLayout parentView){ - types = getParamsFromInputType(t); + private inputType t; + public FieldEditorHelper(Context c, inputType t, TableLayout parentView, parameterType[] tmptypes){ + this.types = tmptypes; + this.t = t; + views = new View[types.length]; for(int i = 0; i < types.length; i++){ TextView tv = new TextView(c); tv.setText(types[i].name); @@ -153,8 +230,21 @@ public class FieldEditorHelper { tv.setTextSize(20); parentView.addView(tv); - parentView.addView(createEdit(c, types[i])); + views[i] = createEdit(c, types[i]); + parentView.addView(views[i]); } } + public FieldEditorHelper(Context c, inputType t, TableLayout parentView){ + this(c,t,parentView,getParamsFromInputType(t)); + } + + public boolean save(){ + for(int i = 0; i < types.length; i++){ + if(!readEdit(views[i], types[i])) + return false; + } + setInputParameter(t, types); + return true; + } } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldsFragment.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldsFragment.java index 24b85a4..a3e8b98 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldsFragment.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/data/FieldsFragment.java @@ -1,11 +1,17 @@ package com.astatin3.scoutingapp2025.ui.data; import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.os.Bundle; +import android.text.InputType; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.FrameLayout; import android.widget.TableLayout; import android.widget.TableRow; @@ -14,11 +20,26 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.navigation.Navigation; +import com.astatin3.scoutingapp2025.R; import com.astatin3.scoutingapp2025.databinding.FragmentDataFieldsBinding; import com.astatin3.scoutingapp2025.scoutingData.fields; +import com.astatin3.scoutingapp2025.types.input.dropdownType; import com.astatin3.scoutingapp2025.types.input.inputType; +import com.astatin3.scoutingapp2025.types.input.sliderType; +import com.astatin3.scoutingapp2025.types.input.tallyType; +import com.astatin3.scoutingapp2025.types.input.textType; +import com.astatin3.scoutingapp2025.utility.AlertManager; import com.astatin3.scoutingapp2025.utility.DataManager; +import com.skydoves.powerspinner.IconSpinnerAdapter; +import com.skydoves.powerspinner.IconSpinnerItem; +import com.skydoves.powerspinner.PowerSpinnerView; +import com.skydoves.powerspinner.SpinnerGravity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; public class FieldsFragment extends Fragment { FragmentDataFieldsBinding binding; @@ -38,6 +59,7 @@ public class FieldsFragment extends Fragment { binding.saveButton.setVisibility(View.GONE); + binding.cancelEditButton.setVisibility(View.GONE); binding.editButton.setVisibility(View.GONE); binding.upButton.setVisibility(View.GONE); binding.addButton.setVisibility(View.GONE); @@ -117,36 +139,25 @@ public class FieldsFragment extends Fragment { binding.valueEditContainer.setVisibility(View.GONE); for(int i = 0; i < version_values.length; i++){ - TableRow tr = new TableRow(getContext()); - TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - FrameLayout.LayoutParams.WRAP_CONTENT - ); - - rowParams.setMargins(20,20,20,20); - tr.setLayoutParams(rowParams); - tr.setPadding(20,20,20,20); - tr.setBackgroundColor(unfocused_background_color); - - TextView tv = new TextView(getContext()); - tv.setText(version_values[i].get_type_name()); - tv.setTextSize(12); - tr.addView(tv); - - tv = new TextView(getContext()); - tv.setText(version_values[i].name); - tv.setTextSize(20); - tr.addView(tv); - - binding.fieldsArea.addView(tr); - - tr.setOnClickListener(v -> { - binding.editButton.setVisibility(View.VISIBLE); - trOnClick(version_values, tr); - }); + addRow(version_values[i]); } selindex = -1; + + binding.addButton.setOnClickListener(this::addField); + binding.saveButton.setOnClickListener(this::buttonfunc); + } + + private void addRow(inputType field){ + TableRow tr = getTableRow(field); + + binding.fieldsArea.addView(tr); + + tr.setOnClickListener(v -> { + binding.editButton.setVisibility(View.VISIBLE); + trOnClick(values[values.length-1], tr); + }); + binding.upButton.setOnClickListener(v -> { if(selindex != 0) { binding.saveButton.setVisibility(View.VISIBLE); @@ -156,16 +167,41 @@ public class FieldsFragment extends Fragment { }); binding.downButton.setOnClickListener(v -> { - if(selindex != version_values.length-1) { + if(selindex != values[values.length-1].length-1) { binding.saveButton.setVisibility(View.VISIBLE); binding.fieldsArea.updateRowOrder(selindex, selindex + 1); selindex += 1; } }); - binding.saveButton.setOnClickListener(v -> { - binding.saveButton.setVisibility(View.GONE); + } + + private void buttonfunc(View v){ + AlertDialog.Builder alert = new AlertDialog.Builder(getContext()); + alert.setTitle("Warning!"); + alert.setMessage("Changing or removing some values will result in lost data!\nBut this will create a new field version, and you can revert at any time."); + alert.setPositiveButton("OK", null); + alert.setNegativeButton("Cancel", null); + alert.setCancelable(true); + alert.setOnDismissListener(b -> { + inputType[][] currentValues = fields.load(filename); + assert currentValues != null; + inputType[][] newValues = new inputType[currentValues.length+1][]; + System.arraycopy(currentValues, 0, newValues, 0, currentValues.length); + + newValues[newValues.length-1] = new inputType[values[values.length-1].length]; + + for(int i = 0; i < values[values.length-1].length; i++){ + newValues[newValues.length-1][i] = values[values.length-1][binding.fieldsArea.getReorderedIndexes().get(i)]; + } +// newValues[newValues.length-1] = values[values.length-1]; + + boolean saved = fields.save(filename, newValues); + AlertManager.alert("Saved", String.valueOf(saved)); + + Navigation.findNavController((Activity) getContext(), R.id.nav_host_fragment_activity_main).navigate(R.id.action_navigation_data_fields_to_navigation_data_fields_chooser); }); + alert.create().show(); } private int selindex = -1; @@ -189,6 +225,7 @@ public class FieldsFragment extends Fragment { //System.out.println(field.name); binding.editButton.setOnClickListener(v -> { + binding.editButton.setVisibility(View.GONE); binding.addButton.setVisibility(View.GONE); binding.upButton.setVisibility(View.GONE); binding.downButton.setVisibility(View.GONE); @@ -204,12 +241,240 @@ public class FieldsFragment extends Fragment { binding.ValueEditTable.addView(tv); - FieldEditorHelper fe = new FieldEditorHelper( + final FieldEditorHelper fe = new FieldEditorHelper( getContext(), field, binding.ValueEditTable ); + + binding.saveButton.setVisibility(View.VISIBLE); + binding.saveButton.setOnClickListener(a -> { + System.out.println(fe.save()); + binding.editButton.setVisibility(View.VISIBLE); + binding.addButton.setVisibility(View.VISIBLE); + binding.upButton.setVisibility(View.VISIBLE); + binding.downButton.setVisibility(View.VISIBLE); + binding.ValueEditTable.removeAllViews(); + binding.valueEditContainer.setVisibility(View.GONE); + binding.cancelEditButton.setVisibility(View.GONE); + binding.saveButton.setOnClickListener(this::buttonfunc); + }); + + binding.cancelEditButton.setVisibility(View.VISIBLE); + binding.cancelEditButton.setOnClickListener(a -> { + binding.editButton.setVisibility(View.VISIBLE); + binding.addButton.setVisibility(View.VISIBLE); + binding.upButton.setVisibility(View.VISIBLE); + binding.downButton.setVisibility(View.VISIBLE); + binding.ValueEditTable.removeAllViews(); + binding.valueEditContainer.setVisibility(View.GONE); + binding.cancelEditButton.setVisibility(View.GONE); + binding.saveButton.setOnClickListener(this::buttonfunc); + }); + }); } + + + + + + + + private void addField(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Title"); + + final EditText input = new EditText(getContext()); + input.setInputType(InputType.TYPE_CLASS_TEXT); + + builder.setView(input); + + builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String title = input.getText().toString(); + if(title.isEmpty() || title.isBlank()) { + AlertManager.error("Title cannot be blank!"); + return; + } + addField_Part_2(title); + } + }); + + builder.show(); + } + + private void addField_Part_2(String title) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Title"); + + final PowerSpinnerView dropdown = new PowerSpinnerView(getContext()); + + List iconSpinnerItems = new ArrayList<>(); + + iconSpinnerItems.add(new IconSpinnerItem("Slider")); + iconSpinnerItems.add(new IconSpinnerItem("Text")); + iconSpinnerItems.add(new IconSpinnerItem("Dropdown")); + iconSpinnerItems.add(new IconSpinnerItem("Tally")); + + IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown); + + dropdown.setGravity(Gravity.CENTER); + + dropdown.setSpinnerAdapter(iconSpinnerAdapter); + dropdown.setItems(iconSpinnerItems); + + dropdown.selectItemByIndex(0); + + dropdown.setPadding(10,20,10,20); + dropdown.setBackgroundColor(0xf0000000); + dropdown.setTextColor(0xff00ff00); + dropdown.setTextSize(14.5f); + dropdown.setArrowGravity(SpinnerGravity.END); + dropdown.setArrowPadding(8); +// dropdown.setSpinnerItemHeight(46); + dropdown.setSpinnerPopupElevation(14); + + builder.setView(dropdown); + + builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + addField_Part_3(title, dropdown.getSelectedIndex()); + } + }); + + builder.show(); + } + + private void addField_Part_3(String title, int typeIndex) { + switch (typeIndex){ + case 0: + sliderType slider = new sliderType(); + slider.name = title; + FieldEditorHelper.setSliderParams(slider, FieldEditorHelper.defaultSliderParams); + addField_Part_4(slider); + break; + case 1: + textType text = new textType(); + text.name = title; + FieldEditorHelper.setTextParams(text, FieldEditorHelper.defaultTextParams); + addField_Part_4(text); + break; + case 2: + dropdownType dropdown = new dropdownType(); + dropdown.name = title; + FieldEditorHelper.setDropdownParams(dropdown, FieldEditorHelper.defaultDropdownParams); + addField_Part_4(dropdown); + break; + case 3: + tallyType tally = new tallyType(); + tally.name = title; + FieldEditorHelper.setTallyParams(tally, FieldEditorHelper.defaultTallyParams); + addField_Part_4(tally); + break; + + } + + } + private void addField_Part_4(inputType field) { + binding.editButton.setVisibility(View.GONE); + binding.addButton.setVisibility(View.GONE); + binding.upButton.setVisibility(View.GONE); + binding.downButton.setVisibility(View.GONE); + + binding.ValueEditTable.removeAllViews(); + binding.valueEditContainer.setVisibility(View.VISIBLE); + TextView tv = new TextView(getContext()); + + tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + tv.setText(field.name); + tv.setPadding(8,8,8,8); + tv.setTextSize(24); + + binding.ValueEditTable.addView(tv); + + final FieldEditorHelper fe = new FieldEditorHelper( + getContext(), + field, + binding.ValueEditTable + ); + + binding.saveButton.setVisibility(View.VISIBLE); + binding.saveButton.setOnClickListener(a -> { + inputType[] newValues = new inputType[values[values.length-1].length+1]; + System.arraycopy(values[values.length-1], 0, newValues, 0, values[values.length-1].length); + newValues[newValues.length-1] = field; + values[values.length-1] = newValues; + + AlertManager.alert("Test", String.valueOf(binding.fieldsArea.getReorderedIndexes())); + + //TableRow tr = getTableRow(field); + //binding.fieldsArea.addView(tr); + addRow(field); + + System.out.println(fe.save()); + binding.editButton.setVisibility(View.VISIBLE); + binding.addButton.setVisibility(View.VISIBLE); + binding.upButton.setVisibility(View.VISIBLE); + binding.downButton.setVisibility(View.VISIBLE); + binding.ValueEditTable.removeAllViews(); + binding.valueEditContainer.setVisibility(View.GONE); + binding.cancelEditButton.setVisibility(View.GONE); + binding.saveButton.setOnClickListener(this::buttonfunc); + }); + + binding.cancelEditButton.setVisibility(View.VISIBLE); + binding.cancelEditButton.setOnClickListener(a -> { + binding.editButton.setVisibility(View.VISIBLE); + binding.addButton.setVisibility(View.VISIBLE); + binding.upButton.setVisibility(View.VISIBLE); + binding.downButton.setVisibility(View.VISIBLE); + binding.ValueEditTable.removeAllViews(); + binding.valueEditContainer.setVisibility(View.GONE); + binding.cancelEditButton.setVisibility(View.GONE); + binding.saveButton.setOnClickListener(this::buttonfunc); + }); + + } + + private @NonNull TableRow getTableRow(inputType field) { + TableRow tr = new TableRow(getContext()); + TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT + ); + + rowParams.setMargins(20,20,20,20); + tr.setLayoutParams(rowParams); + tr.setPadding(20,20,20,20); + tr.setBackgroundColor(unfocused_background_color); + + TextView tv = new TextView(getContext()); + tv.setText(field.get_type_name()); + tv.setTextSize(12); + tr.addView(tv); + + tv = new TextView(getContext()); + tv.setText(field.name); + tv.setTextSize(20); + tr.addView(tv); + return tr; + } } diff --git a/app/src/main/res/layout/fragment_data_fields.xml b/app/src/main/res/layout/fragment_data_fields.xml index ba1b968..c66017d 100644 --- a/app/src/main/res/layout/fragment_data_fields.xml +++ b/app/src/main/res/layout/fragment_data_fields.xml @@ -53,6 +53,15 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> +