Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15be86453e | |||
| 795fa4e85a | |||
| fb0718c4ec | |||
| 03a1507ce2 | |||
| 2b753fcdb4 | |||
| ca703aab60 | |||
| 4854587ea9 |
@@ -1,6 +1,7 @@
|
|||||||
# Gradle files
|
# Gradle files
|
||||||
.gradle/
|
.gradle/
|
||||||
build/
|
build/
|
||||||
|
release/
|
||||||
|
|
||||||
# Local configuration file (sdk path, etc)
|
# Local configuration file (sdk path, etc)
|
||||||
local.properties
|
local.properties
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||

|

|
||||||
|
|
||||||
#### Docs are yet to be written, but here is an overview of the main features currently included in the app:
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Get it on F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/com.ridgebotics.ridgescout/)
|
||||||
|
**Note**: The F-Droid version of this app is not currently up to date with the GitHub release
|
||||||
|
|
||||||
|
[**Read the wiki**](https://github.com/Team4388/ScoutingApp2025/wiki)
|
||||||
|
|
||||||
|
[**Test Data**](https://github.com/Team4388/ScoutingApp2025/blob/main/2024week0-1728149849985.scoutbundle)
|
||||||
|
|
||||||
|
#### Here is an overview of the main features currently included in the app:
|
||||||
- This project is written for Android! No need for some kind of janky laptop charging setup.
|
- This project is written for Android! No need for some kind of janky laptop charging setup.
|
||||||
- Similar to ScoutingPASS, there are many diffrent types of fields that can be used to collect data.
|
- Similar to ScoutingPASS, there are many diffrent types of fields that can be used to collect data.
|
||||||
- The app is designed to handle updates to the fields on the fly, without loosing any data!
|
- The app is designed to handle updates to the fields on the fly, without loosing any data!
|
||||||
@@ -8,13 +17,12 @@
|
|||||||
- Dynamic displays based off of the diffrent fields.
|
- Dynamic displays based off of the diffrent fields.
|
||||||
- Data transfer including 2D codes, Bluetooth, and File Bundle.
|
- Data transfer including 2D codes, Bluetooth, and File Bundle.
|
||||||
- Exporting using CSV.
|
- Exporting using CSV.
|
||||||
|
- Deployment on F-Droid
|
||||||
|
- Data cloud sync using an FTP server
|
||||||
|
|
||||||
#### Things that are yet to be implemented:
|
#### Things that are yet to be implemented:
|
||||||
- A page that lets users cross-compare scouting data between teams. (Compare)
|
- A page that lets users cross-compare scouting data between teams. (Compare)
|
||||||
- A page that lets scouters more easily make reports to the drive team before a match starts (Report)
|
- A page that lets scouters more easily make reports to the drive team before a match starts (Report)
|
||||||
- More types of fields
|
|
||||||
- Data cloud sync using an FTP server
|
|
||||||
- Deployment on F-Droid
|
|
||||||
|
|
||||||
#### Things that may or may not be implemented:
|
#### Things that may or may not be implemented:
|
||||||
- Practice mode
|
- Practice mode
|
||||||
@@ -25,4 +33,5 @@
|
|||||||
### Screenshots
|
### Screenshots
|
||||||
|Match scouting interface|Field editor|Teams data viewer|
|
|Match scouting interface|Field editor|Teams data viewer|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
||||
|
||||
|
||||||
|
|
||||||
|
|||||||
@@ -3,20 +3,15 @@
|
|||||||
- Make practice mode??
|
- Make practice mode??
|
||||||
##### Data Analysis:
|
##### Data Analysis:
|
||||||
- Statbotics intigration???
|
- Statbotics intigration???
|
||||||
- Make the "Compare" menu, cross comparing team's stats.
|
|
||||||
##### Functionality:
|
##### Functionality:
|
||||||
- Add more types of data fields.
|
|
||||||
- Test the scouting app
|
|
||||||
- Write docs
|
|
||||||
|
|
||||||
### In Progress:
|
### In Progress:
|
||||||
##### Scouting:
|
##### Scouting:
|
||||||
##### Data Analysis:
|
##### Data Analysis:
|
||||||
- AI overview of scouting data for a team???
|
- AI overview of scouting data for a team???
|
||||||
- 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 the "Compare" menu, cross comparing team's stats.
|
||||||
##### Functionality:
|
##### Functionality:
|
||||||
- Make server software to allow for easy sync over wifi - FTP
|
|
||||||
- Deploy to F-Droid
|
|
||||||
|
|
||||||
### Done:
|
### Done:
|
||||||
##### Scouting:
|
##### Scouting:
|
||||||
@@ -36,3 +31,8 @@
|
|||||||
- 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
|
- Make pit and match data field builder UIs. I don't want to have to keep editing a variable
|
||||||
- Make the system for blank and unselected fields better.
|
- Make the system for blank and unselected fields better.
|
||||||
|
- Write docs
|
||||||
|
- Deploy to F-Droid
|
||||||
|
- Add more types of data fields.
|
||||||
|
- Make server software to allow for easy sync over wifi - FTP
|
||||||
|
- Test the scouting app
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ android {
|
|||||||
applicationId = "com.ridgebotics.ridgescout"
|
applicationId = "com.ridgebotics.ridgescout"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 4
|
versionCode = 6
|
||||||
versionName = "0.4"
|
versionName = "0.6"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
@@ -61,6 +61,7 @@ dependencies {
|
|||||||
implementation(libs.lifecycle.viewmodel.ktx)
|
implementation(libs.lifecycle.viewmodel.ktx)
|
||||||
implementation(libs.navigation.fragment)
|
implementation(libs.navigation.fragment)
|
||||||
implementation(libs.navigation.ui)
|
implementation(libs.navigation.ui)
|
||||||
|
implementation(libs.preference)
|
||||||
// implementation(libs.support.annotations)
|
// implementation(libs.support.annotations)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.ext.junit)
|
androidTestImplementation(libs.ext.junit)
|
||||||
@@ -79,14 +80,13 @@ dependencies {
|
|||||||
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
|
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// implementation("com.google.firebase:firebase-ml-modeldownloader:24.1.2")
|
// implementation("com.google.firebase:firebase-ml-modeldownloader:24.1.2")
|
||||||
// implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
|
// implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
|
||||||
|
|
||||||
implementation("org.tensorflow:tensorflow-lite-task-text:0.3.0")
|
implementation("org.tensorflow:tensorflow-lite-task-text:0.3.0")
|
||||||
|
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.9.0")
|
implementation("com.squareup.okhttp3:okhttp:4.9.0")
|
||||||
|
implementation("commons-net:commons-net:3.10.0")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 3,
|
|
||||||
"artifactType": {
|
|
||||||
"type": "APK",
|
|
||||||
"kind": "Directory"
|
|
||||||
},
|
|
||||||
"applicationId": "com.ridgebotics.ridgescout",
|
|
||||||
"variantName": "release",
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"type": "SINGLE",
|
|
||||||
"filters": [],
|
|
||||||
"attributes": [],
|
|
||||||
"versionCode": 4,
|
|
||||||
"versionName": "0.4",
|
|
||||||
"outputFile": "app-release.apk"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"elementType": "File",
|
|
||||||
"baselineProfiles": [
|
|
||||||
{
|
|
||||||
"minApi": 28,
|
|
||||||
"maxApi": 30,
|
|
||||||
"baselineProfiles": [
|
|
||||||
"baselineProfiles/1/app-release.dm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minApi": 31,
|
|
||||||
"maxApi": 2147483647,
|
|
||||||
"baselineProfiles": [
|
|
||||||
"baselineProfiles/0/app-release.dm"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"minSdkVersionForDexing": 24
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
android:required="true" />
|
android:required="true" />
|
||||||
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.ridgebotics.ridgescout.utility.settingsManager;
|
|||||||
import com.google.android.material.navigation.NavigationBarView;
|
import com.google.android.material.navigation.NavigationBarView;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@@ -51,6 +52,9 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
fields.save(fields.pitsFieldsFilename, fields.default_pit_fields);
|
fields.save(fields.pitsFieldsFilename, fields.default_pit_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||||
|
|
||||||
AlertManager.init(this);
|
AlertManager.init(this);
|
||||||
SentimentAnalysis.init(this);
|
SentimentAnalysis.init(this);
|
||||||
|
|
||||||
|
|||||||
@@ -55,10 +55,8 @@ public class FieldsFragment extends Fragment {
|
|||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
binding = FragmentDataFieldsBinding.inflate(inflater, container, false);
|
binding = FragmentDataFieldsBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
binding.revertVersionButton.setVisibility(View.VISIBLE);
|
|
||||||
binding.valueEditScrollview.setOnTouchListener((v, event) -> true);
|
binding.valueEditScrollview.setOnTouchListener((v, event) -> true);
|
||||||
|
|
||||||
|
|
||||||
binding.saveButton.setVisibility(View.GONE);
|
binding.saveButton.setVisibility(View.GONE);
|
||||||
binding.cancelEditButton.setVisibility(View.GONE);
|
binding.cancelEditButton.setVisibility(View.GONE);
|
||||||
binding.editButton.setVisibility(View.GONE);
|
binding.editButton.setVisibility(View.GONE);
|
||||||
@@ -124,6 +122,25 @@ public class FieldsFragment extends Fragment {
|
|||||||
tr.setBackgroundColor(unfocused_background_color);
|
tr.setBackgroundColor(unfocused_background_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(values.length > 1) {
|
||||||
|
binding.revertVersionButton.setVisibility(View.VISIBLE);
|
||||||
|
binding.revertVersionButton.setOnClickListener(v -> {
|
||||||
|
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||||
|
alert.setTitle("Warning!");
|
||||||
|
alert.setMessage("If there is any data set this version, it will be deleted!");
|
||||||
|
alert.setPositiveButton("OK", (dialog, which) -> {
|
||||||
|
inputType[][] newArr = new inputType[values.length - 1][];
|
||||||
|
System.arraycopy(values, 0, newArr, 0, values.length - 1);
|
||||||
|
if(fields.save(filename, newArr))
|
||||||
|
AlertManager.toast("Saved");
|
||||||
|
load_field_menu();
|
||||||
|
});
|
||||||
|
alert.setNegativeButton("Cancel", null);
|
||||||
|
alert.setCancelable(true);
|
||||||
|
alert.create().show();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display_fields(inputType[] version_values) {
|
private void display_fields(inputType[] version_values) {
|
||||||
@@ -182,10 +199,7 @@ public class FieldsFragment extends Fragment {
|
|||||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||||
alert.setTitle("Warning!");
|
alert.setTitle("Warning!");
|
||||||
alert.setMessage("Changing or removing some values will result in lost data!\nBut this will create a new field version, and you can revert at any time.");
|
alert.setMessage("Changing or removing some values will result in lost data!\nBut this will create a new field version, and you can revert at any time.");
|
||||||
alert.setPositiveButton("OK", null);
|
alert.setPositiveButton("OK", (dialog, which) -> {
|
||||||
alert.setNegativeButton("Cancel", null);
|
|
||||||
alert.setCancelable(true);
|
|
||||||
alert.setOnDismissListener(b -> {
|
|
||||||
inputType[][] currentValues = fields.load(filename);
|
inputType[][] currentValues = fields.load(filename);
|
||||||
assert currentValues != null;
|
assert currentValues != null;
|
||||||
inputType[][] newValues = new inputType[currentValues.length+1][];
|
inputType[][] newValues = new inputType[currentValues.length+1][];
|
||||||
@@ -198,11 +212,13 @@ public class FieldsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
// newValues[newValues.length-1] = values[values.length-1];
|
// newValues[newValues.length-1] = values[values.length-1];
|
||||||
|
|
||||||
boolean saved = fields.save(filename, newValues);
|
if(fields.save(filename, newValues))
|
||||||
AlertManager.alert("Saved", String.valueOf(saved));
|
AlertManager.toast("Saved");
|
||||||
|
|
||||||
Navigation.findNavController((Activity) getContext(), R.id.nav_host_fragment_activity_main).navigate(R.id.action_navigation_data_fields_to_navigation_data_fields_chooser);
|
Navigation.findNavController((Activity) getContext(), R.id.nav_host_fragment_activity_main).navigate(R.id.action_navigation_data_fields_to_navigation_data_fields_chooser);
|
||||||
});
|
});
|
||||||
|
alert.setNegativeButton("Cancel", null);
|
||||||
|
alert.setCancelable(true);
|
||||||
alert.create().show();
|
alert.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,7 +519,7 @@ public class FieldsFragment extends Fragment {
|
|||||||
newValues[newValues.length-1] = field;
|
newValues[newValues.length-1] = field;
|
||||||
values[values.length-1] = newValues;
|
values[values.length-1] = newValues;
|
||||||
|
|
||||||
AlertManager.alert("Test", String.valueOf(binding.fieldsArea.getReorderedIndexes()));
|
// AlertManager.alert("Test", String.valueOf(binding.fieldsArea.getReorderedIndexes()));
|
||||||
|
|
||||||
//TableRow tr = getTableRow(field);
|
//TableRow tr = getTableRow(field);
|
||||||
//binding.fieldsArea.addView(tr);
|
//binding.fieldsArea.addView(tr);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.settingsManager;
|
import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||||
@@ -282,41 +283,46 @@ public class TeamsFragment extends Fragment {
|
|||||||
|
|
||||||
public void add_individual_views(LinearLayout ll, String[] files) {
|
public void add_individual_views(LinearLayout ll, String[] files) {
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
String[] split = files[i].split("-");
|
try {
|
||||||
int match_num = Integer.parseInt(split[1]);
|
String[] split = files[i].split("-");
|
||||||
|
int match_num = Integer.parseInt(split[1]);
|
||||||
|
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
||||||
|
|
||||||
TextView tv = new TextView(getContext());
|
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);
|
|
||||||
ll.addView(tv);
|
|
||||||
|
|
||||||
for (int a = 0; a < psda.data.array.length; a++) {
|
|
||||||
tv = new TextView(getContext());
|
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
));
|
));
|
||||||
|
tv.setPadding(0, 40, 0, 5);
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||||
tv.setText(psda.data.array[a].getName());
|
tv.setText("M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username);
|
||||||
tv.setTextSize(25);
|
tv.setTextSize(30);
|
||||||
|
|
||||||
if (psda.data.array[a].isNull()) {
|
|
||||||
tv.setBackgroundColor(0xffff0000);
|
|
||||||
tv.setTextColor(0xff000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
ll.addView(tv);
|
ll.addView(tv);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
match_latest_values[a].add_individual_view(ll, psda.data.array[a]);
|
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]);
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
AlertManager.alert("Warning!", "Failure to load file " + files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,10 +335,14 @@ public class TeamsFragment extends Fragment {
|
|||||||
public void add_compiled_views(LinearLayout ll, String[] files){
|
public void add_compiled_views(LinearLayout ll, String[] files){
|
||||||
dataType[][] data = new dataType[match_latest_values.length][files.length];
|
dataType[][] data = new dataType[match_latest_values.length][files.length];
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
try {
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
||||||
for (int a = 0; a < data.length; a++) {
|
for (int a = 0; a < data.length; a++) {
|
||||||
data[a][i] = psda.data.array[a];
|
data[a][i] = psda.data.array[a];
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
AlertManager.alert("Warning!", "Failure to load file " + files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,10 +369,14 @@ public class TeamsFragment extends Fragment {
|
|||||||
public void add_history_views(LinearLayout ll, String[] files){
|
public void add_history_views(LinearLayout ll, String[] files){
|
||||||
dataType[][] data = new dataType[match_latest_values.length][files.length];
|
dataType[][] data = new dataType[match_latest_values.length][files.length];
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
try {
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
||||||
for (int a = 0; a < data.length; a++) {
|
for (int a = 0; a < data.length; a++) {
|
||||||
data[a][i] = psda.data.array[a];
|
data[a][i] = psda.data.array[a];
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
AlertManager.alert("Warning!", "Failure to load file " + files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,8 +310,14 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
default_fields();
|
default_fields();
|
||||||
set_indicator_color(unsaved_color);
|
set_indicator_color(unsaved_color);
|
||||||
}else{
|
}else{
|
||||||
get_fields();
|
try {
|
||||||
set_indicator_color(saved_color);
|
get_fields();
|
||||||
|
set_indicator_color(saved_color);
|
||||||
|
} catch (Exception e){
|
||||||
|
AlertManager.error(e);
|
||||||
|
default_fields();
|
||||||
|
set_indicator_color(unsaved_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asm.start();
|
asm.start();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.settingsManager;
|
import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||||
@@ -74,9 +75,10 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
types[i] = pit_latest_values[i].getViewValue();
|
types[i] = pit_latest_values[i].getViewValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ScoutingDataWriter.save(pit_values.length-1, username, filename, types))
|
if(ScoutingDataWriter.save(pit_values.length-1, username, filename, types)) {
|
||||||
System.out.println("Saved!");
|
System.out.println("Saved!");
|
||||||
else
|
AlertManager.toast("Saved " + filename);
|
||||||
|
}else
|
||||||
System.out.println("Error saving");
|
System.out.println("Error saving");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,8 +119,14 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
default_fields();
|
default_fields();
|
||||||
set_indicator_color(unsaved_color);
|
set_indicator_color(unsaved_color);
|
||||||
}else{
|
}else{
|
||||||
get_fields();
|
try {
|
||||||
set_indicator_color(saved_color);
|
get_fields();
|
||||||
|
set_indicator_color(saved_color);
|
||||||
|
} catch (Exception e){
|
||||||
|
AlertManager.error(e);
|
||||||
|
default_fields();
|
||||||
|
set_indicator_color(unsaved_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asm.start();
|
asm.start();
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
package com.ridgebotics.ridgescout.ui.settings;
|
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.FTPServer;
|
||||||
|
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.defaults;
|
||||||
|
import static com.ridgebotics.ridgescout.utility.settingsManager.getEditor;
|
||||||
|
import static com.ridgebotics.ridgescout.utility.settingsManager.prefs;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -13,11 +26,14 @@ import android.widget.CheckBox;
|
|||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TableRow;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.google.android.material.divider.MaterialDivider;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentSettingsBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentSettingsBinding;
|
||||||
import com.ridgebotics.ridgescout.types.data.intType;
|
import com.ridgebotics.ridgescout.types.data.intType;
|
||||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||||
@@ -27,9 +43,14 @@ import com.skydoves.powerspinner.IconSpinnerAdapter;
|
|||||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||||
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
||||||
import com.skydoves.powerspinner.PowerSpinnerView;
|
import com.skydoves.powerspinner.PowerSpinnerView;
|
||||||
|
import com.skydoves.powerspinner.SpinnerGravity;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.units.qual.C;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
||||||
public class settingsFragment extends Fragment {
|
public class settingsFragment extends Fragment {
|
||||||
@@ -37,9 +58,21 @@ public class settingsFragment extends Fragment {
|
|||||||
private android.widget.ScrollView ScrollArea;
|
private android.widget.ScrollView ScrollArea;
|
||||||
private android.widget.TableLayout Table;
|
private android.widget.TableLayout Table;
|
||||||
|
|
||||||
private void setDropdownItems(Spinner dropdown, String[] items){
|
// private void setDropdownItems(Spinner dropdown, String[] items){
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_spinner_item, items);
|
// ArrayAdapter<String> adapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_spinner_item, items);
|
||||||
dropdown.setAdapter(adapter);
|
// 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){
|
private int safeToInt(String num){
|
||||||
@@ -52,6 +85,144 @@ public class settingsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
ViewGroup container, Bundle savedInstanceState) {
|
ViewGroup container, Bundle savedInstanceState) {
|
||||||
@@ -59,172 +230,19 @@ public class settingsFragment extends Fragment {
|
|||||||
binding = FragmentSettingsBinding.inflate(inflater, container, false);
|
binding = FragmentSettingsBinding.inflate(inflater, container, false);
|
||||||
View root = binding.getRoot();
|
View root = binding.getRoot();
|
||||||
|
|
||||||
EditText username = binding.username;
|
|
||||||
username.setText(settingsManager.getUsername());
|
|
||||||
username.addTextChangedListener(new TextWatcher() {
|
|
||||||
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
settingsManager.setUsername(username.getText().toString());
|
|
||||||
}
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PowerSpinnerView spinnerView = binding.eventDropdown;
|
|
||||||
|
|
||||||
List<IconSpinnerItem> iconSpinnerItems = new ArrayList<>();
|
|
||||||
|
|
||||||
String target_event_name = settingsManager.getEVCode();
|
|
||||||
int target_index = -1;
|
|
||||||
|
|
||||||
ArrayList<String> evlist = fileEditor.getEventList();
|
|
||||||
for(int i = 0; i < evlist.size(); i++){
|
|
||||||
if(evlist.get(i).equals(target_event_name)){
|
|
||||||
target_index = i;
|
|
||||||
}
|
|
||||||
iconSpinnerItems.add(new IconSpinnerItem(evlist.get(i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(spinnerView);
|
|
||||||
spinnerView.setSpinnerAdapter(iconSpinnerAdapter);
|
|
||||||
spinnerView.setItems(iconSpinnerItems);
|
|
||||||
// spinnerView.setLifecycleOwner(this);
|
|
||||||
|
|
||||||
if(!iconSpinnerItems.isEmpty() && target_index != -1){
|
|
||||||
spinnerView.selectItemByIndex(target_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
spinnerView.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener<IconSpinnerItem>() {
|
|
||||||
@Override
|
|
||||||
public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex,
|
|
||||||
IconSpinnerItem newItem) {
|
|
||||||
settingsManager.setEVCode(newItem.getText().toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PowerSpinnerView alliance_pos_spinnerView = binding.alliancePosDropdown;
|
|
||||||
|
|
||||||
List<IconSpinnerItem> alliance_pos_iconSpinnerItems = new ArrayList<>();
|
|
||||||
|
|
||||||
String target_alliance_pos = settingsManager.getAllyPos();
|
|
||||||
int alliance_pos_target_index = -1;
|
|
||||||
|
|
||||||
String[] alliance_pos_list = new String[]{"red-1", "red-2", "red-3",
|
String[] alliance_pos_list = new String[]{"red-1", "red-2", "red-3",
|
||||||
"blue-1", "blue-2", "blue-3"};
|
"blue-1", "blue-2", "blue-3"};
|
||||||
|
|
||||||
for(int i = 0; i < alliance_pos_list.length; i++){
|
addViews(addStringEdit("Username", UnameKey));
|
||||||
if(alliance_pos_list[i].equals(target_alliance_pos)){
|
addViews(addDropdownByString("Event Code", fileEditor.getEventList().toArray(new String[0]), SelEVCodeKey));
|
||||||
alliance_pos_target_index = i;
|
addViews(addDropdownByString("Alliance Position", alliance_pos_list, AllyPosKey));
|
||||||
}
|
addViews(addNumberEdit("Team Number", TeamNumKey));
|
||||||
alliance_pos_iconSpinnerItems.add(new IconSpinnerItem(alliance_pos_list[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
IconSpinnerAdapter alliance_pos_iconSpinnerAdapter = new IconSpinnerAdapter(alliance_pos_spinnerView);
|
View[] FTPDependency = addStringEdit("FTP Server", FTPServer);
|
||||||
alliance_pos_spinnerView.setSpinnerAdapter(alliance_pos_iconSpinnerAdapter);
|
View[] WifiDependency = addCheckbox("FTP Enabled", FTPEnabled, FTPDependency);
|
||||||
alliance_pos_spinnerView.setItems(alliance_pos_iconSpinnerItems);
|
addViews(addCheckbox("Wifi Mode", WifiModeKey, concatArrays(FTPDependency, WifiDependency)));
|
||||||
alliance_pos_spinnerView.setLifecycleOwner(this);
|
addViews(WifiDependency);
|
||||||
|
addViews(FTPDependency);
|
||||||
if(alliance_pos_target_index != -1){
|
|
||||||
alliance_pos_spinnerView.selectItemByIndex(alliance_pos_target_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
alliance_pos_spinnerView.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener<IconSpinnerItem>() {
|
|
||||||
@Override
|
|
||||||
public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex,
|
|
||||||
IconSpinnerItem newItem) {
|
|
||||||
settingsManager.setAllyPos(newItem.getText().toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// CheckBox practice_mode = binding.practiceMode;
|
|
||||||
// practice_mode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
|
|
||||||
// latestSettings.settings.set_practice_mode(isChecked);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// practice_mode.setChecked(latestSettings.settings.get_practice_mode());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EditText team_num = binding.teamNumber;
|
|
||||||
team_num.setText(String.valueOf(settingsManager.getTeamNum()));
|
|
||||||
team_num.addTextChangedListener(new TextWatcher() {
|
|
||||||
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
settingsManager.setTeamNum(safeToInt(team_num.getText().toString()));
|
|
||||||
}
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CheckBox wifi_mode = binding.wifiMode;
|
|
||||||
wifi_mode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
|
|
||||||
settingsManager.setWifiMode(isChecked);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
wifi_mode.setChecked(settingsManager.getWifiMode());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Button reset_button = binding.resetButton;
|
|
||||||
reset_button.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
|
||||||
alert.setTitle("Warning");
|
|
||||||
alert.setMessage("Do you really want to reset settings?");
|
|
||||||
alert.setCancelable(true);
|
|
||||||
|
|
||||||
alert.setPositiveButton("Ok", (dialog, which) -> {
|
|
||||||
// settingsManager.settings.defaultSettings();
|
|
||||||
username.setText(settingsManager.getUsername());
|
|
||||||
spinnerView.clearSelectedItem();
|
|
||||||
// practice_mode.setChecked(latestSettings.settings.get_practice_mode());
|
|
||||||
wifi_mode.setChecked(settingsManager.getWifiMode());
|
|
||||||
alliance_pos_spinnerView.selectItemByIndex(0);
|
|
||||||
team_num.setText(String.valueOf(settingsManager.getTeamNum()));
|
|
||||||
});
|
|
||||||
|
|
||||||
alert.setNegativeButton("Cancel", null);
|
|
||||||
alert.create().show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ import com.ridgebotics.ridgescout.utility.fileEditor;
|
|||||||
public class CSVExport {
|
public class CSVExport {
|
||||||
private static String[] alliances = {"red", "blue"};
|
private static String[] alliances = {"red", "blue"};
|
||||||
|
|
||||||
|
private static String safeCSV(String input){
|
||||||
|
return input.replace("\n", "").replace(",", ".").replace(";", ".");
|
||||||
|
}
|
||||||
|
|
||||||
public static void exportMatches(Context c){
|
public static void exportMatches(Context c){
|
||||||
DataManager.reload_event();
|
DataManager.reload_event();
|
||||||
@@ -55,10 +58,15 @@ public class CSVExport {
|
|||||||
if(!fileEditor.fileExist(filename)){
|
if(!fileEditor.fileExist(filename)){
|
||||||
data += ("null,".repeat(match_latest_values.length));
|
data += ("null,".repeat(match_latest_values.length));
|
||||||
}else{
|
}else{
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues);
|
try {
|
||||||
dataType[] types = psdr.data.array;
|
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues);
|
||||||
for(int i = 0; i < types.length; i++) {
|
dataType[] types = psdr.data.array;
|
||||||
data += (types[i].get() + ",");
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
data += (safeCSV(types[i].get().toString()) + ",");
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
data += ("null,".repeat(pit_latest_values.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -77,7 +85,7 @@ public class CSVExport {
|
|||||||
|
|
||||||
String data = "";
|
String data = "";
|
||||||
|
|
||||||
data += ("teamnum,teamname,city,teamnum,stateOrProv,school,country,startingYear,");
|
data += ("teamnum,teamname,city,stateOrProv,school,country,startingYear,");
|
||||||
for(int i = 0; i < pit_latest_values.length; i++){
|
for(int i = 0; i < pit_latest_values.length; i++){
|
||||||
data += (pit_latest_values[i].name + ",");
|
data += (pit_latest_values[i].name + ",");
|
||||||
}
|
}
|
||||||
@@ -99,10 +107,15 @@ public class CSVExport {
|
|||||||
if(!fileEditor.fileExist(filename)){
|
if(!fileEditor.fileExist(filename)){
|
||||||
data += ("null,".repeat(pit_latest_values.length));
|
data += ("null,".repeat(pit_latest_values.length));
|
||||||
}else{
|
}else{
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.pit_values, DataManager.pit_transferValues);
|
try {
|
||||||
dataType[] types = psdr.data.array;
|
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.pit_values, DataManager.pit_transferValues);
|
||||||
for(int i = 0; i < types.length; i++) {
|
dataType[] types = psdr.data.array;
|
||||||
data += (types[i].get() + ",");
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
data += (safeCSV(types[i].get().toString()) + ",");
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
data += ("null,".repeat(pit_latest_values.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
package com.ridgebotics.ridgescout.ui.transfer;
|
||||||
|
|
||||||
|
//import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||||
|
import static com.ridgebotics.ridgescout.utility.fileEditor.baseDir;
|
||||||
|
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||||
|
|
||||||
|
import org.apache.commons.net.ftp.FTP;
|
||||||
|
import org.apache.commons.net.ftp.FTPClient;
|
||||||
|
import org.apache.commons.net.ftp.FTPCmd;
|
||||||
|
import org.apache.commons.net.ftp.FTPFile;
|
||||||
|
import org.apache.commons.net.ftp.FTPReply;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
public class FTPSync extends Thread {
|
||||||
|
public static final String remoteBasePath = "/RidgeScout/";
|
||||||
|
public static final long timeTolerance = 60000; // One min
|
||||||
|
public static long lastSyncTime = 0;
|
||||||
|
|
||||||
|
public interface onResult {
|
||||||
|
void onResult(boolean error, int upCount, int downCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onResult onResult;
|
||||||
|
|
||||||
|
public static void sync(onResult onResult){
|
||||||
|
// DataManager.reload_event();
|
||||||
|
FTPSync ftpSync = new FTPSync();
|
||||||
|
ftpSync.onResult = onResult;
|
||||||
|
ftpSync.start();
|
||||||
|
|
||||||
|
lastSyncTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
FTPClient ftpClient;
|
||||||
|
|
||||||
|
// private class FileDate {
|
||||||
|
// public String filename;
|
||||||
|
// public Calendar lastModified;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private int upCount = 0;
|
||||||
|
private int downCount = 0;
|
||||||
|
|
||||||
|
private void downloadFile(FTPFile remoteFile, File localFile) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(localFile)) {
|
||||||
|
ftpClient.retrieveFile(remoteBasePath + remoteFile.getName(), fos);
|
||||||
|
}
|
||||||
|
Date d = getUtcTimestamp(remoteFile);
|
||||||
|
System.out.println(d);
|
||||||
|
setLocalFileTimestamp(localFile, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadFile(File localFile) throws IOException {
|
||||||
|
try (FileInputStream fis = new FileInputStream(localFile)) {
|
||||||
|
ftpClient.storeFile(remoteBasePath + localFile.getName(), fis);
|
||||||
|
}
|
||||||
|
setLocalFileTimestamp(localFile, new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
private FTPFile findRemoteFile(FTPFile[] remoteFiles, String fileName) {
|
||||||
|
for (FTPFile file : remoteFiles) {
|
||||||
|
if (file.getName().equals(fileName)) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date getUtcTimestamp(FTPFile file) {
|
||||||
|
return file.getTimestamp().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date getLocalFileUtcTimestamp(File file) {
|
||||||
|
return new Date(file.lastModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocalFileTimestamp(File file, Date date) {
|
||||||
|
file.setLastModified(date.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// private long longAbs(long n){
|
||||||
|
// return n>0 ? n : -n;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private boolean toleranceCompareAfter(Date d1, Date d2){
|
||||||
|
long diff = d1.getTime() - d2.getTime();
|
||||||
|
System.out.println(diff);
|
||||||
|
return diff > timeTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// localTimeZone = TimeZone.getDefault();
|
||||||
|
ftpClient = new FTPClient();
|
||||||
|
InetAddress address = InetAddress.getByName(settingsManager.getFTPServer());
|
||||||
|
ftpClient.connect(address);
|
||||||
|
ftpClient.login("anonymous", null);
|
||||||
|
ftpClient.enterLocalPassiveMode();
|
||||||
|
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
|
||||||
|
|
||||||
|
File localDir = new File(baseDir);
|
||||||
|
File[] localFiles = localDir.listFiles();
|
||||||
|
FTPFile[] remoteFiles = ftpClient.listFiles(remoteBasePath);
|
||||||
|
|
||||||
|
if (localFiles != null) {
|
||||||
|
for (File localFile : localFiles) {
|
||||||
|
if (localFile.isFile()) {
|
||||||
|
FTPFile remoteFile = findRemoteFile(remoteFiles, localFile.getName());
|
||||||
|
//
|
||||||
|
// Date t1 = getLocalFileUtcTimestamp(localFile);
|
||||||
|
// Date t2 = getUtcTimestamp(remoteFile);
|
||||||
|
////
|
||||||
|
// System.out.println("- " + t1.getTime() + (t1.after(t2) ? ">" : "<") + t2.getTime());
|
||||||
|
|
||||||
|
if (remoteFile == null || toleranceCompareAfter(getLocalFileUtcTimestamp(localFile), (getUtcTimestamp(remoteFile)))) {
|
||||||
|
uploadFile(localFile);
|
||||||
|
System.out.println("Uploaded " + localFile.getName());
|
||||||
|
upCount++;
|
||||||
|
}else{
|
||||||
|
System.out.println("Did not upload " + localFile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FTPFile remoteFile : remoteFiles) {
|
||||||
|
if (!remoteFile.isDirectory()) {
|
||||||
|
File localFile = new File(baseDir, remoteFile.getName());
|
||||||
|
|
||||||
|
// Date t1 = getLocalFileUtcTimestamp(localFile);
|
||||||
|
// Date t2 = getUtcTimestamp(remoteFile);
|
||||||
|
////
|
||||||
|
// System.out.println("- " + t1 + (t1.after(t2) ? ">" : "<") + t2);
|
||||||
|
|
||||||
|
if (!localFile.exists() || toleranceCompareAfter(getUtcTimestamp(remoteFile), (getLocalFileUtcTimestamp(localFile)))) {
|
||||||
|
downloadFile(remoteFile, localFile);
|
||||||
|
System.out.println("Downloaded " + localFile.getName());
|
||||||
|
downCount++;
|
||||||
|
}else{
|
||||||
|
System.out.println("Did not download " + remoteFile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
AlertManager.error(e);
|
||||||
|
onResult.onResult(true, upCount, downCount);
|
||||||
|
} finally {
|
||||||
|
onResult.onResult(false, upCount, downCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,11 +14,14 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.settingsManager;
|
import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentTransferBinding;
|
||||||
import com.ridgebotics.ridgescout.ui.transfer.bluetooth.BluetoothSenderFragment;
|
import com.ridgebotics.ridgescout.ui.transfer.bluetooth.BluetoothSenderFragment;
|
||||||
import com.ridgebotics.ridgescout.ui.transfer.codes.CodeGeneratorView;
|
import com.ridgebotics.ridgescout.ui.transfer.codes.CodeGeneratorView;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
public class TransferFragment extends Fragment {
|
public class TransferFragment extends Fragment {
|
||||||
private FragmentTransferBinding binding;
|
private FragmentTransferBinding binding;
|
||||||
|
|
||||||
@@ -66,6 +69,26 @@ public class TransferFragment extends Fragment {
|
|||||||
alert.create().show();
|
alert.create().show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if(!settingsManager.getWifiMode()) {
|
||||||
|
binding.TBAButton.setEnabled(false);
|
||||||
|
binding.SyncButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!settingsManager.getFTPEnabled() ||
|
||||||
|
new Date().getTime()-FTPSync.lastSyncTime < FTPSync.timeTolerance) {
|
||||||
|
binding.SyncButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
if(evcode.equals("unset")){
|
if(evcode.equals("unset")){
|
||||||
binding.noEventError.setVisibility(View.VISIBLE);
|
binding.noEventError.setVisibility(View.VISIBLE);
|
||||||
binding.uploadButton.setEnabled(false);
|
binding.uploadButton.setEnabled(false);
|
||||||
@@ -106,9 +129,6 @@ public class TransferFragment extends Fragment {
|
|||||||
builder.show();
|
builder.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!settingsManager.getWifiMode())
|
|
||||||
binding.TBAButton.setEnabled(false);
|
|
||||||
|
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package com.ridgebotics.ridgescout.ui.transfer.codes;
|
|||||||
|
|
||||||
import static androidx.core.math.MathUtils.clamp;
|
import static androidx.core.math.MathUtils.clamp;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.media.Image;
|
import android.media.Image;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -25,6 +27,7 @@ import androidx.camera.core.ImageProxy;
|
|||||||
import androidx.camera.core.Preview;
|
import androidx.camera.core.Preview;
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
@@ -150,6 +153,9 @@ public class CodeScannerView extends Fragment {
|
|||||||
|
|
||||||
this.lifecycle = getViewLifecycleOwner();
|
this.lifecycle = getViewLifecycleOwner();
|
||||||
|
|
||||||
|
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.CAMERA}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uiHandler = new Handler();
|
uiHandler = new Handler();
|
||||||
|
|||||||
@@ -15,19 +15,25 @@ import java.io.IOException;
|
|||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
public final class fileEditor {
|
public final class fileEditor {
|
||||||
private final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
public final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
||||||
public static final byte internalDataVersion = 0x01;
|
public static final byte internalDataVersion = 0x01;
|
||||||
public static final int maxCompressedBlockSize = 4096;
|
public static final int maxCompressedBlockSize = 4096;
|
||||||
|
// private TimeZone localTimeZone = TimeZone.getDefault();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +49,6 @@ public final class fileEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static char byteToChar(int num){
|
public static char byteToChar(int num){
|
||||||
return new String(toBytes(num, 1), StandardCharsets.ISO_8859_1).charAt(0);
|
return new String(toBytes(num, 1), StandardCharsets.ISO_8859_1).charAt(0);
|
||||||
}
|
}
|
||||||
@@ -189,7 +194,22 @@ public final class fileEditor {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// public static Calendar getLastModified(String filepath){
|
||||||
|
// File f = new File(baseDir + filepath);
|
||||||
|
// if(f.exists()){
|
||||||
|
// Calendar calendar = Calendar.getInstance();
|
||||||
|
// calendar.setTimeInMillis(f.lastModified());
|
||||||
|
// return calendar;
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static void setLastModified(String filepath, Calendar calendar){
|
||||||
|
// File f = new File(baseDir + filepath);
|
||||||
|
// if(f.exists()){
|
||||||
|
// f.setLastModified(calendar.getTimeInMillis());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -198,6 +218,10 @@ public final class fileEditor {
|
|||||||
FileOutputStream output = new FileOutputStream(baseDir + filepath);
|
FileOutputStream output = new FileOutputStream(baseDir + filepath);
|
||||||
output.write(data);
|
output.write(data);
|
||||||
output.close();
|
output.close();
|
||||||
|
|
||||||
|
// Date d = new Date();
|
||||||
|
|
||||||
|
new File(baseDir + filepath).setLastModified(new Date().getTime());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
@@ -341,18 +365,19 @@ public final class fileEditor {
|
|||||||
|
|
||||||
String[] filenames = outFiles.toArray(new String[0]);
|
String[] filenames = outFiles.toArray(new String[0]);
|
||||||
|
|
||||||
Arrays.sort(filenames, new Comparator<String>() {
|
try {
|
||||||
@Override
|
Arrays.sort(filenames, (o1, o2) -> {
|
||||||
public int compare(String o1, String o2) {
|
|
||||||
try {
|
try {
|
||||||
if(!o1.contains("-") || !o2.contains("-"))
|
if (!o1.contains("-") || !o2.contains("-"))
|
||||||
return 0;
|
return 0;
|
||||||
return Integer.valueOf(o1.split("-")[1]).compareTo(Integer.valueOf(o2.split("-")[1]));
|
return Integer.valueOf(o1.split("-")[1]).compareTo(Integer.valueOf(o2.split("-")[1]));
|
||||||
} catch (Exception e){
|
} catch (Exception e) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
} catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return filenames;
|
return filenames;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ public class settingsManager {
|
|||||||
public static final String AllyPosKey = "alliance_pos";
|
public static final String AllyPosKey = "alliance_pos";
|
||||||
public static final String DataModeKey = "data_view_mode";
|
public static final String DataModeKey = "data_view_mode";
|
||||||
public static final String BtUUIDKey = "bt_uuid";
|
public static final String BtUUIDKey = "bt_uuid";
|
||||||
|
public static final String FTPEnabled = "ftp_enabled";
|
||||||
|
public static final String FTPServer = "ftp_server";
|
||||||
|
|
||||||
public static Map defaults = getDefaults();
|
public static Map defaults = getDefaults();
|
||||||
private static Map getDefaults(){
|
private static Map getDefaults(){
|
||||||
@@ -32,15 +34,33 @@ public class settingsManager {
|
|||||||
hm.put(AllyPosKey, "red-1");
|
hm.put(AllyPosKey, "red-1");
|
||||||
hm.put(DataModeKey, 0);
|
hm.put(DataModeKey, 0);
|
||||||
hm.put(BtUUIDKey, UUID.randomUUID().toString());
|
hm.put(BtUUIDKey, UUID.randomUUID().toString());
|
||||||
|
hm.put(FTPEnabled, false);
|
||||||
|
hm.put(FTPServer, "0.0.0.0");
|
||||||
|
|
||||||
return hm;
|
return hm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SharedPreferences.Editor getEditor(){
|
public static SharedPreferences.Editor getEditor(){
|
||||||
if(editor == null) editor = prefs.edit();
|
if(editor == null) editor = prefs.edit();
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void resetSettings(){
|
||||||
|
getEditor() .putString(UnameKey, (String) defaults.get( UnameKey )).apply();
|
||||||
|
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(MatchNumKey, (int) defaults.get( MatchNumKey )).apply();
|
||||||
|
getEditor() .putString(AllyPosKey, (String) defaults.get( AllyPosKey )).apply();
|
||||||
|
getEditor() .putInt(DataModeKey, (int) defaults.get( DataModeKey )).apply();
|
||||||
|
|
||||||
|
getEditor() .putString(BtUUIDKey, (String) defaults.get( BtUUIDKey )).apply();
|
||||||
|
|
||||||
|
getEditor().putBoolean(FTPEnabled, (boolean) defaults.get(FTPEnabled )).apply();
|
||||||
|
getEditor() .putString(FTPServer, (String) defaults.get( BtUUIDKey )).apply();
|
||||||
|
}
|
||||||
|
|
||||||
// IDK why I decided to format these functions like this. It looks cool though.
|
// IDK why I decided to format these functions like this. It looks cool though.
|
||||||
public static String getUsername(){return prefs.getString( UnameKey, (String) defaults.get(UnameKey));}
|
public static String getUsername(){return prefs.getString( UnameKey, (String) defaults.get(UnameKey));}
|
||||||
public static void setUsername(String str){ getEditor().putString( UnameKey,str).apply();}
|
public static void setUsername(String str){ getEditor().putString( UnameKey,str).apply();}
|
||||||
@@ -66,4 +86,14 @@ public class settingsManager {
|
|||||||
public static String getBtUUID(){return prefs.getString( BtUUIDKey, (String) defaults.get(BtUUIDKey));}
|
public static String getBtUUID(){return prefs.getString( BtUUIDKey, (String) defaults.get(BtUUIDKey));}
|
||||||
public static void setBtUUID(String str){ getEditor().putString( BtUUIDKey,str).apply();}
|
public static void setBtUUID(String str){ getEditor().putString( BtUUIDKey,str).apply();}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean getFTPEnabled(){return prefs.getBoolean( FTPEnabled, (boolean) defaults.get(FTPEnabled));}
|
||||||
|
public static void setFTPEnabled(boolean bool){getEditor().putBoolean( FTPEnabled,bool).apply();}
|
||||||
|
|
||||||
|
public static String getFTPServer(){return prefs.getString( FTPServer, (String) defaults.get(FTPServer));}
|
||||||
|
public static void setFTPServer(String str){ getEditor().putString( FTPServer,str).apply();}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
tools:context=".ui.settings.settingsFragment">
|
tools:context=".ui.settings.settingsFragment">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:id="@+id/ScrollArea"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="60dp"
|
android:layout_marginBottom="60dp"
|
||||||
@@ -18,177 +17,13 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<TableLayout
|
||||||
|
android:id="@+id/SettingsTable"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
|
</TableLayout>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<!-- <CheckBox-->
|
|
||||||
<!-- android:id="@+id/practice_mode"-->
|
|
||||||
<!-- android:layout_width="412dp"-->
|
|
||||||
<!-- android:layout_height="79dp"-->
|
|
||||||
<!-- android:layout_marginTop="20dp"-->
|
|
||||||
<!-- android:text="Practice Mode"-->
|
|
||||||
<!-- android:textSize="24sp"-->
|
|
||||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
|
||||||
<!-- app:layout_constraintHorizontal_bias="0.0"-->
|
|
||||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
|
||||||
<!-- app:layout_constraintTop_toBottomOf="@+id/eventDropdown" />-->
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView2"
|
|
||||||
android:layout_width="66dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="Name"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/username"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ems="10"
|
|
||||||
android:inputType="text"
|
|
||||||
android:text="Username"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView2" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView1"
|
|
||||||
android:layout_width="107dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="152dp"
|
|
||||||
android:layout_marginTop="20dp"
|
|
||||||
android:layout_marginEnd="152dp"
|
|
||||||
android:text="Event Code"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/username" />
|
|
||||||
|
|
||||||
<com.skydoves.powerspinner.PowerSpinnerView
|
|
||||||
android:id="@+id/eventDropdown"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/black_2"
|
|
||||||
android:gravity="center"
|
|
||||||
android:hint="No events selected"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:textColor="@color/main_500"
|
|
||||||
android:textColorHint="@color/teal_700"
|
|
||||||
android:textSize="14.5sp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView1"
|
|
||||||
app:spinner_arrow_gravity="end"
|
|
||||||
app:spinner_arrow_padding="8dp"
|
|
||||||
app:spinner_divider_color="@color/teal_200"
|
|
||||||
app:spinner_divider_show="true"
|
|
||||||
app:spinner_divider_size="0.4dp"
|
|
||||||
app:spinner_popup_background="@color/black_2"
|
|
||||||
app:spinner_popup_elevation="14dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/alliance_pos_text"
|
|
||||||
android:layout_width="107dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="152dp"
|
|
||||||
android:layout_marginTop="20dp"
|
|
||||||
android:layout_marginEnd="152dp"
|
|
||||||
android:text="Alliance Position"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/eventDropdown" />
|
|
||||||
|
|
||||||
<com.skydoves.powerspinner.PowerSpinnerView
|
|
||||||
android:id="@+id/alliance_pos_dropdown"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/black_2"
|
|
||||||
android:gravity="center"
|
|
||||||
android:hint="No events selected"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:textColor="@color/main_500"
|
|
||||||
android:textColorHint="@color/teal_700"
|
|
||||||
android:textSize="14.5sp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/alliance_pos_text"
|
|
||||||
app:spinner_arrow_gravity="end"
|
|
||||||
app:spinner_arrow_padding="8dp"
|
|
||||||
app:spinner_divider_color="@color/teal_200"
|
|
||||||
app:spinner_divider_show="true"
|
|
||||||
app:spinner_divider_size="0.4dp"
|
|
||||||
app:spinner_popup_background="@color/black_2"
|
|
||||||
app:spinner_popup_elevation="14dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/team_num_settings_label"
|
|
||||||
android:layout_width="107dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="152dp"
|
|
||||||
android:layout_marginTop="20dp"
|
|
||||||
android:layout_marginEnd="152dp"
|
|
||||||
android:text="Team number"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/alliance_pos_dropdown" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/team_number"
|
|
||||||
android:layout_width="193dp"
|
|
||||||
android:layout_height="65dp"
|
|
||||||
android:ems="10"
|
|
||||||
android:gravity="center"
|
|
||||||
android:inputType="number"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:text="4388"
|
|
||||||
android:textColor="@color/main_500"
|
|
||||||
android:textColorHint="@color/teal_700"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/team_num_settings_label" />
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/wifi_mode"
|
|
||||||
android:layout_width="412dp"
|
|
||||||
android:layout_height="79dp"
|
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:text="Wifi Mode"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/team_number" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/reset_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Reset Settings"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Upload"
|
android:text="Upload"
|
||||||
android:textSize="34sp"
|
android:textSize="34sp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/CSVButton"
|
app:layout_constraintBottom_toTopOf="@+id/SyncButton"
|
||||||
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" />
|
||||||
@@ -44,21 +44,34 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Download"
|
android:text="Download"
|
||||||
android:textSize="34sp"
|
android:textSize="34sp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/CSVButton"
|
app:layout_constraintBottom_toTopOf="@+id/SyncButton"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/uploadButton" />
|
app:layout_constraintTop_toBottomOf="@+id/uploadButton" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/SyncButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SYNC"
|
||||||
|
android:textSize="34sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/CSVButton"
|
android:id="@+id/CSVButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="CSV"
|
android:text="CSV"
|
||||||
android:textSize="34sp"
|
android:textSize="34sp"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/TBAButton"
|
app:layout_constraintBottom_toTopOf="@+id/TBAButton"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/uploadButton" />
|
app:layout_constraintTop_toBottomOf="@+id/SyncButton" />
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/TBAButton"
|
android:id="@+id/TBAButton"
|
||||||
@@ -69,7 +82,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_toBottomOf="@+id/CSVButton" />
|
app:layout_constraintTop_toBottomOf="@+id/SyncButton" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ lifecycleViewmodelKtx = "2.6.1"
|
|||||||
navigationFragment = "2.6.0"
|
navigationFragment = "2.6.0"
|
||||||
navigationUi = "2.6.0"
|
navigationUi = "2.6.0"
|
||||||
supportAnnotations = "28.0.0"
|
supportAnnotations = "28.0.0"
|
||||||
|
preference = "1.2.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
@@ -24,6 +25,7 @@ lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-view
|
|||||||
navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigationFragment" }
|
navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigationFragment" }
|
||||||
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
|
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
|
||||||
support-annotations = { group = "com.android.support", name = "support-annotations", version.ref = "supportAnnotations" }
|
support-annotations = { group = "com.android.support", name = "support-annotations", version.ref = "supportAnnotations" }
|
||||||
|
preference = { group = "androidx.preference", name = "preference", version.ref = "preference" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
Work in progress!
|
This is a scouting app for First Robotics Compitition matches by Ridgebotics, that includes many features.
|
||||||
|
|
||||||
This is a scouting app for First Robotics Compitition matches, that includes many features.
|
Wiki: https://github.com/team4388/ScoutingApp2025/wiki
|
||||||
|
Before Width: | Height: | Size: 373 KiB After Width: | Height: | Size: 373 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 162 KiB |