Merge pull request #1 from Team4388/overhaul-ui

Overhaul UI
This commit is contained in:
Michael Mikovsky
2025-02-27 18:15:55 +00:00
committed by GitHub
52 changed files with 2002 additions and 953 deletions
Binary file not shown.
+6 -2
View File
@@ -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
- "Send Meta Files" button
- Year selector
+3 -6
View File
@@ -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 (<Year num since 2024>.<Update Version>)
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")
@@ -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")
}
};
@@ -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<BuiltByteParser.parsedObject> 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<dataType, Integer> 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);
@@ -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<BuiltByteParser.parsedObject> 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<dataType, Integer> onUpdate){
dropdown = new PowerSpinnerView(context);
dropdown = new CustomSpinnerView(context);
List<IconSpinnerItem> 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<String> 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<IconSpinnerItem>() {
@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());
}
@@ -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<BuiltByteParser.parsedObject> 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);
@@ -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();
@@ -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<BuiltByteParser.parsedObject> 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();
}
@@ -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<BuiltByteParser.parsedObject> 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();
}
@@ -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<BuiltByteParser.parsedObject> 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;
@@ -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 "<no-notes>";}
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<BuiltByteParser.parsedObject> 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();
}
@@ -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<String> 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<String> 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;
// }
//
}
@@ -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<String> 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<String> options, String defaultOption){
setOptions(options, options.indexOf(defaultOption));
}
public void setOptions(List<String> 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);
}
}
@@ -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();
}
}
@@ -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);
});
@@ -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
};
}
@@ -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<String> options = new ArrayList<>();
List<IconSpinnerItem> 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();
}
@@ -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<String> 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<IconSpinnerItem> 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<IconSpinnerItem>() {
@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]);
}
}
}
@@ -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<String> 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<String> 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<String> 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;
}
}
}
@@ -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<dataType> 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<dataType, Integer>() {
@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);
}
}
}
@@ -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();
}
}
}
@@ -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;
});
}
@@ -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);
}
}
}
@@ -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<String> 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<IconSpinnerItem> 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<IconSpinnerItem>)
(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<IconSpinnerItem>)
(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<T> {
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<String> {
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<Integer> {
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<String> {
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<String> 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<Boolean> {
private List<SettingsItem<?>> 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<String, Object> settings;
private List<SettingsItem<?>> 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<View> 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));
}
}
}
@@ -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<String> keySet = remoteTimestamps.keySet();
Iterator<String> 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<String, Date> timestamps){
@@ -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",
@@ -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) {
@@ -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();
});
@@ -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();
}
@@ -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();
});
}
@@ -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);
}
}
}
@@ -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();}
Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/background"
android:tileMode="repeat" />
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent"/>
<stroke android:width="2dip" android:color="#626262" />
<corners android:radius="3dip"/>
<padding android:left="0dip"
android:top="0dip"
android:right="0dip"
android:bottom="0dip" />
</shape>
+5
View File
@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="12dp" android:viewportHeight="24" android:viewportWidth="24" android:width="12dp">
<path android:fillColor="#000000" android:fillType="evenOdd" android:pathData="M5,8l7,8l7,-8z" android:strokeColor="#00000000" android:strokeWidth="1"/>
</vector>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 KiB

After

Width:  |  Height:  |  Size: 43 KiB

