mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-09 00:37:59 -06:00
Add CSV exporting
This commit is contained in:
@@ -6,10 +6,10 @@ Ridgebotics 2025 scouting app in Android
|
|||||||
- Make the "Report" menu, A tool that lets users select data to display from the the teams and compare menus.
|
- Make the "Report" menu, A tool that lets users select data to display from the the teams and compare menus.
|
||||||
- Make practice mode
|
- Make practice mode
|
||||||
#### Data Analysis:
|
#### Data Analysis:
|
||||||
- Add CSV exporting of match scouting data.
|
|
||||||
- Statbotics intigration
|
- Statbotics intigration
|
||||||
- AI overview of scouting data for a team???
|
- AI overview of scouting data for a team???
|
||||||
#### Functionality:
|
#### Functionality:
|
||||||
|
- When a field is created, make updated scouting data return null values, not the default value
|
||||||
- Make the system for blank and unselected fields better.
|
- Make the system for blank and unselected fields better.
|
||||||
- Add more types of data fields.
|
- Add more types of data fields.
|
||||||
- Make server software to allow for easy sync over wifi
|
- Make server software to allow for easy sync over wifi
|
||||||
@@ -21,7 +21,6 @@ Ridgebotics 2025 scouting app in Android
|
|||||||
#### Data Analysis:
|
#### Data Analysis:
|
||||||
- Make the "Compare" menu, cross comparing team's stats.
|
- Make the "Compare" menu, cross comparing team's stats.
|
||||||
#### Functionality:
|
#### Functionality:
|
||||||
- Make pit and match data field builder UIs. I don't want to have to keep editing a variable
|
|
||||||
|
|
||||||
|
|
||||||
## Done:
|
## Done:
|
||||||
@@ -30,6 +29,7 @@ Ridgebotics 2025 scouting app in Android
|
|||||||
#### Data Analysis:
|
#### Data Analysis:
|
||||||
- Add "history" view type to the teams view menu.
|
- Add "history" view type to the teams view menu.
|
||||||
- Sentiment analysis of text input type
|
- Sentiment analysis of text input type
|
||||||
|
- Add CSV exporting of match scouting data.
|
||||||
#### Functionality:
|
#### Functionality:
|
||||||
- Improve the code scanning progress indicator. It has a rounding error, I think.
|
- Improve the code scanning progress indicator. It has a rounding error, I think.
|
||||||
- Fix navigation crashes.
|
- Fix navigation crashes.
|
||||||
@@ -37,3 +37,4 @@ Ridgebotics 2025 scouting app in Android
|
|||||||
- Make the file browser UI
|
- Make the file browser UI
|
||||||
- Bluetooth data sync
|
- Bluetooth data sync
|
||||||
- Formalize error messages & stacktraces
|
- Formalize error messages & stacktraces
|
||||||
|
- Make pit and match data field builder UIs. I don't want to have to keep editing a variable
|
||||||
|
|||||||
@@ -40,6 +40,15 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -64,12 +64,12 @@ public class ScoutingDataWriter {
|
|||||||
case 1: // Int
|
case 1: // Int
|
||||||
dataTypes[i] = intType.newNull(values[version][i].name);
|
dataTypes[i] = intType.newNull(values[version][i].name);
|
||||||
dataTypes[i].forceSetValue(objects.get(i+2).get());
|
dataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||||
System.out.println("Loaded INT: " + values[version][i].name + ", ("+ dataTypes[i].get() +")");
|
//System.out.println("Loaded INT: " + values[version][i].name + ", ("+ dataTypes[i].get() +")");
|
||||||
break;
|
break;
|
||||||
case 2: // String
|
case 2: // String
|
||||||
dataTypes[i] = stringType.newNull(values[version][i].name);
|
dataTypes[i] = stringType.newNull(values[version][i].name);
|
||||||
dataTypes[i].forceSetValue(objects.get(i+2).get());
|
dataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||||
System.out.println("Loaded STR: " + values[version][i].name + ", ("+ dataTypes[i].get() +")");
|
//System.out.println("Loaded STR: " + values[version][i].name + ", ("+ dataTypes[i].get() +")");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package com.astatin3.scoutingapp2025.ui.transfer;
|
||||||
|
|
||||||
|
import static com.astatin3.scoutingapp2025.utility.DataManager.evcode;
|
||||||
|
import static com.astatin3.scoutingapp2025.utility.DataManager.event;
|
||||||
|
import static com.astatin3.scoutingapp2025.utility.DataManager.match_latest_values;
|
||||||
|
import static com.astatin3.scoutingapp2025.utility.DataManager.pit_latest_values;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
|
|
||||||
|
import com.astatin3.scoutingapp2025.scoutingData.ScoutingDataWriter;
|
||||||
|
import com.astatin3.scoutingapp2025.types.data.dataType;
|
||||||
|
import com.astatin3.scoutingapp2025.types.frcMatch;
|
||||||
|
import com.astatin3.scoutingapp2025.types.frcTeam;
|
||||||
|
import com.astatin3.scoutingapp2025.utility.AlertManager;
|
||||||
|
import com.astatin3.scoutingapp2025.utility.DataManager;
|
||||||
|
import com.astatin3.scoutingapp2025.utility.fileEditor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class CSVExport {
|
||||||
|
private static String[] alliances = {"red", "blue"};
|
||||||
|
|
||||||
|
|
||||||
|
public static void exportMatches(Context c){
|
||||||
|
DataManager.reload_event();
|
||||||
|
DataManager.reload_match_fields();
|
||||||
|
|
||||||
|
String data = "";
|
||||||
|
|
||||||
|
data += ("num,alliance,alliance_position,teamnum,");
|
||||||
|
for(int i = 0; i < match_latest_values.length; i++){
|
||||||
|
data += (match_latest_values[i].name + ",");
|
||||||
|
}
|
||||||
|
data += ("\n");
|
||||||
|
|
||||||
|
|
||||||
|
for(int matchNum = 1; matchNum <= event.matches.size(); matchNum++){
|
||||||
|
for(int allianceIndex = 0; allianceIndex <= 1; allianceIndex++){
|
||||||
|
String alliance = alliances[allianceIndex];
|
||||||
|
for(int alliancePos = 1; alliancePos <= 3; alliancePos++){
|
||||||
|
data += (matchNum + ",");
|
||||||
|
data += (alliance + ",");
|
||||||
|
data += (alliancePos + ",");
|
||||||
|
|
||||||
|
frcMatch match = event.matches.get(matchNum-1);
|
||||||
|
int teamNum = 0;
|
||||||
|
|
||||||
|
if(allianceIndex == 0){
|
||||||
|
teamNum = match.redAlliance[alliancePos-1];
|
||||||
|
}else{
|
||||||
|
teamNum = match.blueAlliance[alliancePos-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
data += (teamNum + ",");
|
||||||
|
|
||||||
|
String filename = evcode+"-"+matchNum+"-"+alliance+"-"+alliancePos+"-"+teamNum+".matchscoutdata";
|
||||||
|
if(!fileEditor.fileExist(filename)){
|
||||||
|
data += ("null,".repeat(match_latest_values.length));
|
||||||
|
}else{
|
||||||
|
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues);
|
||||||
|
dataType[] types = psdr.data.array;
|
||||||
|
for(int i = 0; i < types.length; i++) {
|
||||||
|
data += (types[i].get() + ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data += ("\n");
|
||||||
|
}}}
|
||||||
|
|
||||||
|
shareContent(c, evcode+"-matches.csv", data, "text/plain");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void exportPits(Context c){
|
||||||
|
DataManager.reload_event();
|
||||||
|
DataManager.reload_pit_fields();
|
||||||
|
|
||||||
|
String data = "";
|
||||||
|
|
||||||
|
data += ("teamnum,teamname,city,teamnum,stateOrProv,school,country,startingYear,");
|
||||||
|
for(int i = 0; i < pit_latest_values.length; i++){
|
||||||
|
data += (pit_latest_values[i].name + ",");
|
||||||
|
}
|
||||||
|
data += ("\n");
|
||||||
|
|
||||||
|
|
||||||
|
for(int teamIndex = 0; teamIndex < event.teams.size(); teamIndex++){
|
||||||
|
frcTeam team = event.teams.get(teamIndex);
|
||||||
|
|
||||||
|
data += (team.teamNumber + ",");
|
||||||
|
data += (team.teamName + ",");
|
||||||
|
data += (team.city + ",");
|
||||||
|
data += (team.stateOrProv + ",");
|
||||||
|
data += (team.school + ",");
|
||||||
|
data += (team.country + ",");
|
||||||
|
data += (team.startingYear + ",");
|
||||||
|
|
||||||
|
String filename = evcode+"-"+team.teamNumber+".pitscoutdata";
|
||||||
|
if(!fileEditor.fileExist(filename)){
|
||||||
|
data += ("null,".repeat(pit_latest_values.length));
|
||||||
|
}else{
|
||||||
|
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.pit_values, DataManager.pit_transferValues);
|
||||||
|
dataType[] types = psdr.data.array;
|
||||||
|
for(int i = 0; i < types.length; i++) {
|
||||||
|
data += (types[i].get() + ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data += ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.out.print(data);
|
||||||
|
|
||||||
|
shareContent(c, evcode+"-pits.csv", data, "text/plain");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void shareContent(Context context, String fileName, String content, String mimeType) {
|
||||||
|
try {
|
||||||
|
File file = new File(context.getCacheDir(), fileName);
|
||||||
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
fos.write(content.getBytes());
|
||||||
|
fos.close();
|
||||||
|
|
||||||
|
Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
|
||||||
|
|
||||||
|
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||||
|
shareIntent.setType(mimeType);
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||||
|
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
|
||||||
|
context.startActivity(Intent.createChooser(shareIntent, "Share using"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
AlertManager.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package com.astatin3.scoutingapp2025.ui.transfer;
|
|||||||
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -21,14 +22,12 @@ import com.astatin3.scoutingapp2025.ui.transfer.codes.CodeGeneratorView;
|
|||||||
public class TransferFragment extends Fragment {
|
public class TransferFragment extends Fragment {
|
||||||
private FragmentTransferBinding binding;
|
private FragmentTransferBinding binding;
|
||||||
|
|
||||||
private boolean submenu = false;
|
// private enum TransferTypes {
|
||||||
|
// CAMERA,
|
||||||
private enum TransferTypes {
|
// BLUETOOTH,
|
||||||
CAMERA,
|
// LOCAL_WIFI,
|
||||||
BLUETOOTH,
|
// SCOUTING_SERVER
|
||||||
LOCAL_WIFI,
|
// }
|
||||||
SCOUTING_SERVER
|
|
||||||
}
|
|
||||||
|
|
||||||
String evcode;
|
String evcode;
|
||||||
|
|
||||||
@@ -68,6 +67,7 @@ public class TransferFragment extends Fragment {
|
|||||||
if(evcode.equals("unset")){
|
if(evcode.equals("unset")){
|
||||||
binding.noEventError.setVisibility(View.VISIBLE);
|
binding.noEventError.setVisibility(View.VISIBLE);
|
||||||
binding.uploadButton.setVisibility(View.GONE);
|
binding.uploadButton.setVisibility(View.GONE);
|
||||||
|
binding.CSVButton.setVisibility(View.GONE);
|
||||||
binding.downloadButton.setVisibility(View.VISIBLE);
|
binding.downloadButton.setVisibility(View.VISIBLE);
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
@@ -76,6 +76,34 @@ public class TransferFragment extends Fragment {
|
|||||||
start_upload();
|
start_upload();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
binding.CSVButton.setOnClickListener(v -> {
|
||||||
|
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.setPositiveButton("Match data", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
CSVExport.exportMatches(getContext());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.show();
|
||||||
|
});
|
||||||
|
|
||||||
if(!latestSettings.settings.get_wifi_mode())
|
if(!latestSettings.settings.get_wifi_mode())
|
||||||
binding.TBAButton.setVisibility(View.GONE);
|
binding.TBAButton.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ public class DataManager {
|
|||||||
public static String evcode;
|
public static String evcode;
|
||||||
public static frcEvent event;
|
public static frcEvent event;
|
||||||
public static void reload_event(){
|
public static void reload_event(){
|
||||||
evcode = getevcode(); event = frcEvent.decode(fileEditor.readFile(evcode + ".eventdata"));
|
evcode = getevcode();
|
||||||
|
event = frcEvent.decode(fileEditor.readFile(evcode + ".eventdata"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getevcode() {
|
public static String getevcode() {
|
||||||
|
|||||||
@@ -25,8 +25,7 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
tools:visibility="gone">
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/uploadButton"
|
android:id="@+id/uploadButton"
|
||||||
@@ -39,6 +38,17 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/CSVButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CSV"
|
||||||
|
android:textSize="34sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/downloadButton"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/uploadButton" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/downloadButton"
|
android:id="@+id/downloadButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -13,18 +13,6 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/file_selector_searchbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:background="#D33D3D3D"
|
|
||||||
android:ems="10"
|
|
||||||
android:inputType="text"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@@ -47,4 +35,16 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/file_selector_searchbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="#D33D3D3D"
|
||||||
|
android:ems="10"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<cache-path name="shared_files" path="/" />
|
||||||
|
</paths>
|
||||||
Reference in New Issue
Block a user