Finish up report tool

This commit is contained in:
Michael Mikovsky
2025-04-12 14:22:27 -06:00
parent e280fc8523
commit c8c278b316
8 changed files with 164 additions and 19 deletions
@@ -165,4 +165,20 @@ public class frcEvent {
} }
return null; return null;
} }
public boolean getIsBlueAlliance(int teamNum, int matchNum){
return getIsBlueAlliance(teamNum, matches.get(matchNum));
}
public boolean getIsBlueAlliance(int teamNum, frcMatch match){
for(int i = 0; i < match.redAlliance.length; i++)
if(match.redAlliance[i] == teamNum) return false;
for(int i = 0; i < match.blueAlliance.length; i++)
if(match.blueAlliance[i] == teamNum) return true;
return false;
}
} }
@@ -1,8 +1,10 @@
package com.ridgebotics.ridgescout.ui.data; package com.ridgebotics.ridgescout.ui.data;
import static android.content.Context.CLIPBOARD_SERVICE;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static androidx.core.content.ContextCompat.getSystemService;
import static androidx.navigation.fragment.FragmentKt.findNavController; import static androidx.navigation.fragment.FragmentKt.findNavController;
import static com.ridgebotics.ridgescout.utility.Colors.datafragment_option_1; import static com.ridgebotics.ridgescout.utility.Colors.datafragment_option_1;
import static com.ridgebotics.ridgescout.utility.Colors.datafragment_option_2; import static com.ridgebotics.ridgescout.utility.Colors.datafragment_option_2;
@@ -10,7 +12,12 @@ import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
import static com.ridgebotics.ridgescout.utility.DataManager.event; import static com.ridgebotics.ridgescout.utility.DataManager.event;
import static com.ridgebotics.ridgescout.utility.DataManager.match_latest_values; import static com.ridgebotics.ridgescout.utility.DataManager.match_latest_values;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -26,6 +33,8 @@ import com.ridgebotics.ridgescout.types.frcMatch;
import com.ridgebotics.ridgescout.types.frcTeam; import com.ridgebotics.ridgescout.types.frcTeam;
import com.ridgebotics.ridgescout.ui.FieldBorderedRow; import com.ridgebotics.ridgescout.ui.FieldBorderedRow;
import com.ridgebotics.ridgescout.ui.TeamListOption; import com.ridgebotics.ridgescout.ui.TeamListOption;
import com.ridgebotics.ridgescout.utility.AlertManager;
import com.ridgebotics.ridgescout.utility.AutoSaveManager;
import com.ridgebotics.ridgescout.utility.DataManager; import com.ridgebotics.ridgescout.utility.DataManager;
import com.ridgebotics.ridgescout.utility.SettingsManager; import com.ridgebotics.ridgescout.utility.SettingsManager;
@@ -36,11 +45,15 @@ import java.util.List;
public class DataParentFragment extends Fragment { public class DataParentFragment extends Fragment {
private FragmentDataParentBinding binding; private FragmentDataParentBinding binding;
private DataFragment dataFragment; private DataFragment dataFragment;
private boolean editBoxEnabled = true;
private boolean editBoxEnabled = true;
private int teamNum = SettingsManager.getTeamNum();
private frcMatch[] ourMatches;
private int matchIndex = 0;
private AutoSaveManager asm;
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
@@ -63,17 +76,69 @@ public class DataParentFragment extends Fragment {
return binding.getRoot(); return binding.getRoot();
} }
ourMatches = event.getTeamMatches(SettingsManager.getTeamNum());
matchIndex = SettingsManager.getReportMatchIndex(evcode);
if(ourMatches.length == 0){
binding.reportToggleButton.setVisibility(GONE);
return binding.getRoot();
}
binding.scoutUpButton.setOnClickListener(v -> {
matchIndex++;
updateButtons();
});
binding.scoutDownButton.setOnClickListener(v -> {
matchIndex--;
updateButtons();
});
updateButtons();
binding.reportToggleButton.setOnClickListener(view -> { binding.reportToggleButton.setOnClickListener(view -> {
editBoxEnabled =! editBoxEnabled; editBoxEnabled =! editBoxEnabled;
binding.ScoutingEditBox.setVisibility(editBoxEnabled ? GONE : VISIBLE); binding.ScoutingEditBox.setVisibility(editBoxEnabled ? GONE : VISIBLE);
binding.reportToggleButton.setText(editBoxEnabled ? "▲ report" : "▼ report"); binding.reportToggleButton.setText(editBoxEnabled ? "▲ report" : "▼ report");
}); });
generateScoutingTemplate(SettingsManager.getMatchNum()); binding.reportCopyButton.setOnClickListener(v -> {
// ClipData e = new ClipData();
ClipboardManager clipboardManager = (ClipboardManager) getContext().getSystemService(CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText(
"Scouting report",
binding.scoutingReportEdittext.getText().toString()
);
clipboardManager.setPrimaryClip(clipData);
AlertManager.toast("Copied report to clipboard!");
});
asm = new AutoSaveManager(() -> SettingsManager.setScoutingReport(evcode, matchIndex, binding.scoutingReportEdittext.getText().toString()), 300);
asm.start();
binding.scoutingReportEdittext.addTextChangedListener(new TextWatcher() {
@Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
asm.update();
}
@Override public void afterTextChanged(Editable editable) {}
});
return binding.getRoot(); return binding.getRoot();
} }
private void updateButtons(){
binding.matchNum.setText(String.valueOf(ourMatches[matchIndex].matchIndex));
binding.scoutUpButton.setEnabled(matchIndex < ourMatches.length-1);
binding.scoutDownButton.setEnabled(matchIndex > 0);
SettingsManager.setReportIndex(matchIndex, evcode);
String report = SettingsManager.getScoutingReport(evcode, matchIndex);
if(report.isEmpty()) report = generateScoutingTemplate(ourMatches[matchIndex]);
binding.scoutingReportEdittext.setText(report);
}
public void moveToFragment(Fragment newFragment){ public void moveToFragment(Fragment newFragment){
// consider using Java coding conventions (upper first char class names!!!) // consider using Java coding conventions (upper first char class names!!!)
FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
@@ -87,13 +152,9 @@ public class DataParentFragment extends Fragment {
// Generate format for scouting data // Generate format for scouting data
public void generateScoutingTemplate(int currentMatch){ private String generateScoutingTemplate(frcMatch nextMatch){
boolean isBlueAlliance = event.getIsBlueAlliance(teamNum, nextMatch);
int teamNum = SettingsManager.getTeamNum();
boolean isBlueAlliance = false;
frcMatch nextMatch = event.getNextTeamMatch(teamNum, currentMatch);
List<frcTeam> ourAlliance = new ArrayList<>(); List<frcTeam> ourAlliance = new ArrayList<>();
@@ -101,15 +162,15 @@ public class DataParentFragment extends Fragment {
for(int a = 0; a < nextMatch.blueAlliance.length; a++) for(int a = 0; a < nextMatch.blueAlliance.length; a++)
if(nextMatch.blueAlliance[a] != teamNum){ if(nextMatch.blueAlliance[a] != teamNum){
(!isBlueAlliance ? ourAlliance : opposingAlliance).add(event.getTeamByNum(nextMatch.blueAlliance[a])); (isBlueAlliance ? ourAlliance : opposingAlliance).add(event.getTeamByNum(nextMatch.blueAlliance[a]));
} }
for(int a = 0; a < nextMatch.redAlliance.length; a++) for(int a = 0; a < nextMatch.redAlliance.length; a++)
if(nextMatch.redAlliance[a] != teamNum){ if(nextMatch.redAlliance[a] != teamNum){
(isBlueAlliance ? ourAlliance : opposingAlliance).add(event.getTeamByNum(nextMatch.redAlliance[a])); (!isBlueAlliance ? ourAlliance : opposingAlliance).add(event.getTeamByNum(nextMatch.redAlliance[a]));
} }
String output = "Match: " + (nextMatch.matchIndex+1) + "\n"; String output = "Match: " + (nextMatch.matchIndex) + "\n";
output += "## Our Alliance ##"; output += "## Our Alliance ##";
output += getTeamNameAndNum(ourAlliance.get(0)); output += getTeamNameAndNum(ourAlliance.get(0));
@@ -119,7 +180,8 @@ public class DataParentFragment extends Fragment {
output += getTeamNameAndNum(opposingAlliance.get(1)); output += getTeamNameAndNum(opposingAlliance.get(1));
output += getTeamNameAndNum(opposingAlliance.get(2)); output += getTeamNameAndNum(opposingAlliance.get(2));
binding.scoutingReportEdittext.setText(output);
return output;
} }
@@ -62,6 +62,7 @@ public class FieldDataFragment extends Fragment {
for (int i = 0; i < filenames.size(); i++) { for (int i = 0; i < filenames.size(); i++) {
try { try {
System.out.println("Loading: " + filenames.get(i));
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filenames.get(i), match_values, match_transferValues); ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filenames.get(i), match_values, match_transferValues);
if (psda.data.array[fieldIndex] != null && psda.data.array[fieldIndex].get() != null && !psda.data.array[fieldIndex].isNull()) if (psda.data.array[fieldIndex] != null && psda.data.array[fieldIndex].get() != null && !psda.data.array[fieldIndex].isNull())
teamData.add(psda.data.array[fieldIndex]); teamData.add(psda.data.array[fieldIndex]);
@@ -1,5 +1,6 @@
package com.ridgebotics.ridgescout.ui.scouting; package com.ridgebotics.ridgescout.ui.scouting;
import static com.ridgebotics.ridgescout.utility.AutoSaveManager.AUTO_SAVE_DELAY;
import static com.ridgebotics.ridgescout.utility.Colors.rescout_color; import static com.ridgebotics.ridgescout.utility.Colors.rescout_color;
import static com.ridgebotics.ridgescout.utility.Colors.saved_color; import static com.ridgebotics.ridgescout.utility.Colors.saved_color;
import static com.ridgebotics.ridgescout.utility.Colors.unsaved_color; import static com.ridgebotics.ridgescout.utility.Colors.unsaved_color;
@@ -143,7 +144,7 @@ public class MatchScoutingFragment extends Fragment {
boolean edited = false; boolean edited = false;
boolean rescout = false; boolean rescout = false;
ToggleTitleView[] titles; ToggleTitleView[] titles;
AutoSaveManager asm = new AutoSaveManager(this::save); AutoSaveManager asm = new AutoSaveManager(this::save, AUTO_SAVE_DELAY);
@@ -1,5 +1,6 @@
package com.ridgebotics.ridgescout.ui.scouting; package com.ridgebotics.ridgescout.ui.scouting;
import static com.ridgebotics.ridgescout.utility.AutoSaveManager.AUTO_SAVE_DELAY;
import static com.ridgebotics.ridgescout.utility.Colors.rescout_color; import static com.ridgebotics.ridgescout.utility.Colors.rescout_color;
import static com.ridgebotics.ridgescout.utility.Colors.saved_color; import static com.ridgebotics.ridgescout.utility.Colors.saved_color;
import static com.ridgebotics.ridgescout.utility.Colors.unsaved_color; import static com.ridgebotics.ridgescout.utility.Colors.unsaved_color;
@@ -74,7 +75,7 @@ public class PitScoutingFragment extends Fragment {
String fileUsernames = ""; String fileUsernames = "";
ToggleTitleView[] titles; ToggleTitleView[] titles;
AutoSaveManager asm = new AutoSaveManager(this::save); AutoSaveManager asm = new AutoSaveManager(this::save, AUTO_SAVE_DELAY);
ArrayList<DataType> dataTypes; ArrayList<DataType> dataTypes;
@@ -4,13 +4,14 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
public class AutoSaveManager { public class AutoSaveManager {
private static final long AUTO_SAVE_DELAY = 2000; // 2 seconds public static final long AUTO_SAVE_DELAY = 2000; // 2 seconds
private final Handler handler; private final Handler handler;
private final Runnable autoSaveRunnable; private final Runnable autoSaveRunnable;
private boolean isAutoSaveScheduled = false; private boolean isAutoSaveScheduled = false;
private final AutoSaveFunction autoSaveFunction; private final AutoSaveFunction autoSaveFunction;
public boolean isRunning = false; public boolean isRunning = false;
private long delay;
// Functional interface for the auto-save function // Functional interface for the auto-save function
@FunctionalInterface @FunctionalInterface
@@ -18,8 +19,9 @@ public class AutoSaveManager {
void save(); void save();
} }
public AutoSaveManager(AutoSaveFunction autoSaveFunction) { public AutoSaveManager(AutoSaveFunction autoSaveFunction, long delay) {
this.autoSaveFunction = autoSaveFunction; this.autoSaveFunction = autoSaveFunction;
this.delay = delay;
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
autoSaveRunnable = new Runnable() { autoSaveRunnable = new Runnable() {
@Override @Override
@@ -32,6 +32,10 @@ public class SettingsManager {
public static final String EnableQuickAllianceChangeKey = "enable_quick_alliance_change"; public static final String EnableQuickAllianceChangeKey = "enable_quick_alliance_change";
public static final String CustomEventsKey = "enable_custom_event"; public static final String CustomEventsKey = "enable_custom_event";
public static final String ScoutingReportKey = "scouting_report";
public static final String ScoutingReportIndexKey = "scouting_report_index";
public static Map defaults = getDefaults(); public static Map defaults = getDefaults();
private static Map getDefaults(){ private static Map getDefaults(){
Map<String, Object> hm = new HashMap<>(); Map<String, Object> hm = new HashMap<>();
@@ -52,6 +56,8 @@ public class SettingsManager {
hm.put(FTPSendMetaFiles, false); hm.put(FTPSendMetaFiles, false);
hm.put(EnableQuickAllianceChangeKey, false); hm.put(EnableQuickAllianceChangeKey, false);
hm.put(CustomEventsKey, false); hm.put(CustomEventsKey, false);
hm.put(ScoutingReportKey, "");
hm.put(ScoutingReportIndexKey, 0);
return hm; return hm;
} }
@@ -136,5 +142,12 @@ public class SettingsManager {
public static String getScoutingReport(String eventCode, int matchNum){return prefs.getString(ScoutingReportKey+"_"+eventCode+"_"+matchNum, (String) defaults.get(ScoutingReportKey));}
public static void setScoutingReport(String eventCode, int matchNum, String data){getEditor().putString(ScoutingReportKey+"_"+eventCode+"_"+matchNum,data).apply();}
public static int getReportMatchIndex(String eveode){return prefs.getInt( ScoutingReportIndexKey+"_"+eveode, (int) defaults.get(ScoutingReportIndexKey));}
public static void setReportIndex(int num, String evcode){ getEditor().putInt( ScoutingReportIndexKey+"_"+evcode,num).apply();}
} }
@@ -22,15 +22,64 @@
android:id="@+id/ScoutingEditBox" android:id="@+id/ScoutingEditBox"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp" android:layout_height="200dp"
android:layout_margin="5dp"
android:background="@drawable/border"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
tools:layout_editor_absoluteX="48dp"
tools:visibility="visible"> tools:visibility="visible">
<TextView
android:id="@+id/matchNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="42"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
app:layout_constraintBottom_toTopOf="@+id/report_copy_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/scout_up_button"
app:layout_constraintTop_toTopOf="parent" />
<EditText <EditText
android:id="@+id/scouting_report_edittext" android:id="@+id/scouting_report_edittext"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" /> android:layout_height="match_parent"
app:layout_constraintEnd_toStartOf="@+id/scout_up_button"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="5dp" />
<Button
android:id="@+id/scout_up_button"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="5dp"
android:text="▲"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@+id/matchNum"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/scout_down_button"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="5dp"
android:text="▼"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@+id/report_copy_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/matchNum" />
<Button
android:id="@+id/report_copy_button"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="5dp"
android:text="C"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>