+1 -13
View File
@@ -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">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:rotation="0"
android:rotationX="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/field_2025_background" />
<fragment
android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
+125 -13
View File
@@ -1,24 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/teamsMainElem"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:layout_height="match_parent">
<LinearLayout
<ScrollView
android:layout_width="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">
android:layout_height="match_parent">
<ScrollView
android:id="@+id/teamsArea"
<LinearLayout
android:layout_width="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">
</ScrollView>
<com.ridgebotics.ridgescout.ui.CustomSpinnerView
android:id="@+id/data_type_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:id="@+id/team_name2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="0dp" />
<TextView
android:id="@+id/team_description2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@+id/team_name2"
tools:layout_editor_absoluteX="0dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pit Data"
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintTop_toBottomOf="@+id/team_description2"
tools:layout_editor_absoluteX="0dp" />
<LinearLayout
android:id="@+id/pitArea"
android:layout_width="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">
</LinearLayout>
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Match Data"
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintTop_toBottomOf="@+id/team_description2"
tools:layout_editor_absoluteX="0dp" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/individual_view_selector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="gone"
tools:visibility="visible">
<Button
android:id="@+id/matches_minus_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="0dp"
android:text="@string/back"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/match_num"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/match_num"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="0"
android:textAlignment="gravity"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="3dp" />
<Button
android:id="@+id/matches_plus_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="0dp"
android:text="next"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/match_num"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/matchArea"
android:layout_width="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">
</LinearLayout>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
+17 -5
View File
@@ -50,23 +50,35 @@
android:layout_height="wrap_content"
android:text="@string/pit_n_scouting"
android:textSize="34sp"
app:layout_constraintBottom_toTopOf="@id/status_button"
app:layout_constraintBottom_toTopOf="@id/event_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/matchScoutingButton" />
<Button
android:id="@+id/status_button"
android:id="@+id/event_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status"
android:text="event"
android:textSize="34sp"
app:layout_constraintTop_toBottomOf="@+id/pitScoutingButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pitScoutingButton"
app:layout_constraintVertical_bias="0.307" />
<Button
android:id="@+id/event_add_button"
android:layout_width="58dp"
android:layout_height="63dp"
android:layout_marginStart="4dp"
android:text="+"
android:textSize="24sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/event_button"
app:layout_constraintTop_toBottomOf="@+id/pitScoutingButton" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:id="@+id/teams_minus_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="0dp"
android:text="del"
android:textSize="20sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/textView3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Teams"
android:textAlignment="gravity"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/teams_plus_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="0dp"
android:text="Add"
android:textSize="20sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView3"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TableLayout
android:id="@+id/teamsTable"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</TableLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<Button
android:id="@+id/matches_minus_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="0dp"
android:text="del"
android:textSize="20sp"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@+id/textView4"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="1dp"
tools:visibility="visible" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Matches"
android:textAlignment="gravity"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/matches_plus_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="0dp"
android:text="Add"
android:textSize="20sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.686"
app:layout_constraintStart_toEndOf="@+id/textView4"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TableLayout
android:id="@+id/matchTable"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</TableLayout>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="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">
<TableLayout
android:id="@+id/matchTable"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -20,7 +20,8 @@
<TableLayout
android:id="@+id/SettingsTable"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical">
</TableLayout>
+14 -5
View File
@@ -27,7 +27,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/uploadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -38,7 +38,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/downloadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -49,7 +49,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/uploadButton" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/SyncButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -61,7 +61,7 @@
app:layout_constraintTop_toTopOf="parent" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/CSVButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -73,7 +73,7 @@
app:layout_constraintTop_toBottomOf="@+id/SyncButton" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/TBAButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -84,6 +84,15 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/SyncButton" />
<TextView
android:id="@+id/sync_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/SyncButton" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:orientation="horizontal"
android:background="@drawable/border"
tools:ignore="UselessParent">
<TextView
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:textSize="24sp"
android:overlapAnchor="false"/>
</LinearLayout>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="9dp"
android:layout_marginTop="-5dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:text="Test"
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"/>
</RelativeLayout>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:orientation="horizontal"
android:background="@drawable/border"
tools:ignore="UselessParent">
<TextView
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:textSize="24sp"
android:overlapAnchor="false"/>
</LinearLayout>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="9dp"
android:layout_marginTop="-5dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:text="Test"
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"/>
</RelativeLayout>
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/toggle_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/toggle_title_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/toggle_title_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toggle_title"
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"/>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -25,7 +25,7 @@
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/pop_exit_anim" />
<action
android:id="@+id/action_navigation_scouting_to_navigation_scouting_status"
android:id="@+id/action_navigation_scouting_to_navigation_scouting_event"
app:destination="@id/navigation_scouting_status"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
@@ -92,8 +92,8 @@
<fragment
android:id="@+id/navigation_scouting_status"
android:name="com.ridgebotics.ridgescout.ui.scouting.StatusFragment"
tools:layout="@layout/fragment_scouting_status">
android:name="com.ridgebotics.ridgescout.ui.scouting.EventFragment"
tools:layout="@layout/fragment_scouting_event">
</fragment>
<fragment
+5
View File
@@ -13,4 +13,9 @@
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<style name="FullScreenDialogStyle" parent="Theme.MaterialComponents.Dialog">
<item name="android:windowIsFloating">false</item>
<item name="android:windowBackground">@android:color/black</item>
</style>
</resources>
+5
View File
@@ -13,4 +13,9 @@
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<style name="FullScreenDialogStyle" parent="Theme.MaterialComponents.Light.Dialog">
<item name="android:windowIsFloating">false</item>
<item name="android:windowBackground">@android:color/white</item>
</style>
</resources>
+2
View File
@@ -8,6 +8,7 @@ material = "1.10.0"
constraintlayout = "2.1.4"
lifecycleLivedataKtx = "2.6.1"
lifecycleViewmodelKtx = "2.6.1"
material3 = "1.3.1"
navigationFragment = "2.6.0"
navigationUi = "2.6.0"
supportAnnotations = "28.0.0"
@@ -22,6 +23,7 @@ material = { group = "com.google.android.material", name = "material", version.r
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigationFragment" }
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
support-annotations = { group = "com.android.support", name = "support-annotations", version.ref = "supportAnnotations" }