Scouting data loading and saving

This commit is contained in:
astatin3
2024-06-28 15:44:38 -06:00
parent 46219e0a6a
commit 485205f35c
18 changed files with 475 additions and 215 deletions
+18 -7
View File
@@ -1,10 +1,21 @@
# ScoutingApp2025
Ridgebotics 2024 scouting app in Android
Ridgebotics 2025 scouting app in Android
TODO:
- QR Code data transfer
- Data Saving and transmitting
- Format event selector page better on mobile.
- Scouting
- Data Visualization
- Testing on new tablets
- Clean up matchScoutingView class, and make it provide code for both pit and match scouting
- Separate the inputTypes classes into their own files, and integrate the some of the stuff from matchScoutingView to make the code cleaner.
- Make the file browser UI
- Add white border around the datamatrix code to allow file transfer in dark mode
- Fix the code scanning progress indicator
- Make pit and match data field builder UIs. I don't want to have to keep editing a variable
Also TODO:
- Copy matchScoutingView to create pitScoutingView
- Add more types of data fields.
- Make the "Search" menu
- Make the "Compile" menu
Also Also TODO:
- Make practice mode
- Make server software to allow for easy sync over wifi
- Test the scouting app
@@ -3,6 +3,7 @@ package com.astatin3.scoutingapp2025;
import android.os.Bundle;
import com.astatin3.scoutingapp2025.scoutingData.fields;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.appcompat.app.AppCompatActivity;
@@ -25,8 +26,12 @@ public class MainActivity extends AppCompatActivity {
latestSettings.update();
if(!fileEditor.fileExist(fields.fieldsFilename)){
fields.save();
if(!fileEditor.fileExist(fields.matchFieldsFilename)){
fields.save(fields.matchFieldsFilename, fields.default_match_fields);
}
if(!fileEditor.fileExist(fields.pitsFieldsFilename)){
fields.save(fields.pitsFieldsFilename, fields.default_pit_fields);
}
super.onCreate(savedInstanceState);
@@ -1,6 +1,6 @@
package com.astatin3.scoutingapp2025.SettingsVersionStack;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import java.nio.charset.StandardCharsets;
@@ -0,0 +1,86 @@
package com.astatin3.scoutingapp2025.scoutingData;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.utility.BuiltByteParser;
import com.astatin3.scoutingapp2025.utility.ByteBuilder;
import java.util.ArrayList;
public class ScoutingDataWriter {
// private static final int int_type_id = 255;
// private static final int string_type_id = 254;
public static boolean save(int version, String username, String filename, ScoutingVersion.dataType[] data){
ByteBuilder bb = new ByteBuilder();
try {
bb.addInt(version);
bb.addString(username);
for(int i = 0; i < data.length; i++){
switch (data[i].getValueType()){
case NUM:
bb.addInt((int) data[i].get());
break;
case STRING:
bb.addString((String) data[i].get());
break;
}
}
byte[] bytes = bb.build();
fileEditor.writeFile(filename, bytes);
return true;
} catch (ByteBuilder.buildingException e) {
e.printStackTrace();
return false;
}
}
public static class ParsedScoutingDataResult {
public String filename;
public String username;
public int version;
public ScoutingVersion.ScoutingArray data;
}
public static ParsedScoutingDataResult load(String filename, ScoutingVersion.inputType[][] values , ScoutingVersion.transferType[][] transferValues){
byte[] bytes = fileEditor.readFile(filename);
BuiltByteParser bbp = new BuiltByteParser(bytes);
try {
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
ScoutingVersion.dataType[] dataTypes = new ScoutingVersion.dataType[objects.size()-2];
int version = ((int)objects.get(0).get());
System.out.println(version);
String username = (String) objects.get(1).get();
for(int i = 0; i < values[version].length; i++){
switch (objects.get(i+2).getType()){
case 0:
dataTypes[i] = fields.sv.new intType(values[version][i].name, (int) objects.get(i+2).get());
break;
case 1:
String name = values[version][i].name;
String value = (String) objects.get(i+2).get();
dataTypes[i] = fields.sv.new stringType(name,value);
break;
}
}
ScoutingVersion.ScoutingArray msa = fields.sv.new ScoutingArray(version, dataTypes, values, transferValues);
msa.update();
ParsedScoutingDataResult psda = new ParsedScoutingDataResult();
psda.filename = filename;
psda.username = username;
psda.version = version;
psda.data = msa;
return psda;
} catch (BuiltByteParser.byteParsingExeption e){
e.printStackTrace();
return null;
}
}
}
@@ -1,6 +1,6 @@
package com.astatin3.scoutingapp2025.scoutingData;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.utility.BuiltByteParser;
import com.astatin3.scoutingapp2025.utility.ByteBuilder;
@@ -8,36 +8,40 @@ import java.util.ArrayList;
public class fields {
public static ScoutingVersion sv = new ScoutingVersion();
public static final String fieldsFilename = "data.fields";
// public static ScoutingVersion.inputType[][] values = new ScoutingVersion.inputType[][]{};
public static final String matchFieldsFilename = "matches.fields";
public static final String pitsFieldsFilename = "matches.fields";
public static ScoutingVersion.inputType[][] values = new ScoutingVersion.inputType[][] {
public static final ScoutingVersion.inputType[][] default_match_fields = new ScoutingVersion.inputType[][] {
{
sv.new notesType("name", "Unset-Username"),
sv.new sliderType("How good is robot", 5, 0, 10)
}, {
sv.new notesType("name", "Unset-Username"),
sv.new sliderType("How good is robot", 5, 0, 10),
sv.new notesType("notes", "No-Notes")
}, {
sv.new notesType("name", "Unset-Username"),
sv.new notesType("notes", "No-Notes")
}, {
sv.new notesType("name", "Unset-Username")
}, {
sv.new notesType("name", "Unset-Username"),
sv.new sliderType("How good is robot", 5, 0, 10)
sv.new notesType("notes", "<no-notes>"),
},{
sv.new sliderType("How good is robot", 5, 0, 10),
sv.new sliderType("Test", 1, 0, 10),
sv.new notesType("notes", "<no-notes>"),
}
};
public static boolean save(){
public static final ScoutingVersion.inputType[][] default_pit_fields = new ScoutingVersion.inputType[][] {
{
sv.new sliderType("How good is robot", 5, 0, 10),
sv.new notesType("notes", "<no-notes>"),
},{
sv.new sliderType("How good is robot", 5, 0, 10),
sv.new sliderType("Test", 1, 0, 10),
sv.new notesType("notes", "<no-notes>"),
}
};
public static boolean save(String filename, ScoutingVersion.inputType[][] values){
try {
ByteBuilder bb = new ByteBuilder();
for (int i = 0; i < values.length; i++) {
bb.addRaw(127, save_version(values[i]));
}
fileEditor.writeFile(fieldsFilename, bb.build());
fileEditor.writeFile(filename, bb.build());
return true;
}catch (ByteBuilder.buildingException e) {
e.printStackTrace();
@@ -54,25 +58,39 @@ public class fields {
return bb.build();
}
public static boolean load(){
byte[] bytes = fileEditor.readFile(fieldsFilename);
public static ScoutingVersion.inputType[][] load(String filename){
byte[] bytes = fileEditor.readFile(filename);
System.out.println(bytes);
try {
BuiltByteParser bbp = new BuiltByteParser(bytes);
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
values = new ScoutingVersion.inputType[objects.size()][];
ScoutingVersion.inputType[][] values = new ScoutingVersion.inputType[objects.size()][];
for(int i = 0 ; i < objects.size(); i++){
values[i] = load_version((byte[]) objects.get(i).get());
}
return true;
return values;
// return true;
} catch (Exception e) {
e.printStackTrace();
return false;
return null;
// return false;
}
// return new ScoutingVersion.inputType[][] {
// {
// sv.new sliderType("How good is robot", 5, 0, 10),
// sv.new notesType("notes", "<no-notes>"),
// },{
// sv.new sliderType("How good is robot", 5, 0, 10),
// sv.new sliderType("Test", 1, 0, 10),
// sv.new notesType("notes", "<no-notes>"),
// }
// };
}
private static ScoutingVersion.inputType[] load_version(byte[] bytes) throws BuiltByteParser.byteParsingExeption{
@@ -103,27 +121,27 @@ public class fields {
return output;
}
public static void test(){
ScoutingVersion.transferType[][] transferValues = sv.get_transfer_values(values);
ScoutingVersion.ScoutingArray msa = sv.new ScoutingArray(0, new ScoutingVersion.dataType[]{
sv.new stringType("name", "test-username"),
sv.new intType("How good is robot", 12)
}, values, transferValues);
msa.update();
for(ScoutingVersion.dataType dt : msa.array){
if(dt == null) continue;
switch (dt.getValueType()){
case NUM:
System.out.println(dt.name + " " + (int) dt.get());
break;
case STRING:
System.out.println(dt.name + " " + (String) dt.get());
break;
}
}
}
// public static void test(){
// ScoutingVersion.transferType[][] transferValues = sv.get_transfer_values(values);
//
// ScoutingVersion.ScoutingArray msa = sv.new ScoutingArray(0, new ScoutingVersion.dataType[]{
// sv.new stringType("name", "test-username"),
// sv.new intType("How good is robot", 12)
// }, values, transferValues);
//
// msa.update();
//
// for(ScoutingVersion.dataType dt : msa.array){
// if(dt == null) continue;
// switch (dt.getValueType()){
// case NUM:
// System.out.println(dt.name + " " + (int) dt.get());
// break;
// case STRING:
// System.out.println(dt.name + " " + (String) dt.get());
// break;
// }
//
// }
// }
}
@@ -6,8 +6,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -15,9 +13,8 @@ import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings;
import com.astatin3.scoutingapp2025.databinding.FragmentDataBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.types.frcEvent;
import com.astatin3.scoutingapp2025.types.frcTeam;
public class dataFragment extends Fragment {
@@ -5,23 +5,18 @@ import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.astatin3.scoutingapp2025.databinding.FragmentDataBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.types.frcEvent;
import com.astatin3.scoutingapp2025.types.frcMatch;
import com.astatin3.scoutingapp2025.types.frcTeam;
import org.w3c.dom.Text;
public class overviewView extends ScrollView {
public overviewView(@NonNull Context context) {
super(context);
@@ -1,26 +1,26 @@
package com.astatin3.scoutingapp2025.ui.scouting;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.astatin3.scoutingapp2025.scoutingData.ScoutingDataWriter;
import com.astatin3.scoutingapp2025.scoutingData.ScoutingVersion;
import com.astatin3.scoutingapp2025.scoutingData.fields;
import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings;
import com.astatin3.scoutingapp2025.databinding.FragmentScoutingBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.types.frcEvent;
import com.astatin3.scoutingapp2025.types.frcMatch;
import com.astatin3.scoutingapp2025.types.frcTeam;
import com.astatin3.scoutingapp2025.utility.AutoSaveManager;
import com.google.android.material.slider.Slider;
import com.skydoves.powerspinner.PowerSpinnerView;
import java.util.ArrayList;
@@ -32,46 +32,166 @@ public class matchScoutingView extends ConstraintLayout {
super(context, attributeSet);
}
int unsaved_color = 0x60ff0000;
int saved_color = 0x6000ff00;
FragmentScoutingBinding binding;
String alliance_position;
String evcode;
int cur_match_num;
frcEvent event;
String filename;
String username;
boolean edited = false;
ScoutingVersion.inputType[][] values;
ScoutingVersion.inputType[] latest_values;
ScoutingVersion.transferType[][] transferValues;
AutoSaveManager asm = new AutoSaveManager(this::save);
ArrayList<ScoutingVersion.dataType> dataTypes;
ArrayList<View> views = new ArrayList<>();
public void save(){
System.out.println("Saved!");
edited = false;
set_indicator_color(saved_color);
// fileEditor.createFile(filename);
save_fields();
}
public void set_indicator_color(int color){
binding.fileIndicator.setBackgroundColor(color);
}
public void update_asm(){
// v.getBackground().setColorFilter(Color.parseColor("#00ff00"), PorterDuff.Mode.DARKEN);
edited = true;
set_indicator_color(unsaved_color);
asm.update();
}
public void init(FragmentScoutingBinding tmp_binding){
binding = tmp_binding;
alliance_position = latestSettings.settings.get_alliance_pos();
evcode = latestSettings.settings.get_evcode();
event = frcEvent.decode(fileEditor.readFile(evcode + ".eventdata"));
username = latestSettings.settings.get_username();
binding.eventcode.setText(evcode);
binding.alliancePosText.setText(alliance_position);
values = fields.load(fields.matchFieldsFilename);
if(values == null || values.length == 0){
TextView tv = new TextView(getContext());
tv.setText("Failed to load fields.\nTry to either download or create match scouting fields.");
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
binding.MatchScoutArea.addView(tv);
// views.add(tv);
return;
}
cur_match_num = latestSettings.settings.get_match_num();
update_match_num();
binding.nextButton.setOnClickListener(v -> {
if(edited) save();
latestSettings.settings.set_match_num(cur_match_num+1);
cur_match_num += 1;
update_match_num();
update_scouting_data();
});
binding.backButton.setOnClickListener(v -> {
if(edited) save();
latestSettings.settings.set_match_num(cur_match_num-1);
cur_match_num -= 1;
update_match_num();
update_scouting_data();
});
binding.middleButton.setOnClickListener(v -> {
if(edited) save();
});
latest_values = values[values.length-1];
transferValues = fields.sv.get_transfer_values(values);
for(int i = 0; i < views.size(); i++){
binding.MatchScoutArea.removeView(views.get(i));
}
views = new ArrayList<>();
create_fields();
update_scouting_data();
}
private void create_fields(){
for(int i = 0 ; i < latest_values.length; i++) {
TextView tv = new TextView(getContext());
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
tv.setTextSize(24);
binding.MatchScoutArea.addView(tv);
// views.add(tv);
switch (latest_values[i].getInputType()) {
case SLIDER:
ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i];
// dataTypes.add()
tv.setText(sliderType.name);
Slider slider = new Slider(getContext());
slider.setStepSize((float) 1 / sliderType.max);
slider.setValue((int) sliderType.default_value / (float) sliderType.max);
slider.addOnChangeListener(new Slider.OnChangeListener() {
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
System.out.println(value * sliderType.max);
update_asm();
}
});
binding.MatchScoutArea.addView(slider);
views.add(slider);
break;
case DROPDOWN:
ScoutingVersion.dropdownType dropdownType = (ScoutingVersion.dropdownType) latest_values[i];
tv.setText(dropdownType.name);
views.add(new PowerSpinnerView(getContext()));
break;
case NOTES_INPUT:
ScoutingVersion.notesType notesType = (ScoutingVersion.notesType) latest_values[i];
tv.setText(notesType.name);
views.add(new EditText(getContext()));
break;
}
}
}
private void update_match_num(){
// cur_match_num = latestSettings.settings.get_match_num();
edited = false;
binding.matchnum.setText(String.valueOf(cur_match_num+1));
System.out.println(cur_match_num);
@@ -87,10 +207,11 @@ public class matchScoutingView extends ConstraintLayout {
}else{
binding.nextButton.setVisibility(View.VISIBLE);
}
update_scouting_data();
}
private frcTeam get_team(frcMatch match){
// Get team number
@@ -117,85 +238,110 @@ public class matchScoutingView extends ConstraintLayout {
}
}
filename = evcode + "-" + (cur_match_num+1) + "-" + alliance_position + "-" + team_num + ".matchscoutdata";
return team;
}
ArrayList<View> views = new ArrayList<>();
public void update_scouting_data(){
asm.start();
frcMatch match = event.matches.get(cur_match_num);
frcTeam team = get_team(match);
binding.teamName.setText(team.teamName);
binding.teamDescription.setText(team.getDescription());
boolean new_file = !fileEditor.fileExist(filename);
if(asm.isRunning){
asm.stop();
}
if(new_file){
default_fields();
set_indicator_color(unsaved_color);
}else{
get_fields();
set_indicator_color(saved_color);
}
asm.start();
}
public void default_fields(){
for(int i = 0; i < views.size(); i++){
binding.MatchScoutArea.removeView(views.get(i));
}
views = new ArrayList<>();
boolean success = fields.load();
if(!success){
TextView tv = new TextView(getContext());
tv.setText("Failed to load fields.\nTry to either download or create match scouting fields.");
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
binding.MatchScoutArea.addView(tv);
views.add(tv);
return;
}
if(fields.values.length == 0){
return;
}
ScoutingVersion.inputType[] values = fields.values[fields.values.length-1];
// int prev_text = binding.teamDescription.getId();
for(int i = 0 ; i < values.length; i++){
TextView tv = new TextView(getContext());
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
tv.setTextSize(24);
binding.MatchScoutArea.addView(tv);
views.add(tv);
switch (values[i].getInputType()){
case SLIDER:
ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) values[i];
tv.setText(sliderType.name);
Slider slider = new Slider(getContext());
slider.setStepSize((float) 1 / sliderType.max);
slider.setValue((int) sliderType.default_value / (float) sliderType.max);
slider.addOnChangeListener(new Slider.OnChangeListener() {
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
System.out.println(value * sliderType.max);
asm.update();
}
});
binding.MatchScoutArea.addView(slider);
views.add(slider);
break;
case DROPDOWN:
ScoutingVersion.dropdownType dropdownType = (ScoutingVersion.dropdownType) values[i];
tv.setText(dropdownType.name);
break;
case NOTES_INPUT:
ScoutingVersion.notesType notesType = (ScoutingVersion.notesType) values[i];
tv.setText(notesType.name);
break;
if(views.get(i).getClass() == Slider.class){
ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i];
((Slider) views.get(i)).setValue((int) sliderType.default_value / (float) sliderType.max);
}
// prev_text = tv.getId();
// } else if (views.get(i).getClass() == .class) {
//
// }
}
}
public void get_fields(){
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, values, transferValues);
ScoutingVersion.dataType[] types = psdr.data.array;
for(int i = 0; i < views.size(); i++){
View view = views.get(i);
Class<? extends View> c = view.getClass();
if(c == Slider.class){
ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i];
((Slider) view).setValue((float) (sliderType.min + (int) types[i].get()) / (sliderType.max-sliderType.min));
// types[i] = fields.sv.new intType(latest_values[i].name, (int) ((Slider) view).getValue());
} else if (c == PowerSpinnerView.class) {
// types[i] = fields.sv.new intType(latest_values[i].name, 0);
} else if (c == EditText.class) {
// types[i] = fields.sv.new stringType(latest_values[i].name, "Test String");
}
}
// System.out.println(ScoutingDataWriter.save(values.length, username, filename, types));
}
public void save_fields(){
ScoutingVersion.dataType[] types = new ScoutingVersion.dataType[latest_values.length];
for(int i = 0; i < views.size(); i++){
View view = views.get(i);
Class<? extends View> c = view.getClass();
if(c == Slider.class){
ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i];
types[i] = fields.sv.new intType(latest_values[i].name,
sliderType.min + (int)(((Slider) view).getValue() * (sliderType.max-sliderType.min)));
} else if (c == PowerSpinnerView.class) {
types[i] = fields.sv.new intType(latest_values[i].name, 0);
} else if (c == EditText.class) {
types[i] = fields.sv.new stringType(latest_values[i].name, "Test String");
}
}
System.out.println(types.length);
System.out.println(ScoutingDataWriter.save(values.length-1, username, filename, types));
}
}
@@ -12,7 +12,6 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Spinner;
import androidx.annotation.NonNull;
@@ -20,10 +19,9 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.databinding.FragmentSettingsBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings;
import com.google.android.material.textfield.TextInputEditText;
import com.skydoves.powerspinner.IconSpinnerAdapter;
import com.skydoves.powerspinner.IconSpinnerItem;
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
@@ -17,7 +17,7 @@ import com.astatin3.scoutingapp2025.types.frcEvent;
import com.astatin3.scoutingapp2025.types.frcMatch;
import com.astatin3.scoutingapp2025.types.frcTeam;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.astatin3.scoutingapp2025.utility.JSONUtil;
import org.json.JSONArray;
@@ -1,7 +1,6 @@
package com.astatin3.scoutingapp2025.ui.transfer;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -13,10 +12,6 @@ import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import java.util.Objects;
import java.util.Scanner;
public class TransferFragment extends Fragment {
private FragmentTransferBinding binding;
@@ -13,13 +13,12 @@ import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -26,7 +26,7 @@ import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.utility.fileEditor;
import com.google.common.util.concurrent.ListenableFuture;
import java.nio.ByteBuffer;
@@ -4,13 +4,13 @@ import android.os.Handler;
import android.os.Looper;
public class AutoSaveManager {
private static final long AUTO_SAVE_DELAY = 5000; // 5 seconds
private static final long AUTO_SAVE_DELAY = 2000; // 2 seconds
private final Handler handler;
private final Runnable autoSaveRunnable;
private boolean isAutoSaveScheduled = false;
private final AutoSaveFunction autoSaveFunction;
private boolean isRunning = false;
public boolean isRunning = false;
// Functional interface for the auto-save function
@FunctionalInterface
@@ -1,7 +1,5 @@
package com.astatin3.scoutingapp2025.utility;
import com.astatin3.scoutingapp2025.fileEditor;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -1,7 +1,5 @@
package com.astatin3.scoutingapp2025.utility;
import com.astatin3.scoutingapp2025.fileEditor;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -1,4 +1,4 @@
package com.astatin3.scoutingapp2025;
package com.astatin3.scoutingapp2025.utility;
import android.content.Context;
+72 -58
View File
@@ -61,27 +61,16 @@
<com.astatin3.scoutingapp2025.ui.scouting.matchScoutingView
android:id="@+id/matchScoutingView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
<TextView
android:id="@+id/bar_team_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textSize="24sp"
app:layout_constraintEnd_toStartOf="@+id/next_button"
app:layout_constraintStart_toEndOf="@+id/matchnum"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -114,13 +103,77 @@
</LinearLayout>
</ScrollView>
<Button
android:id="@+id/back_button"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/file_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Back"
app:layout_constraintBottom_toBottomOf="@id/back_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
android:background="#60ff0000">
<Button
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/alliance_pos_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/matchnum"
app:layout_constraintStart_toEndOf="@+id/back_button"
app:layout_constraintTop_toBottomOf="@id/eventcode" />
<TextView
android:id="@+id/eventcode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="@+id/matchnum"
app:layout_constraintStart_toEndOf="@+id/back_button"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/matchnum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/bar_team_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/next_button"
app:layout_constraintStart_toEndOf="@+id/matchnum"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<Button
@@ -129,47 +182,8 @@
android:layout_height="wrap_content"
android:text="Save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/alliance_pos_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="@+id/matchnum"
app:layout_constraintStart_toEndOf="@+id/back_button"
app:layout_constraintTop_toBottomOf="@id/eventcode" />
<TextView
android:id="@+id/eventcode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="@+id/matchnum"
app:layout_constraintStart_toEndOf="@+id/back_button"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/matchnum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temp"
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.astatin3.scoutingapp2025.ui.scouting.matchScoutingView>