diff --git a/2024week0-1728149849985.scoutbundle b/2024week0-1728149849985.scoutbundle deleted file mode 100644 index 7927e5d..0000000 Binary files a/2024week0-1728149849985.scoutbundle and /dev/null differ diff --git a/TODO.md b/TODO.md index 296dd5c..8439971 100644 --- a/TODO.md +++ b/TODO.md @@ -1,20 +1,24 @@ ### TODO: ##### Scouting: -- Make practice mode?? ##### Data Analysis: - Statbotics intigration??? ##### Functionality: - Test new FTP thing - UUIDs instead of names for the fields - Fix data storage crashes +- Match selector instead of list for individual team views ### In Progress: ##### Scouting: +- Make scouting UI look much better ##### Data Analysis: ##### Functionality: ### Done: ##### Scouting: +- Make practice mode +- Description for fields ##### Data Analysis: ##### Functionality: -- "Send Meta Files" button \ No newline at end of file +- "Send Meta Files" button +- Year selector \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1ca5e10..c95dcdd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,3 @@ -import com.android.build.api.dsl.AaptOptions -import com.android.build.api.dsl.AndroidResources - plugins { alias(libs.plugins.androidApplication) // id("com.google.gms.google-services") @@ -28,8 +25,8 @@ android { applicationId = "com.ridgebotics.ridgescout" minSdk = 24 targetSdk = 34 - versionCode = 6 - versionName = "0.6" + versionCode = 7 // **IMPORTANT** Increment this before releasing on github + versionName = "1.0"// **IMPORTANT** Change this before releasing on github (.) testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -56,6 +53,7 @@ dependencies { implementation(libs.appcompat) implementation(libs.material) + implementation(libs.material3) implementation(libs.constraintlayout) implementation(libs.lifecycle.livedata.ktx) implementation(libs.lifecycle.viewmodel.ktx) @@ -76,7 +74,6 @@ dependencies { implementation("com.journeyapps:zxing-android-embedded:4.3.0") - implementation("com.github.skydoves:powerspinner:1.2.7") implementation("com.github.PhilJay:MPAndroidChart:v3.1.0") diff --git a/app/src/main/java/com/ridgebotics/ridgescout/scoutingData/fields.java b/app/src/main/java/com/ridgebotics/ridgescout/scoutingData/fields.java index 2aedf5f..edb81c2 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/scoutingData/fields.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/scoutingData/fields.java @@ -23,27 +23,42 @@ public class fields { public static final inputType[][] default_match_fields = new inputType[][] { { - new fieldposType("Auto start pos", new int[]{0,0}), - new tallyType("Auto Notes", 0), - new sliderType("Auto Performance", 5, 0, 10), - new textType("Auto Comments", ""), - new tallyType("Teleop Notes", 0), - new sliderType("Teleop Performance", 5, 0, 10), - new textType("Teleop Comments", ""), - new sliderType("Overall Driving Performance", 5, 0, 10), - new textType("Overall Driving Comments", ""), - new sliderType("Score area (AMP <-> Speaker)", 5, 0, 10), - new dropdownType("End Condition", new String[]{"Nothing", "Attempted Climb", "Successful Climbed", "Climbed with multiple robots", "Climbed with trap"}, 0), - new dropdownType("Robot Condition", new String[]{"Everything was working", "Something was maybe broken", "Something was broken", "Robot was disabled for part of the match", "Missing robot (Joe Johnson)"}, 0), - new textType("Other Comments", "") + new fieldposType("Auto start pos", "Where does the robot start its auto?", new int[]{0,0}), + new tallyType("Auto Coral", "How many coral did this robot score in auto?", 0), + new tallyType("Auto Algae", "How many algae did this robot score in auto?", 0), + new sliderType("Auto Performance", "How well did you think this robot did in auto?", 5, 0, 10), + new textType("Auto Comments", "Anything interesting about auto", ""), + new tallyType("Teleop Coral", "How many coral did this robot score in teleop?", 0), + new tallyType("Teleop Algae", "How many algae did this robot score in teleop?", 0), + new checkboxType("Coral Removal", "Did the robot remove coral?", 0), + new checkboxType("L4 Scoring", "Did the robot score in Layer 4?", 0), + new checkboxType("L3 Scoring", "Did the robot score in Layer 3?", 0), + new checkboxType("L2 Scoring", "Did the robot score in Layer 3?", 0), + new checkboxType("L1 Scoring", "Did the robot score in Layer 1?", 0), + new checkboxType("Processor Scoring", "Did the robot score in the processor?", 0), + new checkboxType("Net Scoring", "Did the robot score in the net?", 0), + new sliderType("Teleop Performance", "How well did the robot drive around?", 5, 0, 10), + new textType("Teleop Notes", "Anything intresting about Teleop", ""), + new dropdownType("End Condition", "What was the final condition of the robot?", new String[]{"Nothing", "Park", "Attempted Shallow", "Shallow", "Attempted Deep", "Deep"}, 0), + new dropdownType("Robot Condition", "Was anything broken?", new String[]{"Everything was working", "Something was maybe broken", "Something was broken", "Robot was disabled for part of the match", "Missing robot (Joe Johnson)"}, 0), + new textType("Other Comments", "Any other comments you have", "") } }; public static final inputType[][] default_pit_fields = new inputType[][] { { - new sliderType("How good is robot", 5, 0, 10), - new sliderType("Test", 1, 0, 10), - new textType("notes", ""), + new dropdownType("Drivetrain type", "What type of drivetrain does this team have?", new String[]{"Swerve Drive", "Tank Drive (Differential)", "Other, Info in comments"}, 0), + new checkboxType("L4 Scoring", "Will the robot score in Layer 4?", 0), + new checkboxType("L3 Scoring", "Will the robot score in Layer 3?", 0), + new checkboxType("L2 Scoring", "Will the robot score in Layer 3?", 0), + new checkboxType("L1/Trough Scoring", "Will the robot score in Layer 1?", 0), + new checkboxType("Processor Scoring", "Will the robot score in the processor?", 0), + new checkboxType("Net Scoring", "Will the robot score algae in the net?", 0), + new sliderType("Specialization", "How specified is the robot to it's scoring area?", 5, 0, 10), + new sliderType("Scoring Consistency", "How consistent is the robot at scoring?", 5, 0, 10), + new dropdownType("Auto type", "What autos does this team have?", new String[]{"No auto", "Simple Coral", "Simple Algae", "Complex Coral", "Complex Algae", "Other, Info in comments"}, 0), + new sliderType("Auto Consistency", "How reliable is this auto;?", 5, 0, 10), + new textType("Comments", "Things go here", "Day 1:\n\nDay 2:\n\nDay 3:\n") } }; diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/checkboxType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/checkboxType.java index 1bcf035..a7fa369 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/checkboxType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/checkboxType.java @@ -1,5 +1,6 @@ package com.ridgebotics.ridgescout.types.input; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.Gravity; @@ -28,11 +29,6 @@ import com.ridgebotics.ridgescout.types.data.dataType; import com.ridgebotics.ridgescout.types.data.intType; import com.ridgebotics.ridgescout.utility.BuiltByteParser; import com.ridgebotics.ridgescout.utility.ByteBuilder; -import com.skydoves.powerspinner.IconSpinnerAdapter; -import com.skydoves.powerspinner.IconSpinnerItem; -import com.skydoves.powerspinner.OnSpinnerItemSelectedListener; -import com.skydoves.powerspinner.PowerSpinnerView; -import com.skydoves.powerspinner.SpinnerGravity; import java.util.ArrayList; import java.util.List; @@ -45,8 +41,8 @@ public class checkboxType extends inputType { public Object get_fallback_value(){return 0;} public checkboxType(){}; public String get_type_name(){return "Checkbox";} - public checkboxType(String name, int isChecked){ - super(name); + public checkboxType(String name, String description, int isChecked){ + super(name, description); this.default_value = isChecked; } @@ -54,6 +50,7 @@ public class checkboxType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addInt((int)default_value); return bb.build(); } @@ -62,7 +59,8 @@ public class checkboxType extends inputType { ArrayList objects = bbp.parse(); name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); } // public PowerSpinnerView dropdown = null; @@ -71,15 +69,11 @@ public class checkboxType extends inputType { public View createView(Context context, Function onUpdate){ checkBox = new CheckBox(context); + checkBox.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6); checkBox.setText(name); - checkBox.setTextSize(24); + setViewValue(default_value); - checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - onUpdate.apply(getViewValue()); - } - }); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> onUpdate.apply(getViewValue())); return checkBox; @@ -114,6 +108,7 @@ public class checkboxType extends inputType { public void add_individual_view(LinearLayout parent, dataType data){ if(data.isNull()) return; CheckBox cb = new CheckBox(parent.getContext()); + cb.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6); cb.setText(name); cb.setChecked((int) data.get() == 1); cb.setEnabled(false); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/dropdownType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/dropdownType.java index cb2d97f..928a8fa 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/dropdownType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/dropdownType.java @@ -1,5 +1,8 @@ package com.ridgebotics.ridgescout.types.input; +import static com.google.android.material.internal.ContextUtils.getActivity; + +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.Gravity; @@ -13,6 +16,7 @@ import androidx.annotation.Nullable; import com.ridgebotics.ridgescout.types.data.dataType; import com.ridgebotics.ridgescout.types.data.intType; +import com.ridgebotics.ridgescout.ui.CustomSpinnerView; import com.ridgebotics.ridgescout.utility.BuiltByteParser; import com.ridgebotics.ridgescout.utility.ByteBuilder; import com.github.mikephil.charting.charts.LineChart; @@ -24,13 +28,9 @@ import com.github.mikephil.charting.data.LineDataSet; import com.github.mikephil.charting.data.PieData; import com.github.mikephil.charting.data.PieDataSet; import com.github.mikephil.charting.data.PieEntry; -import com.skydoves.powerspinner.IconSpinnerAdapter; -import com.skydoves.powerspinner.IconSpinnerItem; -import com.skydoves.powerspinner.OnSpinnerItemSelectedListener; -import com.skydoves.powerspinner.PowerSpinnerView; -import com.skydoves.powerspinner.SpinnerGravity; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.Function; @@ -42,8 +42,8 @@ public class dropdownType extends inputType { public Object get_fallback_value(){return 0;} public dropdownType(){}; public String get_type_name(){return "Dropdown";} - public dropdownType(String name, String[] text_options, int defaultSelIndex){ - super(name); + public dropdownType(String name, String description, String[] text_options, int defaultSelIndex){ + super(name, description); this.text_options = text_options; this.default_value = defaultSelIndex; } @@ -52,6 +52,7 @@ public class dropdownType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addInt((int)default_value); bb.addStringArray(text_options); return bb.build(); @@ -61,55 +62,24 @@ public class dropdownType extends inputType { ArrayList objects = bbp.parse(); name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); - text_options = (String[]) objects.get(2).get(); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); + text_options = (String[]) objects.get(3).get(); } - public PowerSpinnerView dropdown = null; + public CustomSpinnerView dropdown = null; public View createView(Context context, Function onUpdate){ - dropdown = new PowerSpinnerView(context); + dropdown = new CustomSpinnerView(context); - List iconSpinnerItems = new ArrayList<>(); - for(int i = 0; i < text_options.length; i++){ - iconSpinnerItems.add(new IconSpinnerItem(text_options[i])); - } - IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown); + ArrayList iconSpinnerItems = new ArrayList<>(Arrays.asList(text_options)); - dropdown.setGravity(Gravity.CENTER); + dropdown.setTitle(name); + dropdown.setOptions(iconSpinnerItems, (int) default_value); + onUpdate.apply(getViewValue()); - dropdown.setSpinnerAdapter(iconSpinnerAdapter); - dropdown.setItems(iconSpinnerItems); + dropdown.setOnClickListener((item, index) -> onUpdate.apply(getViewValue())); - dropdown.selectItemByIndex((int) default_value); - - 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); - - - - - dropdown.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener() { - @Override - public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex, - IconSpinnerItem newItem) { - onUpdate.apply(getViewValue()); - } - }); - -// dropdown.setLifecycleOwner(context.life); -// slider.addOnChangeListener(new Slider.OnChangeListener() { -// @Override -// public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) { -// onUpdate.apply(getViewValue()); -// } -// }); return dropdown; } @@ -123,7 +93,7 @@ public class dropdownType extends inputType { isBlank = false; dropdown.setVisibility(View.VISIBLE); - dropdown.selectItemByIndex((int) value); + dropdown.setOption((int) value); } public void nullify(){ isBlank = true; @@ -132,7 +102,7 @@ public class dropdownType extends inputType { public dataType getViewValue(){ if(dropdown == null) return null; if(dropdown.getVisibility() == View.GONE) return new intType(name, intType.nullval); - return new intType(name, dropdown.getSelectedIndex()); + return new intType(name, dropdown.getIndex()); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/fieldposType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/fieldposType.java index 7cb635c..316ec6a 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/fieldposType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/fieldposType.java @@ -2,6 +2,7 @@ package com.ridgebotics.ridgescout.types.input; import static android.text.InputType.TYPE_CLASS_NUMBER; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.text.Editable; @@ -39,8 +40,8 @@ public class fieldposType extends inputType { public Object get_fallback_value(){return 0;} public fieldposType(){} public String get_type_name(){return "Field Pos";} - public fieldposType(String name, int[] default_value){ - super(name); + public fieldposType(String name, String description, int[] default_value){ + super(name, description); this.default_value = default_value; } @@ -51,6 +52,7 @@ public class fieldposType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addIntArray((int[]) default_value); return bb.build(); } @@ -60,8 +62,8 @@ public class fieldposType extends inputType { ArrayList objects = bbp.parse(); name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); - System.out.println("Defalt value!!!!!" + default_value); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); } @@ -85,6 +87,10 @@ public class fieldposType extends inputType { nullify(); return; } + if(((int[]) value)[0] == 255 && ((int[]) value)[1] == 255){ + nullify(); + return; + } isBlank = false; field.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/inputType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/inputType.java index 71818f1..305a105 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/inputType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/inputType.java @@ -1,5 +1,6 @@ package com.ridgebotics.ridgescout.types.input; +import android.app.Activity; import android.content.Context; import android.view.View; import android.widget.LinearLayout; @@ -29,14 +30,16 @@ public abstract class inputType { FIELDPOS } public String name; + public String description; public Object default_value; public abstract inputTypes getInputType(); public abstract dataType.valueTypes getValueType(); public abstract Object get_fallback_value(); public abstract int get_byte_id(); public inputType(){} - public inputType(String name){ + public inputType(String name, String description){ this.name = name; + this.description = description; } public abstract String get_type_name(); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/numberType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/numberType.java index dbff3a9..b0dab60 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/numberType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/numberType.java @@ -2,6 +2,7 @@ package com.ridgebotics.ridgescout.types.input; import static android.text.InputType.TYPE_CLASS_NUMBER; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.text.Editable; @@ -35,8 +36,8 @@ public class numberType extends inputType { public Object get_fallback_value(){return 0;} public numberType(){} public String get_type_name(){return "Number";} - public numberType(String name, int default_value){ - super(name); + public numberType(String name, String description, int default_value){ + super(name, description); this.default_value = default_value; } @@ -47,6 +48,7 @@ public class numberType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addInt((int)default_value); return bb.build(); } @@ -55,7 +57,8 @@ public class numberType extends inputType { ArrayList objects = bbp.parse(); name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/sliderType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/sliderType.java index b96c1b5..c3d443a 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/sliderType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/sliderType.java @@ -1,5 +1,6 @@ package com.ridgebotics.ridgescout.types.input; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.View; @@ -35,8 +36,8 @@ public class sliderType extends inputType { public Object get_fallback_value(){return 0;} public sliderType(){}; public String get_type_name(){return "Slider";} - public sliderType(String name, int defaultValue, int min, int max){ - super(name); + public sliderType(String name, String description, int defaultValue, int min, int max){ + super(name, description); this.default_value = defaultValue; this.min = min; this.max = max; @@ -48,6 +49,7 @@ public class sliderType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addInt((int)default_value); bb.addInt(min); bb.addInt(max); @@ -57,10 +59,11 @@ public class sliderType extends inputType { BuiltByteParser bbp = new BuiltByteParser(bytes); ArrayList objects = bbp.parse(); - name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); - min = (int) objects.get(2).get(); - max = (int) objects.get(3).get(); + name = (String) objects.get(0).get(); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); + min = (int) objects.get(3).get(); + max = (int) objects.get(4).get(); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/tallyType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/tallyType.java index 1808bfb..68333d6 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/tallyType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/tallyType.java @@ -1,5 +1,6 @@ package com.ridgebotics.ridgescout.types.input; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.Gravity; @@ -31,8 +32,8 @@ public class tallyType extends inputType { public Object get_fallback_value(){return 0;} public tallyType(){} public String get_type_name(){return "Tally";} - public tallyType(String name, int default_value){ - super(name); + public tallyType(String name, String description, int default_value){ + super(name, description); this.default_value = default_value; } @@ -43,6 +44,7 @@ public class tallyType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addInt((int)default_value); return bb.build(); } @@ -51,7 +53,8 @@ public class tallyType extends inputType { ArrayList objects = bbp.parse(); name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); } @@ -72,7 +75,6 @@ public class tallyType extends inputType { public void setViewValue(Object value) { if(tally == null) return; - System.out.println(value); if(intType.isNull((int)value)){ nullify(); return; diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/textType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/textType.java index a1be0d1..30247c8 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/textType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/textType.java @@ -1,5 +1,6 @@ package com.ridgebotics.ridgescout.types.input; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.text.Editable; @@ -34,8 +35,8 @@ public class textType extends inputType { public dataType.valueTypes getValueType(){return dataType.valueTypes.STRING;} public Object get_fallback_value(){return "";} public textType(){} - public textType(String name, String default_text){ - super(name); + public textType(String name, String description, String default_text){ + super(name, description); this.default_value = default_text; } public String get_type_name(){return "Text";} @@ -49,6 +50,7 @@ public class textType extends inputType { public byte[] encode() throws ByteBuilder.buildingException { ByteBuilder bb = new ByteBuilder(); bb.addString(name); + bb.addString(description); bb.addString((String) default_value); return bb.build(); } @@ -56,8 +58,9 @@ public class textType extends inputType { BuiltByteParser bbp = new BuiltByteParser(bytes); ArrayList objects = bbp.parse(); - name = (String) objects.get(0).get(); - default_value = objects.get(1).get(); + name = (String) objects.get(0).get(); + description = (String) objects.get(1).get(); + default_value = objects.get(2).get(); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/CustomSpinnerPopup.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/CustomSpinnerPopup.java new file mode 100644 index 0000000..62d7aaf --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/CustomSpinnerPopup.java @@ -0,0 +1,117 @@ +package com.ridgebotics.ridgescout.ui; + +import android.content.Context; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.TableLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.appbar.MaterialToolbar; +import com.google.android.material.divider.MaterialDivider; +import com.ridgebotics.ridgescout.R; + +import java.util.ArrayList; +import java.util.List; + +public class CustomSpinnerPopup extends TableLayout { + + public CustomSpinnerPopup(Context context) { + super(context); + } + + public CustomSpinnerPopup(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public interface OnOptionSelectedListener { + void onOptionSelected(String option); + } + + public CustomSpinnerPopup init(List options, OnOptionSelectedListener onOptionSelectedListener, int defaultOption){ + CheckBox[] checkBoxes = new CheckBox[options.size()]; + setPadding(16, 16, 16, 16); + for(int i = 0; i < options.size(); i++){ + final CheckBox cb = new CheckBox(getContext()); + cb.setText(options.get(i)); + cb.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline5); + cb.setChecked(i == defaultOption); + + if(i > 0) + addView(new MaterialDivider(getContext())); + + addView(cb); + checkBoxes[i] = cb; + + final int fi = i; + cb.setOnClickListener(a -> { + onOptionSelectedListener.onOptionSelected(options.get(fi)); + for (CheckBox checkBox : checkBoxes) + checkBox.setChecked(false); + cb.setChecked(true); + }); + } + + return this; + } + +// public static CustomSpinnerPopup newInstance(ArrayList options) { +// CustomSpinnerPopup dialog = new CustomSpinnerPopup(); +// Bundle args = new Bundle(); +// args.putStringArrayList("options", options); +// +// +// +//// dialog.setArguments(args); +// return dialog; +// } + +// @Override +// public void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// setStyle(DialogFragment.STYLE_NORMAL, R.style.FullScreenDialogStyle); +// if (getArguments() != null) { +// options = getArguments().getStringArrayList("options"); +// } +// } +// +// @Nullable +// @Override +// public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, +// @Nullable Bundle savedInstanceState) { +// View view = inflater.inflate(R.layout.view_custom_spinner_popup, container, false); +// +// // Setup toolbar +// MaterialToolbar toolbar = view.findViewById(R.id.toolbar); +// toolbar.setNavigationOnClickListener(v -> dismiss()); +// toolbar.setTitle("Select an Option"); +// +// // Setup RecyclerView +// recyclerView = view.findViewById(R.id.recyclerView); +// recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); +// adapter = new CustomSpinnerOptionsAdapter(options, option -> { +// if (listener != null) { +// listener.onOptionSelected(option); +// } +// dismiss(); +// }); +// recyclerView.setAdapter(adapter); +// +// return view; +// } +// + + + +} + diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/CustomSpinnerView.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/CustomSpinnerView.java new file mode 100644 index 0000000..5a18298 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/CustomSpinnerView.java @@ -0,0 +1,130 @@ +package com.ridgebotics.ridgescout.ui; + +import static android.app.PendingIntent.getActivity; +import static com.ridgebotics.ridgescout.utility.settingsManager.getEditor; + +import android.app.AlertDialog; +import android.content.Context; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; + +import com.ridgebotics.ridgescout.R; +import com.ridgebotics.ridgescout.databinding.ViewCustomSpinnerBinding; + +import java.util.ArrayList; +import java.util.List; + +public class CustomSpinnerView extends LinearLayout { + + public interface onClickListener { + void onClick(String item, int index); + } + + public CustomSpinnerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public CustomSpinnerView(Context context) { + super(context); + init(context); + } + + private List options; + private onClickListener onClickListener; + + private TextView title; + private TextView item; + + private int index = -1; + + public void init(Context context) { + LayoutInflater.from(context).inflate(R.layout.view_custom_spinner, this, true); + + title = findViewById(R.id.title); + item = findViewById(R.id.item); + } + + public void setOnClickListener(onClickListener listener){ + this.onClickListener = listener; + } + + + public void setOptions(List options, String defaultOption){ + setOptions(options, options.indexOf(defaultOption)); + } + + public void setOptions(List options, int defaultOption){ + this.options = options; + this.index = defaultOption; + + if(defaultOption != -1) + this.item.setText(options.get(defaultOption)); + + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + + ScrollView sv = new ScrollView(getContext()); + sv.setLayoutDirection(ScrollView.SCROLL_AXIS_VERTICAL); + + LinearLayout ll = new LinearLayout(getContext()); + ll.setOrientation(LinearLayout.VERTICAL); + sv.addView(ll); + + builder.setPositiveButton("OK", (dialog, which) -> {}); + CustomSpinnerPopup popup = new CustomSpinnerPopup(getContext()).init(options, option -> { +// dialog.(); + if(!isEnabled()) return; + item.setText(option); + index = options.indexOf(option); + if(onClickListener != null) { + onClickListener.onClick(option, options.indexOf(option)); + } + }, index); + + ll.addView(popup); + + popup.setLayoutDirection(0); + builder.setView(sv); + AlertDialog dialog = builder.create(); + + +// popup.setOnOptionSelectedListener(); + + this.setOnClickListener(v -> { + if(!isEnabled()) return; + dialog.show(); + }); + } + + public void setTitle(String text){ + title.setText(text); + } + + public void setOption(String option) { + item.setText(option); + index = options.indexOf(option); + } + + public void setOption(int index) { + item.setText(options.get(index)); + this.index = index; + } + + public int getIndex(){ + return index; + } + public String getOption(){ + return options.get(index); + } +} diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/ToggleTitleView.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/ToggleTitleView.java new file mode 100644 index 0000000..2d63f81 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/ToggleTitleView.java @@ -0,0 +1,96 @@ +package com.ridgebotics.ridgescout.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.ridgebotics.ridgescout.R; + +public class ToggleTitleView extends ConstraintLayout { + public ToggleTitleView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public ToggleTitleView(@NonNull Context context) { + super(context); + init(context); + } + + public interface OnToggleListener { + void onToggle(boolean enabled); + } + + TextView titleView; + CheckBox toggle_title_checkbox; + TextView toggle_title_description; + OnToggleListener onToggleListener; + + + + public void init(Context context){ + LayoutInflater.from(context).inflate(R.layout.view_toggle_title, this, true); + + titleView = findViewById(R.id.toggle_title); + toggle_title_checkbox = findViewById(R.id.toggle_title_checkbox); + toggle_title_description = findViewById(R.id.toggle_title_description); + + toggle_title_checkbox.setOnCheckedChangeListener((compoundButton, checked) -> { + // If checkbox has already updated + if(enabled == checked) return; + + if (checked) + enable(); + else + disable(); + + onToggleListener.onToggle(!checked); + }); + } + + public void setTitle(String title){ + titleView.setText(title); + } + + public void setDescription(String description){ + toggle_title_description.setText(description); + } + + public void setOnToggleListener(OnToggleListener onToggleListener){ + this.onToggleListener = onToggleListener; + } + + public boolean enabled = true; + + public boolean isEnabled(){return enabled;} + + public void disable(){ + enabled = false; + toggle_title_checkbox.setChecked(false); + toggle_title_description.setVisibility(View.GONE); + setBackgroundColor(0xffff0000); + titleView.setTextColor(0xff000000); + } + public void enable(){ + enabled = true; + toggle_title_checkbox.setChecked(true); + toggle_title_description.setVisibility(View.VISIBLE); + setBackgroundColor(0x00000000); + titleView.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline5); + } + + public void setEnabled(boolean enabled){ + if(enabled) + disable(); + else + enable(); + } +} diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataFragment.java index 4c91875..c00565f 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataFragment.java @@ -54,12 +54,9 @@ public class DataFragment extends Fragment { binding.teamsButton.setOnClickListener(v -> { TeamSelectorFragment.setPits_mode(false); - TeamSelectorFragment.setOnSelect(new TeamSelectorFragment.onTeamSelected() { - @Override - public void onSelect(TeamSelectorFragment self, frcTeam team) { - TeamsFragment.setTeam(team); - findNavController(self).navigate(R.id.action_navigation_team_selector_to_navigation_data_teams); - } + TeamSelectorFragment.setOnSelect((self, team) -> { + TeamsFragment.setTeam(team); + findNavController(self).navigate(R.id.action_navigation_team_selector_to_navigation_data_teams); }); findNavController(this).navigate(R.id.action_navigation_data_to_navigation_team_selector); }); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldEditorHelper.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldEditorHelper.java index 2dea62d..fad663f 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldEditorHelper.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldEditorHelper.java @@ -68,27 +68,34 @@ public class FieldEditorHelper { // } public static final parameterType[] defaultSliderParams = new parameterType[]{ + new paramString("Description", ""), new paramNumber("Min", 0), new paramNumber("Max", 10), new paramNumber("Default Value", 5) }; public static final parameterType[] defaultDropdownParams = new parameterType[]{ + new paramString("Description", ""), new paramStringArray("Default Value", new String[]{"Zero","One","Two","Three"}), new paramNumber("Default Option", 0), }; public static final parameterType[] defaultTextParams = new parameterType[]{ + new paramString("Description", ""), new paramString("Default Value", "") }; public static final parameterType[] defaultTallyParams = new parameterType[]{ + new paramString("Description", ""), new paramNumber("Default Value", 0) }; public static final parameterType[] defaultNumberParams = new parameterType[]{ + new paramString("Description", ""), new paramNumber("Default Value", 0) }; public static final parameterType[] defaultCheckboxParam = new parameterType[]{ + new paramString("Description", ""), new paramNumber("Default Value ( 1 or 0 )", 0) }; public static final parameterType[] defaultFieldPosParam = new parameterType[]{ + new paramString("Description", ""), new paramNumber("Default X", 0), new paramNumber("Default Y", 0) }; @@ -96,6 +103,7 @@ public class FieldEditorHelper { private static parameterType[] getSliderParams(sliderType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramNumber("Min", s.min), new paramNumber("Max", s.max), new paramNumber("Default Value", (int) s.default_value) @@ -104,6 +112,7 @@ public class FieldEditorHelper { private static parameterType[] getDropdownParams(dropdownType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramStringArray("Default Value",s.text_options), new paramNumber("Default Option", (int) s.default_value), }; @@ -111,30 +120,35 @@ public class FieldEditorHelper { private static parameterType[] getTextParams(textType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramString("Default Value", (String) s.default_value) }; } private static parameterType[] getTallyParams(tallyType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramNumber("Default Value", (int) s.default_value) }; } private static parameterType[] getNumberParams(numberType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramNumber("Default Value", (int) s.default_value) }; } private static parameterType[] getCheckboxParam(checkboxType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramNumber("Default Value ( 1 or 0 )", (int) s.default_value) }; } private static parameterType[] getFieldPosParam(fieldposType s){ return new parameterType[]{ + new paramString("Description", s.description), new paramNumber("Default X", ((int[]) s.default_value)[0]), new paramNumber("Default Y", ((int[]) s.default_value)[1]) }; @@ -143,36 +157,43 @@ 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; + s.description = ((paramString) types[0]).val; + s.min = ((paramNumber) types[1]).val; + s.max = ((paramNumber) types[2]).val; + s.default_value = ((paramNumber) types[3]).val; } public static void setDropdownParams(dropdownType s, parameterType[] types){ - s.text_options = ((paramStringArray) types[0]).val; - s.default_value = ((paramNumber) types[1]).val; + s.description = ((paramString) types[0]).val; + s.text_options = ((paramStringArray) types[1]).val; + s.default_value = ((paramNumber) types[2]).val; } public static void setTextParams(textType s, parameterType[] types){ - s.default_value = ((paramString) types[0]).val; + s.description = ((paramString) types[0]).val; + s.default_value = ((paramString) types[1]).val; } public static void setTallyParams(tallyType s, parameterType[] types){ - s.default_value = ((paramNumber) types[0]).val; + s.description = ((paramString) types[0]).val; + s.default_value = ((paramNumber) types[1]).val; } public static void setNumberParams(numberType s, parameterType[] types){ - s.default_value = ((paramNumber) types[0]).val; + s.description = ((paramString) types[0]).val; + s.default_value = ((paramNumber) types[1]).val; } public static void setCheckboxParam(checkboxType s, parameterType[] types){ - s.default_value = ((paramNumber) types[0]).val; + s.description = ((paramString) types[0]).val; + s.default_value = ((paramNumber) types[1]).val; } public static void setFieldPosParam(fieldposType s, parameterType[] types){ + s.description = ((paramString) types[0]).val; s.default_value = new int[]{ - ((paramNumber) types[0]).val, - ((paramNumber) types[1]).val + ((paramNumber) types[1]).val, + ((paramNumber) types[2]).val }; } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldsFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldsFragment.java index d1f4ef3..6a681d5 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldsFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldsFragment.java @@ -32,11 +32,8 @@ import com.ridgebotics.ridgescout.types.input.numberType; import com.ridgebotics.ridgescout.types.input.sliderType; import com.ridgebotics.ridgescout.types.input.tallyType; import com.ridgebotics.ridgescout.types.input.textType; +import com.ridgebotics.ridgescout.ui.CustomSpinnerView; import com.ridgebotics.ridgescout.utility.AlertManager; -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; @@ -401,53 +398,26 @@ public class FieldsFragment extends Fragment { private void addField_Part_2(String title) { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle("Title"); + builder.setTitle("Select Type"); - final PowerSpinnerView dropdown = new PowerSpinnerView(getContext()); + final CustomSpinnerView dropdown = new CustomSpinnerView(getContext()); + List options = new ArrayList<>(); - List iconSpinnerItems = new ArrayList<>(); + options.add("Slider"); + options.add("Text"); + options.add("Dropdown"); + options.add("Tally"); + options.add("Number"); + options.add("Checkbox"); + options.add("Field Position"); - iconSpinnerItems.add(new IconSpinnerItem("Slider")); - iconSpinnerItems.add(new IconSpinnerItem("Text")); - iconSpinnerItems.add(new IconSpinnerItem("Dropdown")); - iconSpinnerItems.add(new IconSpinnerItem("Tally")); - iconSpinnerItems.add(new IconSpinnerItem("Number")); - iconSpinnerItems.add(new IconSpinnerItem("Checkbox")); - iconSpinnerItems.add(new IconSpinnerItem("Field Position")); - - 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); + dropdown.setOptions(options, 0); + dropdown.setTitle("Type"); 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.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel()); + builder.setPositiveButton("OK", (dialog, which) -> addField_Part_3(title, dropdown.getIndex())); builder.show(); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/TeamsFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/TeamsFragment.java index 0998ed7..d1229af 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/TeamsFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/TeamsFragment.java @@ -22,6 +22,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.ridgebotics.ridgescout.ui.CustomSpinnerView; import com.ridgebotics.ridgescout.utility.AlertManager; import com.ridgebotics.ridgescout.utility.settingsManager; import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding; @@ -31,11 +32,6 @@ import com.ridgebotics.ridgescout.types.frcTeam; import com.ridgebotics.ridgescout.utility.DataManager; import com.ridgebotics.ridgescout.utility.fileEditor; import com.google.android.material.divider.MaterialDivider; -import com.skydoves.powerspinner.IconSpinnerAdapter; -import com.skydoves.powerspinner.IconSpinnerItem; -import com.skydoves.powerspinner.OnSpinnerItemSelectedListener; -import com.skydoves.powerspinner.PowerSpinnerView; -import com.skydoves.powerspinner.SpinnerGravity; import java.util.ArrayList; import java.util.List; @@ -48,22 +44,30 @@ public class TeamsFragment extends Fragment { team = tmpteam; } - private static final int background_color = 0x5000ff00; - private static final int unsaved_background_color = 0x2000ff00; public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentDataTeamsBinding.inflate(inflater, container, false); - binding.teamsArea.removeAllViews(); - DataManager.reload_match_fields(); DataManager.reload_pit_fields(); - TableLayout table = new TableLayout(getContext()); - table.setStretchAllColumns(true); - binding.teamsArea.addView(table); + binding.dataTypeSpinner.setTitle("Data Mode"); + + List options = new ArrayList<>(); + options.add("Individual"); + options.add("Compiled"); + options.add("History"); + + binding.dataTypeSpinner.setOptions(options, 0); + + binding.dataTypeSpinner.setOnClickListener((item, index) -> { + settingsManager.setDataMode(index); + loadTeam(index); + }); + +// binding.teamsMainElem. loadTeam(settingsManager.getDataMode()); @@ -71,117 +75,57 @@ public class TeamsFragment extends Fragment { } public void loadTeam(int mode) { - binding.teamsArea.removeAllViews(); - LinearLayout ll = new LinearLayout(getContext()); - ll.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - ll.setOrientation(LinearLayout.VERTICAL); - binding.teamsArea.addView(ll); - - - - PowerSpinnerView dropdown = new PowerSpinnerView(getContext()); - - List iconSpinnerItems = new ArrayList<>(); - - iconSpinnerItems.add(new IconSpinnerItem("Individual")); - iconSpinnerItems.add(new IconSpinnerItem("Compiled")); - iconSpinnerItems.add(new IconSpinnerItem("History")); - - IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown); - dropdown.setSpinnerAdapter(iconSpinnerAdapter); - dropdown.setItems(iconSpinnerItems); - - dropdown.selectItemByIndex(0); - - dropdown.setPadding(10,20,10,20); - dropdown.setBackgroundColor(0xf0000000); - dropdown.setTextColor(0xff00ff00); - dropdown.setTextSize(15); - dropdown.setArrowGravity(SpinnerGravity.END); - dropdown.setArrowPadding(8); -// dropdown.setSpinnerItemHeight(46); - dropdown.setSpinnerPopupElevation(14); - - - dropdown.selectItemByIndex(mode); - - - dropdown.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener() { - @Override - public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex, - IconSpinnerItem newItem) { - - settingsManager.setDataMode(newIndex); - loadTeam(newIndex); - } - }); - - ll.addView(dropdown); +// LinearLayout ll = new LinearLayout(getContext()); +// ll.setLayoutParams(new LinearLayout.LayoutParams( +// ViewGroup.LayoutParams.MATCH_PARENT, +// ViewGroup.LayoutParams.WRAP_CONTENT +// )); +// ll.setOrientation(LinearLayout.VERTICAL); +// binding.teamsArea.addView(ll); + binding.teamName2.setText(String.valueOf(team.teamNumber)); + binding.teamDescription2.setText(team.getDescription()); +// tv = new TextView(getContext()); +// tv.setLayoutParams(new FrameLayout.LayoutParams( +// ViewGroup.LayoutParams.MATCH_PARENT, +// ViewGroup.LayoutParams.WRAP_CONTENT +// )); +// tv.setGravity(Gravity.CENTER_HORIZONTAL); +// tv.setText(team.getDescription()); +// tv.setTextSize(16); +// ll.addView(tv); - TextView tv = new TextView(getContext()); - tv.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText(String.valueOf(team.teamNumber)); - tv.setTextSize(28); - ll.addView(tv); - - tv = new TextView(getContext()); - tv.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText(team.teamName); - tv.setTextSize(28); - ll.addView(tv); - - tv = new TextView(getContext()); - tv.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText(team.getDescription()); - tv.setTextSize(16); - ll.addView(tv); - - add_pit_data(ll, team); - add_match_data(ll, team, mode); + add_pit_data(team); + add_match_data(team, mode); } - public void add_pit_data(LinearLayout ll, frcTeam team){ + public void add_pit_data(frcTeam team){ + binding.pitArea.removeAllViews(); final String filename = evcode+"-"+team.teamNumber+".pitscoutdata"; - ll.addView(new MaterialDivider(getContext())); +// ll.addView(new MaterialDivider(getContext())); - TextView tv = new TextView(getContext()); - tv.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setPadding(0,10,0,10); - tv.setText("----- Pit data -----"); - tv.setTextSize(30); - ll.addView(tv); +// TextView tv = new TextView(getContext()); +// tv.setLayoutParams(new FrameLayout.LayoutParams( +// ViewGroup.LayoutParams.MATCH_PARENT, +// ViewGroup.LayoutParams.WRAP_CONTENT +// )); +// tv.setGravity(Gravity.CENTER_HORIZONTAL); +// tv.setPadding(0,10,0,10); +// tv.setText("----- Pit data -----"); +// tv.setTextSize(30); +// ll.addView(tv); - ll.addView(new MaterialDivider(getContext())); +// ll.addView(new MaterialDivider(getContext())); if(!fileEditor.fileExist(filename)){ - tv = new TextView(getContext()); + TextView tv = new TextView(getContext()); tv.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT @@ -189,13 +133,13 @@ public class TeamsFragment extends Fragment { tv.setGravity(Gravity.CENTER_HORIZONTAL); tv.setText("No pit data has been collected!"); tv.setTextSize(23); - ll.addView(tv); + binding.pitArea.addView(tv); return; } ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filename, pit_values, pit_transferValues); - tv = new TextView(getContext()); + TextView tv = new TextView(getContext()); tv.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT @@ -204,7 +148,7 @@ public class TeamsFragment extends Fragment { tv.setGravity(Gravity.CENTER_HORIZONTAL); tv.setText("Pit scouting by " + psda.username); tv.setTextSize(30); - ll.addView(tv); + binding.pitArea.addView(tv); for (int a = 0; a < psda.data.array.length; a++) { tv = new TextView(getContext()); @@ -222,38 +166,24 @@ public class TeamsFragment extends Fragment { } - ll.addView(tv); + + binding.pitArea.addView(tv); - pit_latest_values[a].add_individual_view(ll, psda.data.array[a]); + pit_latest_values[a].add_individual_view(binding.pitArea, psda.data.array[a]); } } + private int matchIndex = 0; - - public void add_match_data(LinearLayout ll, frcTeam team, int mode){ + public void add_match_data(frcTeam team, int mode){ + binding.matchArea.removeAllViews(); + binding.individualViewSelector.setVisibility(View.GONE); String[] files = fileEditor.getMatchesByTeamNum(evcode, team.teamNumber); - ll.addView(new MaterialDivider(getContext())); - - TextView tv = new TextView(getContext()); - tv.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText("----- Match data -----"); - tv.setPadding(0,10,0,10); - tv.setTextSize(30); - ll.addView(tv); - - ll.addView(new MaterialDivider(getContext())); - - - if(files.length == 0){ - tv = new TextView(getContext()); + TextView tv = new TextView(getContext()); tv.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT @@ -261,19 +191,19 @@ public class TeamsFragment extends Fragment { tv.setGravity(Gravity.CENTER_HORIZONTAL); tv.setText("No match data has been collected!"); tv.setTextSize(23); - ll.addView(tv); + binding.matchArea.addView(tv); return; } switch (mode){ case 0: - add_individual_views(ll,files); + add_individual_views(files); break; case 1: - add_compiled_views(ll,files); + add_compiled_views(files); break; case 2: - add_history_views(ll,files); + add_history_views(files); break; } } @@ -281,50 +211,75 @@ public class TeamsFragment extends Fragment { - public void add_individual_views(LinearLayout ll, String[] files) { - for (int i = 0; i < files.length; i++) { - try { - String[] split = files[i].split("-"); - int match_num = Integer.parseInt(split[1]); + public void add_individual_views(String[] files) { - ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues); - TextView tv = new TextView(getContext()); + matchIndex = 0; + + binding.individualViewSelector.setVisibility(View.VISIBLE); + + binding.matchesPlusBtn.setOnClickListener(view -> { + matchIndex++; + update_individual_view(files); + }); + + binding.matchesMinusBtn.setOnClickListener(view -> { + matchIndex--; + update_individual_view(files); + }); + + update_individual_view(files); + } + + private void update_individual_view(String[] files){ + binding.matchesPlusBtn.setEnabled(matchIndex < files.length - 1); + binding.matchesMinusBtn.setEnabled(matchIndex > 0); + binding.matchArea.removeAllViews(); + + + try { + String[] split = files[matchIndex].split("-"); + int match_num = Integer.parseInt(split[1]); + binding.matchNum.setText(split[1]); + + ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[matchIndex], match_values, match_transferValues); + + TextView tv = new TextView(getContext()); + tv.setLayoutParams(new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + tv.setPadding(0, 40, 0, 5); + tv.setGravity(Gravity.CENTER_HORIZONTAL); + tv.setText("M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username); + tv.setTextSize(30); + binding.matchArea.addView(tv); + + for (int i = 0; i < psda.data.array.length; i++) { + tv = new TextView(getContext()); tv.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT )); - tv.setPadding(0, 40, 0, 5); tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText("M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username); - tv.setTextSize(30); - ll.addView(tv); + tv.setText(psda.data.array[i].getName()); + tv.setTextSize(25); - for (int a = 0; a < psda.data.array.length; a++) { - tv = new TextView(getContext()); - tv.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText(psda.data.array[a].getName()); - tv.setTextSize(25); - - if (psda.data.array[a].isNull()) { - tv.setBackgroundColor(0xffff0000); - tv.setTextColor(0xff000000); - } - - ll.addView(tv); - - - match_latest_values[a].add_individual_view(ll, psda.data.array[a]); + if (psda.data.array[i].isNull()) { + tv.setBackgroundColor(0xffff0000); + tv.setTextColor(0xff000000); } - }catch (Exception e){ - e.printStackTrace(); - AlertManager.alert("Warning!", "Failure to load file " + files[i]); + + binding.matchArea.addView(tv); + + + match_latest_values[i].add_individual_view(binding.matchArea, psda.data.array[i]); } + }catch (Exception e){ + e.printStackTrace(); + AlertManager.alert("Warning!", "Failure to load file " + files[matchIndex]); } + } @@ -332,7 +287,7 @@ public class TeamsFragment extends Fragment { - public void add_compiled_views(LinearLayout ll, String[] files){ + public void add_compiled_views(String[] files){ dataType[][] data = new dataType[match_latest_values.length][files.length]; for (int i = 0; i < files.length; i++) { try { @@ -356,9 +311,9 @@ public class TeamsFragment extends Fragment { tv.setGravity(Gravity.CENTER_HORIZONTAL); tv.setText(match_latest_values[i].name); tv.setTextSize(30); - ll.addView(tv); + binding.matchArea.addView(tv); - match_latest_values[i].add_compiled_view(ll, data[i]); + match_latest_values[i].add_compiled_view(binding.matchArea, data[i]); } } @@ -366,7 +321,7 @@ public class TeamsFragment extends Fragment { - public void add_history_views(LinearLayout ll, String[] files){ + public void add_history_views(String[] files){ dataType[][] data = new dataType[match_latest_values.length][files.length]; for (int i = 0; i < files.length; i++) { try { @@ -390,9 +345,9 @@ public class TeamsFragment extends Fragment { tv.setGravity(Gravity.CENTER_HORIZONTAL); tv.setText(match_latest_values[i].name); tv.setTextSize(30); - ll.addView(tv); + binding.matchArea.addView(tv); - match_latest_values[i].add_history_view(ll, data[i]); + match_latest_values[i].add_history_view(binding.matchArea, data[i]); } } } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/EventFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/EventFragment.java new file mode 100644 index 0000000..67f64f2 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/EventFragment.java @@ -0,0 +1,383 @@ +package com.ridgebotics.ridgescout.ui.scouting; + +import static android.widget.LinearLayout.HORIZONTAL; +import static com.ridgebotics.ridgescout.utility.DataManager.evcode; +import static com.ridgebotics.ridgescout.utility.DataManager.event; + +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.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TableRow; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.fragment.app.Fragment; + +import com.ridgebotics.ridgescout.databinding.FragmentScoutingEventBinding; +import com.ridgebotics.ridgescout.types.frcTeam; +import com.ridgebotics.ridgescout.ui.CustomSpinnerView; +import com.ridgebotics.ridgescout.utility.DataManager; +import com.ridgebotics.ridgescout.utility.fileEditor; +import com.ridgebotics.ridgescout.types.frcEvent; +import com.ridgebotics.ridgescout.types.frcMatch; +import com.ridgebotics.ridgescout.utility.settingsManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class EventFragment extends Fragment { + FragmentScoutingEventBinding binding; + + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + + binding = FragmentScoutingEventBinding.inflate(inflater, container, false); + + reloadTable(); + + return binding.getRoot(); + } + + public void reloadTable() { + DataManager.reload_event(); + binding.teamsTable.removeAllViews(); + binding.teamsTable.setStretchAllColumns(true); + binding.matchTable.removeAllViews(); + binding.matchTable.setStretchAllColumns(true); + add_pit_scouting(event); + add_match_scouting(event); + } + + public static int color_found = 0x7f00ff00; + public static int color_not_found = 0x7f7f0000; + + private void addTableText(TableRow tr, String textStr){ + TextView text = new TextView(getContext()); + text.setTextSize(18); + text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center + text.setText(textStr); + tr.addView(text); + } + + public void add_pit_scouting(frcEvent event){ + + if(settingsManager.getCustomEvents()){ + binding.teamsMinusBtn.setVisibility(View.VISIBLE); + binding.teamsMinusBtn.setOnClickListener(view -> removeTeam()); + binding.teamsPlusBtn.setVisibility(View.VISIBLE); + binding.teamsPlusBtn.setOnClickListener(view -> addTeam()); + } + + int[] teams = new int[event.teams.size()]; + + for(int i = 0 ; i < event.teams.size(); i++){ + teams[i] = event.teams.get(i).teamNumber; + } + + Arrays.sort(teams); + + TableRow tr = null; + for(int i=0; i < event.teams.size(); i++){ +// frcTeam team = event.teams.get(i); + int num = teams[i]; + + if(i % 7 == 0){ + if(i != 0) + binding.teamsTable.addView(tr); + tr = new TableRow(getContext()); + } + + TextView text = new TextView(getContext()); + text.setTextSize(18); + text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + + text.setText(String.valueOf(num)); + if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){ + text.setBackgroundColor(color_found); + }else{ + text.setBackgroundColor(color_not_found); + } + tr.addView(text); + } + if(tr != null) + binding.teamsTable.addView(tr); + } + + + public void add_match_scouting(frcEvent event){ + + + if(settingsManager.getCustomEvents()){ + binding.matchesMinusBtn.setVisibility(View.VISIBLE); + binding.matchesMinusBtn.setOnClickListener(view -> removeMatch()); + binding.matchesPlusBtn.setVisibility(View.VISIBLE); + binding.matchesPlusBtn.setOnClickListener(view -> addMatch()); + } + + TableRow tr = new TableRow(getContext()); + addTableText(tr, "#"); + addTableText(tr, "Red-1"); + addTableText(tr, "Red-2"); + addTableText(tr, "Red-3"); + addTableText(tr, "Blue-1"); + addTableText(tr, "Blue-2"); + addTableText(tr, "Blue-3"); + binding.matchTable.addView(tr); + + for(frcMatch match : event.matches){ + + tr = new TableRow(getContext()); + addTableText(tr, String.valueOf(match.matchIndex)); +// + for(int i=0;i<6;i++){ + TextView text = new TextView(getContext()); + text.setTextSize(18); + text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + + int team_num; + String alliance_position; + + if(i < 3){ + team_num = match.redAlliance[i]; + alliance_position = "red-"+(i+1); + }else{ + team_num = match.blueAlliance[i-3]; + alliance_position = "blue-"+(i-2); + } + + text.setText(String.valueOf(team_num)); + if(fileEditor.fileExist(event.eventCode + "-" + match.matchIndex + "-" + alliance_position + "-" + team_num + ".matchscoutdata")){ + text.setBackgroundColor(color_found); + }else{ + text.setBackgroundColor(color_not_found); + } + tr.addView(text); + } + + binding.matchTable.addView(tr); + } + } + + public void addTeam(){ + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Add team"); + + LinearLayout ll = new LinearLayout(getContext()); + ll.setOrientation(LinearLayout.VERTICAL); + + EditText teamNum = new EditText(getContext()); + teamNum.setHint("Team Number"); + teamNum.setInputType(InputType.TYPE_CLASS_NUMBER); + ll.addView(teamNum); + + EditText teamName = new EditText(getContext()); + teamName.setHint("Team Name"); + ll.addView(teamName); + + EditText school = new EditText(getContext()); + school.setHint("School"); + ll.addView(school); + + EditText city = new EditText(getContext()); + city.setHint("City"); + ll.addView(city); + + EditText stateOrProv = new EditText(getContext()); + stateOrProv.setHint("State Or Province"); + ll.addView(stateOrProv); + + EditText country = new EditText(getContext()); + country.setHint("Country"); + ll.addView(country); + + EditText startingYear = new EditText(getContext()); + startingYear.setHint("Starting Year"); + startingYear.setInputType(InputType.TYPE_CLASS_NUMBER); + ll.addView(startingYear); + + builder.setView(ll); + + builder.setNeutralButton("Cancel", (dialogInterface, i) -> {}); + builder.setPositiveButton("OK", (dialogInterface, i) -> { + if(teamNum.getText().toString().isEmpty() || teamName.getText().toString().isEmpty()) return; + frcTeam team = new frcTeam(); + team.teamNumber = Integer.parseInt(teamNum.getText().toString()); + team.teamName = teamName.getText().toString(); + team.school = school.getText().toString(); + team.city = city.getText().toString(); + team.country = country.getText().toString(); + team.stateOrProv = stateOrProv.getText().toString(); + team.startingYear = safeToInt(startingYear.getText().toString()); + + event.teams.add(team); + fileEditor.setEvent(event); + reloadTable(); + }); + + builder.create().show(); + + } + public void removeTeam(){ + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Remove team"); + + CustomSpinnerView dropdown = new CustomSpinnerView(getContext()); + + List teamNums = new ArrayList<>(); + for(int i = 0 ;i < event.teams.size(); i++) + teamNums.add(String.valueOf(event.teams.get(i).teamNumber)); + + + dropdown.setTitle("Teams"); + dropdown.setOptions(teamNums, -1); + + builder.setView(dropdown); + + builder.setNeutralButton("Cancel", (dialogInterface, i) -> {}); + builder.setPositiveButton("OK", (dialogInterface, i) -> { + + int index = dropdown.getIndex(); + System.out.println(index); + if(!(index >= 0 && index < teamNums.size())) return; + + event.teams.remove(index); + fileEditor.setEvent(event); + reloadTable(); + }); + + builder.create().show(); + + } + public void addMatch(){ + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Add match"); + + List teamNums = new ArrayList<>(); + for(int i = 0 ;i < event.teams.size(); i++) + teamNums.add(String.valueOf(event.teams.get(i).teamNumber)); + + ScrollView sv = new ScrollView(getContext()); + sv.setLayoutDirection(ScrollView.SCROLL_AXIS_VERTICAL); + + LinearLayout ll = new LinearLayout(getContext()); + ll.setOrientation(LinearLayout.VERTICAL); + sv.addView(ll); + + CustomSpinnerView Red1dropdown = new CustomSpinnerView(getContext()); + Red1dropdown.setTitle("Red-1"); + Red1dropdown.setOptions(teamNums, -1); + ll.addView(Red1dropdown); + + CustomSpinnerView Red2dropdown = new CustomSpinnerView(getContext()); + Red2dropdown.setTitle("Red-2"); + Red2dropdown.setOptions(teamNums, -1); + ll.addView(Red2dropdown); + + CustomSpinnerView Red3dropdown = new CustomSpinnerView(getContext()); + Red3dropdown.setTitle("Red-3"); + Red3dropdown.setOptions(teamNums, -1); + ll.addView(Red3dropdown); + + + CustomSpinnerView Blue1dropdown = new CustomSpinnerView(getContext()); + Blue1dropdown.setTitle("Blue-1"); + Blue1dropdown.setOptions(teamNums, -1); + ll.addView(Blue1dropdown); + + CustomSpinnerView Blue2dropdown = new CustomSpinnerView(getContext()); + Blue2dropdown.setTitle("Blue-2"); + Blue2dropdown.setOptions(teamNums, -1); + ll.addView(Blue2dropdown); + + CustomSpinnerView Blue3dropdown = new CustomSpinnerView(getContext()); + Blue3dropdown.setTitle("Blue-3"); + Blue3dropdown.setOptions(teamNums, -1); + ll.addView(Blue3dropdown); + + builder.setView(sv); + + builder.setNeutralButton("Cancel", (dialogInterface, i) -> {}); + builder.setPositiveButton("OK", (dialogInterface, i) -> { + int red1index = Red1dropdown.getIndex(); + int red2index = Red2dropdown.getIndex(); + int red3index = Red3dropdown.getIndex(); + int blue1index = Blue1dropdown.getIndex(); + int blue2index = Blue2dropdown.getIndex(); + int blue3index = Blue3dropdown.getIndex(); + + if(red1index == -1 || red2index == -1 || red3index == -1 || blue1index == -1 || blue2index == -1 || blue3index == -1) return; + + frcMatch match = new frcMatch(); + match.matchIndex = event.matches.size() + 1; + match.redAlliance = new int[] { + event.teams.get(red1index).teamNumber, + event.teams.get(red2index).teamNumber, + event.teams.get(red3index).teamNumber + }; + match.blueAlliance = new int[] { + event.teams.get(blue1index).teamNumber, + event.teams.get(blue2index).teamNumber, + event.teams.get(blue3index).teamNumber + }; + + event.matches.add(match); + fileEditor.setEvent(event); + reloadTable(); + }); + + builder.create().show(); + + + + + } + public void removeMatch(){ + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Remove match"); + + List matches = new ArrayList<>(); + for(int i = 0 ;i < event.matches.size(); i++) { + frcMatch match = event.matches.get(i); + matches.add(match.matchIndex + " - " + Arrays.toString(match.redAlliance) + ", " + Arrays.toString(match.blueAlliance)); + } + + CustomSpinnerView dropdown = new CustomSpinnerView(getContext()); + dropdown.setTitle("Matches"); + dropdown.setOptions(matches, -1); + + builder.setView(dropdown); + + builder.setNeutralButton("Cancel", (dialogInterface, i) -> {}); + builder.setPositiveButton("OK", (dialogInterface, i) -> { + if(dropdown.getIndex() == -1) return; + event.matches.remove(dropdown.getIndex()); + fileEditor.setEvent(event); + reloadTable(); + }); + + builder.create().show(); + + } + + + public int safeToInt(String str){ + try{ + return Integer.parseInt(str); + }catch (Exception e){ + return 0; + } + } +} diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java index caec176..02befe8 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java @@ -14,6 +14,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.google.android.material.divider.MaterialDivider; +import com.ridgebotics.ridgescout.ui.ToggleTitleView; import com.ridgebotics.ridgescout.utility.settingsManager; import com.ridgebotics.ridgescout.databinding.FragmentScoutingMatchBinding; import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter; @@ -63,10 +65,6 @@ public class MatchScoutingFragment extends Fragment { - - cur_match_num = settingsManager.getMatchNum(); - update_match_num(); - binding.nextButton.setOnClickListener(v -> { if(edited) save(); settingsManager.setMatchNum(cur_match_num+1); @@ -103,6 +101,14 @@ public class MatchScoutingFragment extends Fragment { // if(edited) save(); // }); + cur_match_num = settingsManager.getMatchNum(); + + if(cur_match_num >= event.matches.size()) { + cur_match_num = 0; + settingsManager.setMatchNum(0); + } + + update_match_num(); create_fields(); update_scouting_data(); @@ -134,15 +140,10 @@ public class MatchScoutingFragment extends Fragment { int cur_match_num; String username; String filename; - boolean edited = false; - - TextView[] titles; - + ToggleTitleView[] titles; AutoSaveManager asm = new AutoSaveManager(this::save); - ArrayList dataTypes; - public void save(){ @@ -186,48 +187,41 @@ public class MatchScoutingFragment extends Fragment { asm.stop(); } - titles = new TextView[DataManager.match_latest_values.length]; + titles = new ToggleTitleView[DataManager.match_latest_values.length]; for(int i = 0 ; i < DataManager.match_latest_values.length; i++) { - final TextView tv = new TextView(getContext()); - tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - tv.setText(DataManager.match_latest_values[i].name); - tv.setPadding(8,8,8,8); - tv.setTextSize(24); - titles[i] = tv; + binding.MatchScoutArea.addView(new MaterialDivider(getContext())); - default_text_color = tv.getCurrentTextColor(); - final View v = DataManager.match_latest_values[i].createView(getContext(), new Function() { - @Override - public Integer apply(dataType dataType) { -// edited = true; - if(asm.isRunning) - update_asm(); - return 0; - } + final ToggleTitleView ttv = new ToggleTitleView(getContext()); + ttv.setTitle(DataManager.match_latest_values[i].name); + ttv.setDescription(DataManager.match_latest_values[i].description); + titles[i] = ttv; + + + final View v = DataManager.match_latest_values[i].createView(getContext(), dataType -> { +// edited = true; + if(asm.isRunning) + update_asm(); + return 0; }); - binding.MatchScoutArea.addView(tv); + binding.MatchScoutArea.addView(ttv); int fi = i; - tv.setOnClickListener(p -> { -// boolean blank = !latest_values[fi].getViewValue().isNull(); -// System.out.println(blank); + ttv.setOnToggleListener(enabled -> { if(asm.isRunning) update_asm(); - if(!DataManager.match_latest_values[fi].isBlank){ - tv.setBackgroundColor(0xffff0000); - tv.setTextColor(0xff000000); +// System.out.println("Checked!"); + + if(enabled){ DataManager.match_latest_values[fi].nullify(); - }else{ - tv.setBackgroundColor(0x00000000); - tv.setTextColor(default_text_color); + }else DataManager.match_latest_values[fi].setViewValue(DataManager.match_latest_values[fi].default_value); - } }); + binding.MatchScoutArea.addView(v); } } @@ -297,6 +291,13 @@ public class MatchScoutingFragment extends Fragment { frcMatch match = event.matches.get(cur_match_num); frcTeam team = get_team(match); + if(team == null) { + AlertManager.error("This team does not exist!"); + binding.teamName.setText("ERROR!"); + binding.teamDescription.setText("ERROR!"); + return; + } + binding.teamName.setText(team.teamName); binding.teamDescription.setText(team.getDescription()); @@ -331,8 +332,7 @@ public class MatchScoutingFragment extends Fragment { inputType input = DataManager.match_latest_values[i]; input.setViewValue(input.default_value); - titles[i].setBackgroundColor(0x00000000); - titles[i].setTextColor(default_text_color); + titles[i].enable(); } } @@ -343,6 +343,7 @@ public class MatchScoutingFragment extends Fragment { ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues); dataType[] types = psdr.data.array; + for(int i = 0; i < DataManager.match_latest_values.length; i++){ // types[i] = latest_values[i].getViewValue(); try { @@ -352,14 +353,8 @@ public class MatchScoutingFragment extends Fragment { DataManager.match_latest_values[i].setViewValue(DataManager.match_latest_values[i].default_value); } + titles[i].setEnabled(DataManager.match_latest_values[i].isBlank); - if(DataManager.match_latest_values[i].isBlank){ - titles[i].setBackgroundColor(0xffff0000); - titles[i].setTextColor(0xff000000); - }else{ - titles[i].setBackgroundColor(0x00000000); - titles[i].setTextColor(default_text_color); - } } } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java index 4975f68..0aab0fd 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java @@ -15,6 +15,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.google.android.material.divider.MaterialDivider; +import com.ridgebotics.ridgescout.ui.ToggleTitleView; import com.ridgebotics.ridgescout.utility.AlertManager; import com.ridgebotics.ridgescout.utility.settingsManager; import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding; @@ -59,7 +61,7 @@ public class PitScoutingFragment extends Fragment { String filename; String username; - TextView[] titles; + ToggleTitleView[] titles; AutoSaveManager asm = new AutoSaveManager(this::save); @@ -133,38 +135,31 @@ public class PitScoutingFragment extends Fragment { } - private int default_text_color = 0; - private void create_fields() { if(asm.isRunning){ asm.stop(); } - titles = new TextView[pit_latest_values.length]; + titles = new ToggleTitleView[pit_latest_values.length]; for(int i = 0 ; i < pit_latest_values.length; i++) { - TextView tv = new TextView(getContext()); - tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - tv.setText(pit_latest_values[i].name); - tv.setTextSize(24); - tv.setPadding(8,8,8,8); - titles[i] = tv; - binding.pitScoutArea.addView(tv); + binding.pitScoutArea.addView(new MaterialDivider(getContext())); + + ToggleTitleView ttv = new ToggleTitleView(getContext()); + ttv.setTitle(pit_latest_values[i].name); + ttv.setDescription(pit_latest_values[i].description); + titles[i] = ttv; + binding.pitScoutArea.addView(ttv); - default_text_color = tv.getCurrentTextColor(); int fi = i; - tv.setOnClickListener(p -> { + ttv.setOnToggleListener(enabled -> { update_asm(); - if(!pit_latest_values[fi].isBlank){ - tv.setBackgroundColor(0xffff0000); - tv.setTextColor(0xff000000); + if(enabled){ pit_latest_values[fi].nullify(); }else{ - tv.setBackgroundColor(0x00000000); - tv.setTextColor(default_text_color); pit_latest_values[fi].setViewValue(pit_latest_values[fi].default_value); } }); @@ -187,9 +182,7 @@ public class PitScoutingFragment extends Fragment { for(int i = 0; i < pit_latest_values.length; i++){ inputType input = pit_latest_values[i]; input.setViewValue(input.default_value); - - titles[i].setBackgroundColor(0x00000000); - titles[i].setTextColor(default_text_color); + titles[i].enable(); } } @@ -199,15 +192,12 @@ public class PitScoutingFragment extends Fragment { dataType[] types = psdr.data.array; for(int i = 0; i < pit_latest_values.length; i++){ -// types[i] = latest_values[i].getViewValue(); pit_latest_values[i].setViewValue(types[i]); if(pit_latest_values[i].isBlank){ - titles[i].setBackgroundColor(0xffff0000); - titles[i].setTextColor(0xff000000); + titles[i].disable(); }else{ - titles[i].setBackgroundColor(0x00000000); - titles[i].setTextColor(default_text_color); + titles[i].enable(); } } } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/ScoutingFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/ScoutingFragment.java index 9f29e87..7ada2ff 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/ScoutingFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/ScoutingFragment.java @@ -1,28 +1,35 @@ package com.ridgebotics.ridgescout.ui.scouting; +import static android.widget.LinearLayout.VERTICAL; import static androidx.navigation.fragment.FragmentKt.findNavController; import static com.ridgebotics.ridgescout.utility.DataManager.event; +import android.app.AlertDialog; import android.os.Bundle; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.ridgebotics.ridgescout.R; -import com.ridgebotics.ridgescout.utility.AlertManager; +import com.ridgebotics.ridgescout.types.frcEvent; +import com.ridgebotics.ridgescout.utility.fileEditor; import com.ridgebotics.ridgescout.utility.settingsManager; import com.ridgebotics.ridgescout.databinding.FragmentScoutingBinding; import com.ridgebotics.ridgescout.types.frcTeam; import com.ridgebotics.ridgescout.ui.TeamSelectorFragment; import com.ridgebotics.ridgescout.utility.DataManager; +import java.util.ArrayList; + public class ScoutingFragment extends Fragment { private FragmentScoutingBinding binding; @@ -35,37 +42,78 @@ public class ScoutingFragment extends Fragment { binding.buttons.setVisibility(View.VISIBLE); - String evcode = settingsManager.getEVCode(); - DataManager.reload_event(); + if(settingsManager.getCustomEvents()){ + binding.eventAddButton.setVisibility(View.VISIBLE); + binding.eventAddButton.setOnClickListener(view -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Chose event name"); + + LinearLayout layout = new LinearLayout(getContext()); + layout.setOrientation(VERTICAL); + EditText eventName = new EditText(getContext()); + eventName.setHint("Event Name"); + EditText eventCode = new EditText(getContext()); + eventCode.setHint("Event Code"); + layout.addView(eventName); + layout.addView(eventCode); + + + builder.setPositiveButton("Create", (dialog, which) -> { + String name = eventName.getText().toString(); + String code = eventCode.getText().toString(); + if(name.isEmpty() || code.isEmpty()) return; + + frcEvent event = new frcEvent(); + event.name = name; + event.eventCode = code; + event.teams = new ArrayList<>(); + event.matches = new ArrayList<>(); + + fileEditor.setEvent(event); + + + }); + builder.setNeutralButton("Cancel", (dialog, which) -> {}); + + builder.setView(layout); + builder.create().show(); + }); + } + if(event == null){ binding.noEventError.setVisibility(View.VISIBLE); binding.matchScoutingButton.setEnabled(false); binding.pitScoutingButton.setEnabled(false); - binding.statusButton.setEnabled(false); + binding.eventButton.setEnabled(false); is_main_page = false; return binding.getRoot(); } + if(event.matches.isEmpty()){ + binding.matchScoutingButton.setEnabled(false); + } + + if(event.teams.isEmpty()){ + binding.pitScoutingButton.setEnabled(false); + } + binding.matchScoutingButton.setOnClickListener(v -> { findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_match_scouting); }); binding.pitScoutingButton.setOnClickListener(v -> { TeamSelectorFragment.setPits_mode(true); - TeamSelectorFragment.setOnSelect(new TeamSelectorFragment.onTeamSelected() { - @Override - public void onSelect(TeamSelectorFragment self, frcTeam team) { - PitScoutingFragment.setTeam(team); - findNavController(self).navigate(R.id.action_navigation_team_selector_to_navigation_pit_scouting); - } + TeamSelectorFragment.setOnSelect((self, team) -> { + PitScoutingFragment.setTeam(team); + findNavController(self).navigate(R.id.action_navigation_team_selector_to_navigation_pit_scouting); }); findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_team_selector); }); - binding.statusButton.setOnClickListener(v -> { - findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_scouting_status); + binding.eventButton.setOnClickListener(v -> { + findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_scouting_event); }); return binding.getRoot(); @@ -81,23 +129,17 @@ public class ScoutingFragment extends Fragment { getView().setFocusableInTouchMode(true); getView().requestFocus(); - getView().setOnKeyListener(new View.OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { + getView().setOnKeyListener((v, keyCode, event) -> { - if (event.getAction() == KeyEvent.ACTION_UP - && keyCode == KeyEvent.KEYCODE_BACK - && !is_main_page){ + if (event.getAction() == KeyEvent.ACTION_UP + && keyCode == KeyEvent.KEYCODE_BACK + && !is_main_page){ -// binding.buttons.setVisibility(View.VISIBLE); -// binding.matchScoutingView.setVisibility(View.GONE); -// binding.pitScoutingView.setVisibility(View.GONE); - is_main_page = true; + is_main_page = true; - return true; - } - return false; + return true; } + return false; }); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/StatusFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/StatusFragment.java deleted file mode 100644 index ceb47b8..0000000 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/StatusFragment.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.ridgebotics.ridgescout.ui.scouting; - -import static com.ridgebotics.ridgescout.utility.DataManager.event; - -import android.os.Bundle; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TableRow; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; - -import com.ridgebotics.ridgescout.databinding.FragmentScoutingStatusBinding; -import com.ridgebotics.ridgescout.utility.DataManager; -import com.ridgebotics.ridgescout.utility.fileEditor; -import com.ridgebotics.ridgescout.types.frcEvent; -import com.ridgebotics.ridgescout.types.frcMatch; - -import java.util.Arrays; - -public class StatusFragment extends Fragment { - FragmentScoutingStatusBinding binding; - - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - - binding = FragmentScoutingStatusBinding.inflate(inflater, container, false); - - DataManager.reload_event(); - binding.matchTable.removeAllViews(); - binding.matchTable.setStretchAllColumns(true); - add_pit_scouting(event); - add_match_scouting(event); - - return binding.getRoot(); - } - public static int color_found = 0x7f00ff00; - public static int color_not_found = 0x7f7f0000; - - private void addTableText(TableRow tr, String textStr){ - TextView text = new TextView(getContext()); - text.setTextSize(18); - text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center - text.setText(textStr); - tr.addView(text); - } - - public void add_pit_scouting(frcEvent event){ - TextView tv = new TextView(getContext()); - tv.setLayoutParams(new TableRow.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText("Pit Scouting"); - tv.setTextSize(28); - binding.matchTable.addView(tv); - - int[] teams = new int[event.teams.size()]; - - for(int i = 0 ; i < event.teams.size(); i++){ - teams[i] = event.teams.get(i).teamNumber; - } - - Arrays.sort(teams); - - TableRow tr = null; - for(int i=0; i < event.teams.size(); i++){ -// frcTeam team = event.teams.get(i); - int num = teams[i]; - - if(i % 7 == 0){ - if(i != 0) - binding.matchTable.addView(tr); - tr = new TableRow(getContext()); - } - - TextView text = new TextView(getContext()); - text.setTextSize(18); - text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - - text.setText(String.valueOf(num)); - if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){ - text.setBackgroundColor(color_found); - }else{ - text.setBackgroundColor(color_not_found); - } - tr.addView(text); - } - if(tr != null) - binding.matchTable.addView(tr); - } - - - public void add_match_scouting(frcEvent event){ - - TextView tv = new TextView(getContext()); - tv.setLayoutParams(new TableRow.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setText("Match Scouting"); - tv.setTextSize(28); - binding.matchTable.addView(tv); - - TableRow tr = new TableRow(getContext()); - addTableText(tr, "#"); - addTableText(tr, "Red-1"); - addTableText(tr, "Red-2"); - addTableText(tr, "Red-3"); - addTableText(tr, "Blue-1"); - addTableText(tr, "Blue-2"); - addTableText(tr, "Blue-3"); - binding.matchTable.addView(tr); - - for(frcMatch match : event.matches){ - - tr = new TableRow(getContext()); - addTableText(tr, String.valueOf(match.matchIndex)); -// - for(int i=0;i<6;i++){ - TextView text = new TextView(getContext()); - text.setTextSize(18); - text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - - int team_num; - String alliance_position; - - if(i < 3){ - team_num = match.redAlliance[i]; - alliance_position = "red-"+(i+1); - }else{ - team_num = match.blueAlliance[i-3]; - alliance_position = "blue-"+(i-2); - } - - text.setText(String.valueOf(team_num)); - if(fileEditor.fileExist(event.eventCode + "-" + match.matchIndex + "-" + alliance_position + "-" + team_num + ".matchscoutdata")){ - text.setBackgroundColor(color_found); - }else{ - text.setBackgroundColor(color_not_found); - } - tr.addView(text); - } - -// addTableText(tr, String.valueOf(match.matchIndex)); -// addTableText(tr, String.valueOf(match.blueAlliance[0])); -// addTableText(tr, String.valueOf(match.blueAlliance[1])); -// addTableText(tr, String.valueOf(match.blueAlliance[2])); -// addTableText(tr, String.valueOf(match.redAlliance[0])); -// addTableText(tr, String.valueOf(match.redAlliance[1])); -// addTableText(tr, String.valueOf(match.redAlliance[2])); -// if (toggle) { -// tr.setBackgroundColor(0x30000000); -// } -// -// toggle = !toggle; - binding.matchTable.addView(tr); - } - } -} diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/settingsFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/settingsFragment.java index 7671f18..6e294d1 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/settingsFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/settingsFragment.java @@ -1,229 +1,48 @@ package com.ridgebotics.ridgescout.ui.settings; -import static android.text.InputType.TYPE_CLASS_NUMBER; import static com.ridgebotics.ridgescout.utility.settingsManager.AllyPosKey; -import static com.ridgebotics.ridgescout.utility.settingsManager.FTPEnabled; -import static com.ridgebotics.ridgescout.utility.settingsManager.FTPSendMetaFiles; -import static com.ridgebotics.ridgescout.utility.settingsManager.FTPServer; +import static com.ridgebotics.ridgescout.utility.settingsManager.CustomEventsKey; import static com.ridgebotics.ridgescout.utility.settingsManager.SelEVCodeKey; -import static com.ridgebotics.ridgescout.utility.settingsManager.TeamNumKey; import static com.ridgebotics.ridgescout.utility.settingsManager.UnameKey; import static com.ridgebotics.ridgescout.utility.settingsManager.WifiModeKey; +import static com.ridgebotics.ridgescout.utility.settingsManager.YearNumKey; import static com.ridgebotics.ridgescout.utility.settingsManager.defaults; import static com.ridgebotics.ridgescout.utility.settingsManager.getEditor; import static com.ridgebotics.ridgescout.utility.settingsManager.prefs; -import android.app.AlertDialog; +import android.content.Context; import android.os.Bundle; import android.text.Editable; +import android.text.InputType; import android.text.TextWatcher; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TableRow; +import android.widget.LinearLayout; +import android.widget.TableLayout; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import com.google.android.material.divider.MaterialDivider; +import com.google.android.material.card.MaterialCardView; +import com.google.android.material.checkbox.MaterialCheckBox; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; import com.ridgebotics.ridgescout.databinding.FragmentSettingsBinding; -import com.ridgebotics.ridgescout.types.data.intType; +import com.ridgebotics.ridgescout.ui.CustomSpinnerPopup; +import com.ridgebotics.ridgescout.ui.CustomSpinnerView; import com.ridgebotics.ridgescout.utility.fileEditor; import com.ridgebotics.ridgescout.utility.settingsManager; -import com.skydoves.powerspinner.IconSpinnerAdapter; -import com.skydoves.powerspinner.IconSpinnerItem; -import com.skydoves.powerspinner.OnSpinnerItemSelectedListener; -import com.skydoves.powerspinner.PowerSpinnerView; -import com.skydoves.powerspinner.SpinnerGravity; - -import org.checkerframework.checker.units.qual.C; - import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; -import java.util.stream.Stream; public class settingsFragment extends Fragment { private FragmentSettingsBinding binding; - private android.widget.ScrollView ScrollArea; - private android.widget.TableLayout Table; - -// private void setDropdownItems(Spinner dropdown, String[] items){ -// ArrayAdapter adapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_spinner_item, items); -// dropdown.setAdapter(adapter); -// } - - private View[] concatArrays(View[] a, View[] b){ - return Stream.of(a, b).flatMap(Stream::of).toArray(View[]::new); - } - - - private View[] addViews(View[] a){ - for(int i = 0; i < a.length; i++){ - binding.SettingsTable.addView(a[i]); - } - return a; - } - - private int safeToInt(String num){ - if(num.isEmpty()) - return 0; - try { - return Integer.parseInt(num); - }catch (NumberFormatException e){ - return 0; - } - } - - private View[] createHeading(String name){ - TextView tv = new TextView(getContext()); - tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); - TableRow.LayoutParams params = new TableRow.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ); - params.topMargin = 100; - tv.setLayoutParams(params); - tv.setTextSize(20); - tv.setText(name); - - View divider = new MaterialDivider(getContext()); - - return new View[]{tv, divider}; - } - - private View[] addStringEdit(String name, String key){ - View[] heading = createHeading(name); - EditText et = new EditText(getContext()); - et.setText(prefs.getString(key, (String) defaults.get(key))); - - et.addTextChangedListener(new TextWatcher() { - - public void afterTextChanged(Editable s) { - getEditor().putString(key, s.toString()).apply(); - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - public void onTextChanged(CharSequence s, int start, int before, int count) {} - }); - return concatArrays(heading, new View[]{et}); - } - - private View[] addNumberEdit(String name, String key){ - View[] heading = createHeading(name); - EditText et = new EditText(getContext()); - et.setText(String.valueOf(prefs.getInt(key, (Integer) defaults.get(key)))); - et.setInputType(TYPE_CLASS_NUMBER); - - et.addTextChangedListener(new TextWatcher() { - - public void afterTextChanged(Editable s) { - getEditor().putInt(key, safeToInt(s.toString())).apply(); - } - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - public void onTextChanged(CharSequence s, int start, int before, int count) {} - }); - return concatArrays(heading, new View[]{et}); - } - - private PowerSpinnerView addDropdownEdit(String name, String[] options, String key){ - PowerSpinnerView dropdown = new PowerSpinnerView(getContext()); - - List iconSpinnerItems = new ArrayList<>(); - for(int i = 0; i < options.length; i++){ - iconSpinnerItems.add(new IconSpinnerItem(options[i])); - } - IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown); - - dropdown.setGravity(Gravity.CENTER); - - dropdown.setSpinnerAdapter(iconSpinnerAdapter); - dropdown.setItems(iconSpinnerItems); - dropdown.setHint("Unselected"); - - dropdown.setPadding(10,20,10,20); - dropdown.setBackgroundColor(0xf0000000); - dropdown.setTextColor(0xff00ff00); - dropdown.setTextSize(14.5f); - dropdown.setArrowGravity(SpinnerGravity.END); - dropdown.setArrowPadding(8); - dropdown.setSpinnerPopupElevation(14); - - return dropdown; - } - - private View[] addDropdownByString(String name, String[] options, String key){ - View[] heading = createHeading(name); - PowerSpinnerView dropdown = addDropdownEdit(name, options, key); - int index = Arrays.asList(options).indexOf(prefs.getString(key, (String) defaults.get(key))); - System.out.println(index); - - if(options.length != 0 && index != -1){ - dropdown.selectItemByIndex(index); - } - - dropdown.setOnSpinnerItemSelectedListener( - (OnSpinnerItemSelectedListener) - (oldIndex, oldItem, newIndex, newItem) -> getEditor().putString(key, newItem.getText().toString()).apply() - ); - - return concatArrays(heading, new View[]{dropdown}); - } - - private View[] addDropdownByIndex(String name, String[] options, String key){ - View[] heading = createHeading(name); - PowerSpinnerView dropdown = addDropdownEdit(name, options, key); - - int index = prefs.getInt(key, (Integer) defaults.get(key)); - - if(dropdown.length() != 0 && index != -1){ - dropdown.selectItemByIndex(index); - } - - dropdown.setOnSpinnerItemSelectedListener( - (OnSpinnerItemSelectedListener) - (oldIndex, oldItem, newIndex, newItem) -> getEditor().putInt(key, newIndex).apply() - ); - - return concatArrays(heading, new View[]{dropdown}); - } - - private View[] addCheckbox(String name, String key, View[] dependency){ - CheckBox cb = new CheckBox(getContext()); - cb.setText(name); - cb.setTextSize(22); - boolean checked = prefs.getBoolean(key, (Boolean) defaults.get(key)); - cb.setChecked(checked); - - if(dependency != null && !checked){ - for(int i = 0; i < dependency.length; i++){ - dependency[i].setVisibility(View.GONE); - } - } - - cb.setOnCheckedChangeListener((buttonView, isChecked) -> { - getEditor().putBoolean(key, isChecked).apply(); - if(dependency != null){ - for(int i = 0; i < dependency.length; i++){ - dependency[i].setVisibility(isChecked ? View.VISIBLE : View.GONE); - System.out.println(dependency[i]); - } - } - }); - - return new View[]{new MaterialDivider(getContext()), cb}; - } public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -234,20 +53,28 @@ public class settingsFragment extends Fragment { String[] alliance_pos_list = new String[]{"red-1", "red-2", "red-3", "blue-1", "blue-2", "blue-3"}; - addViews(addStringEdit("Username", UnameKey)); - addViews(addDropdownByString("Event Code", fileEditor.getEventList().toArray(new String[0]), SelEVCodeKey)); - addViews(addDropdownByString("Alliance Position", alliance_pos_list, AllyPosKey)); - addViews(addNumberEdit("Team Number", TeamNumKey)); + SettingsManager manager = new SettingsManager(getContext()); - View[] FTPDependency = concatArrays( - addCheckbox("Send Meta Files", FTPSendMetaFiles, new View[]{}), - addStringEdit("FTP Server", FTPServer) - ); - View[] WifiDependency = addCheckbox("FTP Enabled", FTPEnabled, FTPDependency); - addViews(addCheckbox("Wifi Mode", WifiModeKey, concatArrays(FTPDependency, WifiDependency))); - addViews(WifiDependency); - addViews(FTPDependency); + manager.addItem(new CheckboxSettingsItem(CustomEventsKey, "Custom Events")); + + StringSettingsItem FTPServer = new StringSettingsItem(settingsManager.FTPServer, "FTP Server (Sync)"); + manager.addItem(FTPServer); + CheckboxSettingsItem FTPSendMetaFiles = new CheckboxSettingsItem(settingsManager.FTPSendMetaFiles, "Sync meta files"); + manager.addItem(FTPSendMetaFiles); + CheckboxSettingsItem FTPEnabled = new CheckboxSettingsItem(settingsManager.FTPEnabled, "FTP Enabled", FTPServer, FTPSendMetaFiles); + manager.addItem(FTPEnabled); + + manager.addItem(new CheckboxSettingsItem(WifiModeKey, "Wifi Mode", FTPEnabled)); + + manager.addItem(new NumberSettingsItem(YearNumKey, "Year", 0, 9999)); + + manager.addItem(new DropdownSettingsItem(AllyPosKey, "Alliance Pos", alliance_pos_list)); + manager.addItem(new DropdownSettingsItem(SelEVCodeKey, "Event Code", fileEditor.getEventList().toArray(new String[0]))); + manager.addItem(new StringSettingsItem(UnameKey, "Username")); + + manager.getView(binding.SettingsTable); + return root; } @@ -258,4 +85,265 @@ public class settingsFragment extends Fragment { super.onDestroyView(); binding = null; } + + + + + + + + + + + + + + + public abstract class SettingsItem { + private String key; + private String title; + private T defaultValue; + + public SettingsItem(String key, String title, T defaultValue) { + this.key = key; + this.title = title; + this.defaultValue = defaultValue; + } + + public abstract View createView(Context context); + public abstract T getValue(); + + public String getKey() { return key; } + public String getTitle() { return title; } + public T getDefaultValue() { return defaultValue; } + public abstract void setEnabled(boolean enabled); + } + + public class StringSettingsItem extends SettingsItem { + public StringSettingsItem(String key, String title) { + super(key, title, prefs.getString(key, (String) defaults.get(key))); + } + + TextInputEditText editText; + + @Override + public void setEnabled(boolean enabled){ + editText.setEnabled(enabled); + } + + @Override + public View createView(Context context) { + TextInputLayout textInputLayout = new TextInputLayout(context); + textInputLayout.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + editText = new TextInputEditText(context); + editText.setText(getValue()); + + editText.addTextChangedListener(new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + getEditor().putString(getKey(), s.toString()).apply(); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + }); + + textInputLayout.addView(editText); + return textInputLayout; + } + + @Override + public String getValue() { + return prefs.getString(getKey(), (String) defaults.get(getKey())); + } + } + + public class NumberSettingsItem extends SettingsItem { + private int min; + private int max; + + public NumberSettingsItem(String key, String title, int min, int max) { + super(key, title, prefs.getInt(key, (int) defaults.get(key))); + this.min = min; + this.max = max; + } + + TextInputEditText editText; + + @Override + public void setEnabled(boolean enabled){ + editText.setEnabled(enabled); + } + + @Override + public View createView(Context context) { + TextView titleView = new TextView(context); + titleView.setText(getTitle()); + titleView.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1); + + TextInputLayout textInputLayout = new TextInputLayout(context); + editText = new TextInputEditText(context); + + editText.setInputType(InputType.TYPE_CLASS_NUMBER); + editText.setText(String.valueOf(getValue())); + + editText.addTextChangedListener(new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + try { + int value = Integer.parseInt(s.toString()); + if (value >= min && value <= max) { + getEditor().putInt(getKey(), value).apply(); + } + } catch (NumberFormatException e) { + editText.setText(String.valueOf(getDefaultValue())); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + }); + + textInputLayout.addView(editText); + textInputLayout.addView(titleView); + return textInputLayout; + } + + @Override + public Integer getValue() { + return prefs.getInt(getKey(), (int) defaults.get(getKey())); + } + } + + public class DropdownSettingsItem extends SettingsItem { + private String[] options; + + private boolean enabled = true; + + @Override + public void setEnabled(boolean enabled){ + this.enabled = enabled; + } + + public DropdownSettingsItem(String key, String title, String[] options) { + super(key, title, prefs.getString(key, (String) defaults.get(key))); + this.options = options; + } + + @Override + public View createView(Context context) { + CustomSpinnerView dropdown = new CustomSpinnerView(getContext()); + dropdown.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + + + ArrayList optionsList = new ArrayList<>(Arrays.asList(options)); + + dropdown.setTitle(getTitle()); + dropdown.setOptions(optionsList, getValue()); + dropdown.setOption(getValue()); + + dropdown.setOnClickListener((item, index) -> { + getEditor().putString(getKey(), item).apply(); + }); + + return dropdown; + } + + @Override + public String getValue() { + return prefs.getString(getKey(), (String) defaults.get(getKey())); + } + } + + public class CheckboxSettingsItem extends SettingsItem { + private List> controlledItems; + + public CheckboxSettingsItem(String key, String title, SettingsItem... controlledItems) { + super(key, title, prefs.getBoolean(key, (Boolean) defaults.get(key))); + this.controlledItems = Arrays.asList(controlledItems); + } + + MaterialCheckBox checkBox; + + @Override + public void setEnabled(boolean enabled){ + checkBox.setEnabled(enabled); + for (SettingsItem item : controlledItems) { + item.setEnabled(enabled && checkBox.isChecked()); + } + } + + @Override + public View createView(Context context) { + checkBox = new MaterialCheckBox(context); + checkBox.setText(getTitle()); + checkBox.setChecked(getValue()); + checkBox.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + getEditor().putBoolean(getKey(), isChecked).apply(); + for (SettingsItem item : controlledItems) { + item.setEnabled(isChecked); + } + }); + + for (SettingsItem item : controlledItems) { + item.setEnabled(getValue()); + } + + return checkBox; + } + + @Override + public Boolean getValue() { + return prefs.getBoolean(getKey(), (Boolean) defaults.get(getKey())); + } + } + + public class SettingsManager { + private Context context; + private HashMap settings; + private List> items; +// private LinearLayout container; + + public SettingsManager(Context context) { + this.context = context; + this.items = new ArrayList<>(); +// this.container = new LinearLayout(context); +// this.container.setOrientation(LinearLayout.VERTICAL); +// this.container.setLayoutParams(new LinearLayout.LayoutParams( +// LinearLayout.LayoutParams.MATCH_PARENT, +// LinearLayout.LayoutParams.WRAP_CONTENT +// )); + } + + private final List views = new ArrayList<>(); + public void addItem(SettingsItem item) { + items.add(item); + + LinearLayout itemContainer = new LinearLayout(context); + itemContainer.setOrientation(LinearLayout.VERTICAL); + itemContainer.setPadding(32, 0, 32, 8); + + itemContainer.addView(item.createView(context)); + views.add(itemContainer); + } + + public void getView(LinearLayout layout) { + for(int i = views.size()-1; i >= 0; i--) + layout.addView(views.get(i)); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java index cafbcd1..7987259 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java @@ -27,27 +27,54 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TimeZone; public class FTPSync extends Thread { public static final String remoteBasePath = "/RidgeScout/"; public static final String timestampsFilename = "timestamps"; - public static long lastSyncTime = 0; + + + public static long lastSyncTime = 0; private static Date curSyncTime; + private static final long millisTolerance = 1000; + + private boolean after(Date a, Date b){ + return a.getTime() - b.getTime() > millisTolerance; + } + public interface onResult { void onResult(boolean error, int upCount, int downCount); } + public interface UpdateIndicator { + void onText(String text); + } + private static UpdateIndicator updateIndicator = text -> {}; + public static String text = ""; + private static void setUpdateIndicator(String m_text){ + text = m_text; + updateIndicator.onText(m_text); + } + public static void setOnUpdateIndicator(UpdateIndicator m_updateIndicator){ + updateIndicator = m_updateIndicator; + } - public onResult onResult; + private static onResult onResult = (error, upCount, downCount) -> {}; + public static void setOnResult(onResult result){ + onResult = result; + } - public static void sync(onResult onResult){ + private static boolean isRunning = false; + public static boolean getIsRunning(){return isRunning;} + + public static void sync(){ // DataManager.reload_event(); FTPSync ftpSync = new FTPSync(); - ftpSync.onResult = onResult; curSyncTime = new Date(); @@ -94,6 +121,7 @@ public class FTPSync extends Thread { public void run() { + isRunning = true; boolean sendMetaFiles = settingsManager.getFTPSendMetaFiles(); // Meta files @@ -118,7 +146,10 @@ public class FTPSync extends Thread { // Loop through local files and send all that are more recent if (localFiles != null) { - for (File localFile : localFiles) { + for (int i = 0; i < localFiles.length; i++) { + File localFile = localFiles[i]; + setUpdateIndicator("Uploading " + (i+1) + "/" + localFiles.length); + if(localFile.isDirectory()) continue; // Remove timestamts file if(localFile.getName().equals(timestampsFilename)) continue; @@ -127,20 +158,27 @@ public class FTPSync extends Thread { Date remoteTimestamp = remoteTimestamps.get(localFile.getName()); - if (remoteTimestamp == null || getLocalFileUtcTimestamp(localFile).after(remoteTimestamp)) { + Date localTimeStamp = getLocalFileUtcTimestamp(localFile); + + if (remoteTimestamp == null || after(localTimeStamp, remoteTimestamp)) { uploadFile(localFile); - System.out.println("Uploaded " + localFile.getName()); + System.out.println("Uploaded" + localFile.getName()); setLocalFileTimestamp(localFile, curSyncTime); remoteTimestamps.put(localFile.getName(), curSyncTime); upCount++; }else{ - System.out.println("Did not upload " + localFile.getName()); + System.out.println("Did not upload"); } } } - for (String remoteFile : remoteTimestamps.keySet()) { + Set keySet = remoteTimestamps.keySet(); + Iterator keyIt = keySet.iterator(); + for (int i = 0; i < keySet.size(); i++) { + String remoteFile = keyIt.next(); + setUpdateIndicator("Downloading " + (i+1) + "/" + keySet.size()); + File localFile = new File(baseDir, remoteFile); if(remoteFile.equals(timestampsFilename)) continue; // Remove meta files if the option is disabled @@ -151,15 +189,25 @@ public class FTPSync extends Thread { //// // System.out.println("- " + t1 + (t1.after(t2) ? ">" : "<") + t2); - if (!localFile.exists() || remoteTimestamps.get(remoteFile).after(getLocalFileUtcTimestamp(localFile))) { + Date localTimeStamp = getLocalFileUtcTimestamp(localFile); + Date remoteTimestamp = remoteTimestamps.get(remoteFile); + + + + if (!localFile.exists() || (after(remoteTimestamp, localTimeStamp) && !localTimeStamp.equals(remoteTimestamp))) { downloadFile(remoteFile, localFile); + System.out.println("Downloaded " + localFile.getName()); + + if(!localFile.exists()) System.out.println("Not exist"); + else if(after(remoteTimestamp, localTimeStamp)) System.out.println("Before: " + (localTimeStamp.getTime()-remoteTimestamp.getTime())); + // Date d = getUtcTimestamp(remoteFile); setLocalFileTimestamp(localFile, remoteTimestamps.get(localFile.getName())); // remoteTimestamps.put(remoteFile, curSyncTime); downCount++; }else{ - System.out.println("Did not download " + remoteFile); + System.out.println("Did not download"); } } @@ -168,9 +216,13 @@ public class FTPSync extends Thread { } catch (Exception e) { AlertManager.error(e); onResult.onResult(true, upCount, downCount); + setUpdateIndicator("ERROR!"); } finally { onResult.onResult(false, upCount, downCount); + setUpdateIndicator("Finished"); } + + isRunning = false; } private boolean setTimestamps(Map timestamps){ diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java index 38d799c..8e592b6 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java @@ -20,6 +20,7 @@ import com.ridgebotics.ridgescout.databinding.FragmentTransferFileSelectorBindin import com.ridgebotics.ridgescout.types.file; import com.ridgebotics.ridgescout.utility.AlertManager; import com.ridgebotics.ridgescout.utility.ByteBuilder; +import com.ridgebotics.ridgescout.utility.DataManager; import com.ridgebotics.ridgescout.utility.fileEditor; import java.util.ArrayList; @@ -42,6 +43,7 @@ public class FileSelectorFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentTransferFileSelectorBinding.inflate(inflater, container, false); + DataManager.reload_event(); meta_string_array = new String[]{ "matches.fields", diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TBAFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TBAFragment.java index e1017f1..08fa460 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TBAFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TBAFragment.java @@ -22,6 +22,7 @@ import com.ridgebotics.ridgescout.types.frcMatch; import com.ridgebotics.ridgescout.types.frcTeam; import com.ridgebotics.ridgescout.utility.fileEditor; import com.ridgebotics.ridgescout.utility.JSONUtil; +import com.ridgebotics.ridgescout.utility.settingsManager; import org.json.JSONArray; import org.json.JSONException; @@ -35,13 +36,13 @@ import java.util.Comparator; import java.util.Date; public class TBAFragment extends Fragment { - private final String TBAAddress = "https://www.thebluealliance.com/api/v3/"; - private final String TBAHeader = "X-TBA-Auth-Key: tjEKSZojAU2pgbs2mBt06SKyOakVhLutj3NwuxLTxPKQPLih11aCIwRIVFXKzY4e"; + private static final String TBAAddress = "https://www.thebluealliance.com/api/v3/"; + private static final String TBAHeader = "X-TBA-Auth-Key: tjEKSZojAU2pgbs2mBt06SKyOakVhLutj3NwuxLTxPKQPLih11aCIwRIVFXKzY4e"; private android.widget.TableLayout Table; private FragmentTransferTbaBinding binding; - private static final int year = 2024; + private final int year = settingsManager.getYearNum(); public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java index dd3c597..aa48c92 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java @@ -20,6 +20,8 @@ import com.ridgebotics.ridgescout.databinding.FragmentTransferBinding; import com.ridgebotics.ridgescout.ui.transfer.bluetooth.BluetoothSenderFragment; import com.ridgebotics.ridgescout.ui.transfer.codes.CodeGeneratorView; +import org.apache.commons.net.ftp.FTP; + import java.util.Date; public class TransferFragment extends Fragment { @@ -81,12 +83,22 @@ public class TransferFragment extends Fragment { binding.SyncButton.setOnClickListener(v -> { binding.SyncButton.setEnabled(false); - FTPSync.sync((error, upcount, downcount) -> getActivity().runOnUiThread(() -> { -// binding.SyncButton.setEnabled(true); - AlertManager.toast((!error ? "Synced! " : "Error Syncing. ") + upcount + " Up " + downcount + " Down"); - })); + FTPSync.sync(); }); + if(FTPSync.getIsRunning()) + binding.SyncButton.setEnabled(false); + + FTPSync.setOnResult((error, upcount, downcount) -> { + if (getActivity() != null) + getActivity().runOnUiThread(() -> { + binding.SyncButton.setEnabled(true); + AlertManager.toast((!error ? "Synced! " : "Error Syncing. ") + upcount + " Up " + downcount + " Down"); + }); + }); + + binding.syncIndicator.setText(FTPSync.text); + FTPSync.setOnUpdateIndicator(text -> {if(getActivity() != null) getActivity().runOnUiThread(() -> binding.syncIndicator.setText(text));}); if(evcode.equals("unset")){ binding.noEventError.setVisibility(View.VISIBLE); @@ -104,26 +116,11 @@ public class TransferFragment extends Fragment { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("Chose data"); - builder.setNegativeButton("Pit data", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - CSVExport.exportPits(getContext()); - } - }); + builder.setNegativeButton("Pit data", (dialog, which) -> CSVExport.exportPits(getContext())); - builder.setPositiveButton("Match data", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - CSVExport.exportMatches(getContext()); - } - }); + builder.setPositiveButton("Match data", (dialog, which) -> CSVExport.exportMatches(getContext())); - builder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); + builder.setNeutralButton("Cancel", (dialog, which) -> dialog.cancel()); builder.show(); }); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferSelectorFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferSelectorFragment.java index 0017c83..0b72e6b 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferSelectorFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferSelectorFragment.java @@ -30,17 +30,11 @@ public class TransferSelectorFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentTransferSelectorBinding.inflate(inflater, container, false); - binding.codesButton.setOnClickListener(view -> { - onselect.onSelectCodes(this); - }); + binding.codesButton.setOnClickListener(view -> onselect.onSelectCodes(this)); - binding.bluetoothButton.setOnClickListener(view -> { - onselect.onSelectBluetooth(this); - }); + binding.bluetoothButton.setOnClickListener(view -> onselect.onSelectBluetooth(this)); - binding.fileBundleButton.setOnClickListener(view -> { - onselect.onSelectFileBundle(this); - }); + binding.fileBundleButton.setOnClickListener(view -> onselect.onSelectFileBundle(this)); return binding.getRoot(); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/AlertManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/AlertManager.java index 324eb67..f776db5 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/AlertManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/AlertManager.java @@ -53,19 +53,17 @@ public class AlertManager { public static void error(Exception e) { e.printStackTrace(); - ((Activity) context).runOnUiThread(new Runnable() { - public void run() { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); + ((Activity) context).runOnUiThread(() -> { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); - AlertDialog.Builder alert = new AlertDialog.Builder(context); - alert.setMessage(sw.toString()); - alert.setTitle(e.getMessage()); - alert.setPositiveButton("OK", null); - alert.setCancelable(true); + AlertDialog.Builder alert = new AlertDialog.Builder(context); + alert.setMessage(sw.toString()); + alert.setTitle(e.getMessage()); + alert.setPositiveButton("OK", null); + alert.setCancelable(true); - alert.create().show(); - } + alert.create().show(); }); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java index b1a0bfd..4bae7a4 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java @@ -30,17 +30,25 @@ public class DataManager { public static inputType[] match_latest_values; public static transferType[][] match_transferValues; public static void reload_match_fields(){ - match_values = fields.load(fields.matchFieldsFilename); - match_latest_values = match_values[match_values.length-1]; - match_transferValues = transferType.get_transfer_values(match_values); + try { + match_values = fields.load(fields.matchFieldsFilename); + match_latest_values = match_values[match_values.length - 1]; + match_transferValues = transferType.get_transfer_values(match_values); + } catch (Exception e){ + AlertManager.error(e); + } } public static inputType[][] pit_values; public static inputType[] pit_latest_values; public static transferType[][] pit_transferValues; public static void reload_pit_fields(){ - pit_values = fields.load(fields.pitsFieldsFilename); - pit_latest_values = pit_values[pit_values.length-1]; - pit_transferValues = transferType.get_transfer_values(pit_values); + try { + pit_values = fields.load(fields.pitsFieldsFilename); + pit_latest_values = pit_values[pit_values.length-1]; + pit_transferValues = transferType.get_transfer_values(pit_values); + } catch (Exception e){ + AlertManager.error(e); + } } } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/settingsManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/settingsManager.java index 6a9b365..21eaacc 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/settingsManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/settingsManager.java @@ -13,8 +13,8 @@ public class settingsManager { public static final String UnameKey = "username"; public static final String SelEVCodeKey = "selected_event_code"; + public static final String YearNumKey = "year_num"; public static final String WifiModeKey = "wifi_mode"; - public static final String TeamNumKey = "team_num"; public static final String MatchNumKey = "match_num"; public static final String AllyPosKey = "alliance_pos"; public static final String DataModeKey = "data_view_mode"; @@ -22,6 +22,7 @@ public class settingsManager { public static final String FTPEnabled = "ftp_enabled"; public static final String FTPServer = "ftp_server"; public static final String FTPSendMetaFiles = "ftp_send_meta_files"; + public static final String CustomEventsKey = "enable_custom_event"; public static Map defaults = getDefaults(); private static Map getDefaults(){ @@ -30,7 +31,7 @@ public class settingsManager { hm.put(UnameKey, "Username"); hm.put(SelEVCodeKey, "unset"); hm.put(WifiModeKey, false); - hm.put(TeamNumKey, 4388); + hm.put(YearNumKey, 2025); hm.put(MatchNumKey, 0); hm.put(AllyPosKey, "red-1"); hm.put(DataModeKey, 0); @@ -38,6 +39,7 @@ public class settingsManager { hm.put(FTPEnabled, false); hm.put(FTPServer, "0.0.0.0"); hm.put(FTPSendMetaFiles, false); + hm.put(CustomEventsKey, false); return hm; } @@ -52,7 +54,7 @@ public class settingsManager { getEditor() .putString(SelEVCodeKey,(String) defaults.get( SelEVCodeKey)).apply(); getEditor().putBoolean(WifiModeKey, (boolean) defaults.get( WifiModeKey )).apply(); - getEditor() .putInt(TeamNumKey, (int) defaults.get( TeamNumKey )).apply(); + getEditor() .putInt(YearNumKey, (int) defaults.get( YearNumKey )).apply(); getEditor() .putInt(MatchNumKey, (int) defaults.get( MatchNumKey )).apply(); getEditor() .putString(AllyPosKey, (String) defaults.get( AllyPosKey )).apply(); getEditor() .putInt(DataModeKey, (int) defaults.get( DataModeKey )).apply(); @@ -62,6 +64,8 @@ public class settingsManager { getEditor().putBoolean(FTPEnabled, (boolean) defaults.get( FTPEnabled )).apply(); getEditor() .putString(FTPServer, (String) defaults.get( FTPServer )).apply(); getEditor().putBoolean(FTPSendMetaFiles, (boolean) defaults.get( FTPSendMetaFiles )).apply(); + + getEditor().putBoolean(CustomEventsKey, (boolean) defaults.get( CustomEventsKey )).apply(); } // IDK why I decided to format these functions like this. It looks cool though. @@ -74,8 +78,8 @@ public class settingsManager { public static boolean getWifiMode(){return prefs.getBoolean( WifiModeKey, (boolean) defaults.get(WifiModeKey));} public static void setWifiMode(boolean bool){getEditor().putBoolean( WifiModeKey,bool).apply();} - public static int getTeamNum(){return prefs.getInt( TeamNumKey, (int) defaults.get(TeamNumKey));} - public static void setTeamNum(int num){ getEditor().putInt( TeamNumKey,num).apply();} + public static int getYearNum(){return prefs.getInt( YearNumKey, (int) defaults.get(YearNumKey));} + public static void setYearNum(int num){ getEditor().putInt( YearNumKey,num).apply();} public static int getMatchNum(){return prefs.getInt( MatchNumKey, (int) defaults.get(MatchNumKey));} public static void setMatchNum(int num){ getEditor().putInt( MatchNumKey,num).apply();} @@ -98,7 +102,12 @@ public class settingsManager { public static void setFTPServer(String str){ getEditor().putString( FTPServer,str).apply();} public static boolean getFTPSendMetaFiles(){return prefs.getBoolean(FTPSendMetaFiles, (boolean) defaults.get(FTPSendMetaFiles));} - public static void setFTPSendMetaFiles(String str){getEditor().putString(FTPSendMetaFiles,str).apply();} + public static void setFTPSendMetaFiles(boolean bool){getEditor().putBoolean(FTPSendMetaFiles,bool).apply();} + + + public static boolean getCustomEvents(){return prefs.getBoolean(CustomEventsKey, (boolean) defaults.get(FTPSendMetaFiles));} + public static void setCustomEvents(boolean bool){getEditor().putBoolean(CustomEventsKey,bool).apply();} + diff --git a/app/src/main/res/drawable/background.png b/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..929153b Binary files /dev/null and b/app/src/main/res/drawable/background.png differ diff --git a/app/src/main/res/drawable/background_repeat.xml b/app/src/main/res/drawable/background_repeat.xml new file mode 100644 index 0000000..ca37804 --- /dev/null +++ b/app/src/main/res/drawable/background_repeat.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable/border.xml b/app/src/main/res/drawable/border.xml new file mode 100644 index 0000000..83c790d --- /dev/null +++ b/app/src/main/res/drawable/border.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dropdown.xml b/app/src/main/res/drawable/dropdown.xml new file mode 100644 index 0000000..0c10589 --- /dev/null +++ b/app/src/main/res/drawable/dropdown.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/field_2025.png b/app/src/main/res/drawable/field_2025.png index 43b79fe..3c0af23 100644 Binary files a/app/src/main/res/drawable/field_2025.png and b/app/src/main/res/drawable/field_2025.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bc2b7a6..c8a1e7b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,21 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" + android:background="@drawable/background_repeat" android:layout_height="match_parent"> - - + android:layout_height="match_parent"> - + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:orientation="vertical" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + - + + + + + + + + + + + + + + + +