From c8c278b31670555de1a9638008b8b1f415d1bf6d Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Sat, 12 Apr 2025 14:22:27 -0600 Subject: [PATCH] Finish up report tool --- .../ridgescout/types/frcEvent.java | 16 ++++ .../ui/data/DataParentFragment.java | 88 ++++++++++++++++--- .../ridgescout/ui/data/FieldDataFragment.java | 1 + .../ui/scouting/MatchScoutingFragment.java | 3 +- .../ui/scouting/PitScoutingFragment.java | 3 +- .../ridgescout/utility/AutoSaveManager.java | 6 +- .../ridgescout/utility/SettingsManager.java | 13 +++ .../main/res/layout/fragment_data_parent.xml | 53 ++++++++++- 8 files changed, 164 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/frcEvent.java b/app/src/main/java/com/ridgebotics/ridgescout/types/frcEvent.java index 066e029..a2bebca 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/frcEvent.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/frcEvent.java @@ -165,4 +165,20 @@ public class frcEvent { } 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; + + } } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataParentFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataParentFragment.java index 2883678..ece2dca 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataParentFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/DataParentFragment.java @@ -1,8 +1,10 @@ package com.ridgebotics.ridgescout.ui.data; +import static android.content.Context.CLIPBOARD_SERVICE; import static android.view.View.GONE; import static android.view.View.VISIBLE; +import static androidx.core.content.ContextCompat.getSystemService; 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_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.match_latest_values; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -26,6 +33,8 @@ import com.ridgebotics.ridgescout.types.frcMatch; import com.ridgebotics.ridgescout.types.frcTeam; import com.ridgebotics.ridgescout.ui.FieldBorderedRow; 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.SettingsManager; @@ -36,11 +45,15 @@ import java.util.List; public class DataParentFragment extends Fragment { private FragmentDataParentBinding binding; - 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, @Nullable Bundle savedInstanceState) { @@ -63,17 +76,69 @@ public class DataParentFragment extends Fragment { 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 -> { editBoxEnabled =! editBoxEnabled; binding.ScoutingEditBox.setVisibility(editBoxEnabled ? GONE : VISIBLE); 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(); } + 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){ // consider using Java coding conventions (upper first char class names!!!) FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); @@ -87,13 +152,9 @@ public class DataParentFragment extends Fragment { // 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 ourAlliance = new ArrayList<>(); @@ -101,15 +162,15 @@ public class DataParentFragment extends Fragment { for(int a = 0; a < nextMatch.blueAlliance.length; a++) 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++) 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 += getTeamNameAndNum(ourAlliance.get(0)); @@ -119,7 +180,8 @@ public class DataParentFragment extends Fragment { output += getTeamNameAndNum(opposingAlliance.get(1)); output += getTeamNameAndNum(opposingAlliance.get(2)); - binding.scoutingReportEdittext.setText(output); + + return output; } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldDataFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldDataFragment.java index c414333..7eb4d12 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldDataFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/data/FieldDataFragment.java @@ -62,6 +62,7 @@ public class FieldDataFragment extends Fragment { for (int i = 0; i < filenames.size(); i++) { try { + System.out.println("Loading: " + filenames.get(i)); 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()) teamData.add(psda.data.array[fieldIndex]); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java index ea36b8a..dbabc5e 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/MatchScoutingFragment.java @@ -1,5 +1,6 @@ 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.saved_color; import static com.ridgebotics.ridgescout.utility.Colors.unsaved_color; @@ -143,7 +144,7 @@ public class MatchScoutingFragment extends Fragment { boolean edited = false; boolean rescout = false; ToggleTitleView[] titles; - AutoSaveManager asm = new AutoSaveManager(this::save); + AutoSaveManager asm = new AutoSaveManager(this::save, AUTO_SAVE_DELAY); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java index 7e65d79..654045e 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/scouting/PitScoutingFragment.java @@ -1,5 +1,6 @@ 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.saved_color; import static com.ridgebotics.ridgescout.utility.Colors.unsaved_color; @@ -74,7 +75,7 @@ public class PitScoutingFragment extends Fragment { String fileUsernames = ""; ToggleTitleView[] titles; - AutoSaveManager asm = new AutoSaveManager(this::save); + AutoSaveManager asm = new AutoSaveManager(this::save, AUTO_SAVE_DELAY); ArrayList dataTypes; diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/AutoSaveManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/AutoSaveManager.java index 882ad7b..bf2e0e3 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/AutoSaveManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/AutoSaveManager.java @@ -4,13 +4,14 @@ import android.os.Handler; import android.os.Looper; 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 Runnable autoSaveRunnable; private boolean isAutoSaveScheduled = false; private final AutoSaveFunction autoSaveFunction; public boolean isRunning = false; + private long delay; // Functional interface for the auto-save function @FunctionalInterface @@ -18,8 +19,9 @@ public class AutoSaveManager { void save(); } - public AutoSaveManager(AutoSaveFunction autoSaveFunction) { + public AutoSaveManager(AutoSaveFunction autoSaveFunction, long delay) { this.autoSaveFunction = autoSaveFunction; + this.delay = delay; handler = new Handler(Looper.getMainLooper()); autoSaveRunnable = new Runnable() { @Override diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java index 520d110..42a4c39 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java @@ -32,6 +32,10 @@ public class SettingsManager { public static final String EnableQuickAllianceChangeKey = "enable_quick_alliance_change"; 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(); private static Map getDefaults(){ Map hm = new HashMap<>(); @@ -52,6 +56,8 @@ public class SettingsManager { hm.put(FTPSendMetaFiles, false); hm.put(EnableQuickAllianceChangeKey, false); hm.put(CustomEventsKey, false); + hm.put(ScoutingReportKey, ""); + hm.put(ScoutingReportIndexKey, 0); 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();} + + } diff --git a/app/src/main/res/layout/fragment_data_parent.xml b/app/src/main/res/layout/fragment_data_parent.xml index 414e410..545c661 100644 --- a/app/src/main/res/layout/fragment_data_parent.xml +++ b/app/src/main/res/layout/fragment_data_parent.xml @@ -22,15 +22,64 @@ android:id="@+id/ScoutingEditBox" android:layout_width="match_parent" android:layout_height="200dp" + android:layout_margin="5dp" + android:background="@drawable/border" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" + tools:layout_editor_absoluteX="48dp" tools:visibility="visible"> + + + android:layout_width="0dp" + android:layout_height="match_parent" + app:layout_constraintEnd_toStartOf="@+id/scout_up_button" + app:layout_constraintStart_toStartOf="parent" + tools:layout_editor_absoluteY="5dp" /> + +