mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-09 00:37:59 -06:00
Attempt to get F-Droid working
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package com.ridgebotics.ridgescout;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.ridgebotics.ridgescout.scoutingData.fields;
|
||||
import com.ridgebotics.ridgescout.utility.SentimentAnalysis;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavOptions;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.ActivityMainBinding;
|
||||
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.google.android.material.navigation.NavigationBarView;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
private BottomNavigationView navView;
|
||||
|
||||
private AppBarConfiguration appBarConfiguration;
|
||||
private NavController navController;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
latestSettings.update();
|
||||
|
||||
if(!fileEditor.fileExist(fields.matchFieldsFilename)){
|
||||
fields.save(fields.matchFieldsFilename, fields.default_match_fields);
|
||||
}
|
||||
|
||||
if(!fileEditor.fileExist(fields.pitsFieldsFilename)){
|
||||
fields.save(fields.pitsFieldsFilename, fields.default_pit_fields);
|
||||
}
|
||||
|
||||
AlertManager.init(this);
|
||||
SentimentAnalysis.init(this);
|
||||
|
||||
Objects.requireNonNull(getSupportActionBar()).hide();
|
||||
|
||||
|
||||
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
navView = findViewById(R.id.nav_view);
|
||||
// appBarConfiguration = new AppBarConfiguration.Builder(
|
||||
// R.id.navigation_scouting,
|
||||
// R.id.navigation_match_scouting,
|
||||
// R.id.navigation_team_selector,
|
||||
// R.id.navigation_pit_scouting,
|
||||
//
|
||||
// R.id.navigation_data,
|
||||
// R.id.navigation_data_status,
|
||||
// R.id.navigation_data_teams,
|
||||
// R.id.navigation_data_compile,
|
||||
// R.id.navigation_data_fields_chooser,
|
||||
// R.id.navigation_data_fields,
|
||||
//
|
||||
// R.id.navigation_transfer,
|
||||
// R.id.navigation_file_selector,
|
||||
// R.id.navigation_transfer_selector,
|
||||
// R.id.navigation_code_generator,
|
||||
// R.id.navigation_code_scanner,
|
||||
// R.id.navigation_bluetooth_sender,
|
||||
// R.id.navigation_bluetooth_receiver,
|
||||
// R.id.navigation_tba,
|
||||
//
|
||||
// R.id.navigation_settings)
|
||||
// .build();
|
||||
|
||||
appBarConfiguration = new AppBarConfiguration.Builder(
|
||||
R.id.navigation_scouting,
|
||||
R.id.navigation_data,
|
||||
R.id.navigation_transfer,
|
||||
R.id.navigation_settings)
|
||||
.build();
|
||||
|
||||
// appBarConfiguration.set
|
||||
|
||||
navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
|
||||
|
||||
|
||||
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
|
||||
NavigationUI.setupWithNavController(navView, navController);
|
||||
|
||||
navView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
clearBackStack();
|
||||
navController.navigate(item.getItemId(), savedInstanceState, new NavOptions.Builder()
|
||||
.setEnterAnim(R.anim.enter_anim)
|
||||
.setExitAnim(R.anim.exit_anim)
|
||||
.setPopEnterAnim(R.anim.pop_enter_anim)
|
||||
.setPopExitAnim(R.anim.pop_exit_anim).build()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
return navController.navigateUp() || super.onSupportNavigateUp();
|
||||
}
|
||||
|
||||
private void clearBackStack() {
|
||||
navController.popBackStack(navController.getGraph().getStartDestinationId(), false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public interface activityResultRelay {
|
||||
void onActivityResult(int requestCode, int resultCode, Intent data);
|
||||
}
|
||||
|
||||
public static activityResultRelay resultRelay = null;
|
||||
public static void setResultRelay(activityResultRelay tmpresultRelay){
|
||||
resultRelay = tmpresultRelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
// AlertManager.error(String.valueOf(requestCode));
|
||||
if (resultRelay != null) {
|
||||
resultRelay.onActivityResult(resultCode, requestCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.ridgebotics.ridgescout.SettingsVersionStack;
|
||||
|
||||
public class latestSettings {
|
||||
public static sv1 settings = new sv1();
|
||||
public static void update(){
|
||||
settings.init_settings();
|
||||
settings.update();
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.ridgebotics.ridgescout.SettingsVersionStack;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public abstract class settingsVersion {
|
||||
private static final String settingsFilename = "settings.txt";
|
||||
public abstract void defaultSettings();
|
||||
public abstract int getVersion();
|
||||
public abstract void update();
|
||||
|
||||
public static String get_settings_file_content(){
|
||||
byte[] data = fileEditor.readFile(settingsFilename);
|
||||
if(data == null){return "";}
|
||||
return new String(data, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public int get_file_version(){
|
||||
String[] fileContent = get_settings_file_content().split("\n");
|
||||
try{
|
||||
return Integer.parseInt(fileContent[0]);
|
||||
}catch(Exception e){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void set_file_version(int version){
|
||||
String[] fileContent = get_settings_file_content().split("\n");
|
||||
String output = String.valueOf(version);
|
||||
for(int i = 0; i < fileContent.length; i++){
|
||||
output += ("\n" + fileContent[i]);
|
||||
}
|
||||
fileEditor.writeFile(settingsFilename, output.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public String readTag(String search_tag){
|
||||
String[] fileContent = get_settings_file_content().split("\n");
|
||||
|
||||
try{
|
||||
for(String line : fileContent){
|
||||
if(line.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
String[] split = line.split("=");
|
||||
if(split[0].equals(search_tag)){
|
||||
if(split[1].equals("<empty>")){
|
||||
return "";
|
||||
}else if(split[1].equals("<null>")){
|
||||
return null;
|
||||
}else {
|
||||
return split[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
AlertManager.error(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void init_settings(){
|
||||
if(!fileEditor.fileExist(settingsFilename)){
|
||||
fileEditor.createFile(settingsFilename);
|
||||
|
||||
set_file_version(getVersion());
|
||||
defaultSettings();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public String writeTag(String tag_name, String data){
|
||||
final boolean already_exists = readTag(tag_name) != null;
|
||||
|
||||
if(data == null){
|
||||
data = "<null>";
|
||||
}else if(data.equals("")){
|
||||
data = "<empty>";
|
||||
}
|
||||
|
||||
if(!already_exists){
|
||||
String fileContent = get_settings_file_content();
|
||||
String output = fileContent + "\n" + tag_name + "=" + data;
|
||||
fileEditor.writeFile(settingsFilename, output.getBytes(StandardCharsets.UTF_8));
|
||||
return output;
|
||||
}else{
|
||||
String[] fileContent = get_settings_file_content().split("\n");
|
||||
try{
|
||||
for(int i = 0; i < fileContent.length; i++){
|
||||
if(fileContent[i].isEmpty()){
|
||||
continue;
|
||||
}
|
||||
String[] split = fileContent[i].split("=");
|
||||
if(split[0].equals(tag_name)){
|
||||
fileContent[i] = tag_name + "=" + data;
|
||||
String output = String.join("\n", fileContent);
|
||||
fileEditor.writeFile(settingsFilename, output.getBytes(StandardCharsets.UTF_8));
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return "No idea how this happened";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.ridgebotics.ridgescout.SettingsVersionStack;
|
||||
|
||||
public class sv0 extends settingsVersion {
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public void update(){
|
||||
// int file_version = get_file_version();
|
||||
// if(file_version == getVersion()) {
|
||||
// return;
|
||||
// }else if(file_version < getVersion()){
|
||||
// super.update();
|
||||
// }
|
||||
// set_file_version(getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultSettings() {
|
||||
writeTag("username", "Username");
|
||||
writeTag("selected_event_code", "unset");
|
||||
// writeTag("practice_mode", "false");
|
||||
writeTag("wifi_mode", "false");
|
||||
}
|
||||
|
||||
public void set_username(String name){
|
||||
writeTag("username", name);
|
||||
}
|
||||
public String get_username(){
|
||||
return readTag("username");
|
||||
}
|
||||
public void set_evcode(String evcode){
|
||||
writeTag("selected_event_code", evcode);
|
||||
}
|
||||
public String get_evcode(){
|
||||
return readTag("selected_event_code");
|
||||
}
|
||||
// public void set_practice_mode(boolean value) {
|
||||
// writeTag("practice_mode", value ? "true" : "false");
|
||||
// }
|
||||
// public boolean get_practice_mode(){
|
||||
// return readTag("practice_mode").equals("true");
|
||||
// }
|
||||
public void set_wifi_mode(boolean value){
|
||||
writeTag("wifi_mode", value ? "true" : "false");
|
||||
}
|
||||
public boolean get_wifi_mode(){
|
||||
return readTag("wifi_mode").equals("true");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.ridgebotics.ridgescout.SettingsVersionStack;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class sv1 extends sv0 {
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public void update(){
|
||||
int file_version = get_file_version();
|
||||
if(file_version == getVersion()) {
|
||||
return;
|
||||
}else if(file_version < getVersion()){
|
||||
super.update();
|
||||
}
|
||||
set_file_version(getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultSettings() {
|
||||
writeTag("username", "Username");
|
||||
writeTag("selected_event_code", "unset");
|
||||
// writeTag("practice_mode", "false");
|
||||
writeTag("wifi_mode", "false");
|
||||
writeTag("team_num", "4388");
|
||||
|
||||
writeTag("match_num", "0");
|
||||
writeTag("alliance_pos", "red-1");
|
||||
writeTag("data_view_mode", "0");
|
||||
writeTag("bt_uuid", UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
public int get_match_num(){
|
||||
return Integer.parseInt(readTag("match_num"));
|
||||
}
|
||||
|
||||
public void set_match_num(int num){
|
||||
writeTag("match_num", String.valueOf(num));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_evcode(String evcode){
|
||||
set_match_num(0);
|
||||
writeTag("selected_event_code", evcode);
|
||||
}
|
||||
|
||||
public String get_alliance_pos(){
|
||||
return readTag("alliance_pos");
|
||||
}
|
||||
|
||||
public void set_alliance_pos(String pos){
|
||||
writeTag("alliance_pos", pos);
|
||||
}
|
||||
|
||||
public int get_team_num(){return Integer.parseInt(readTag("team_num"));}
|
||||
public void set_team_num(String str){
|
||||
|
||||
if(str.isEmpty()) {
|
||||
set_team_num(0);
|
||||
return;
|
||||
}
|
||||
|
||||
set_team_num(Integer.parseInt(str));
|
||||
}
|
||||
public void set_team_num(int num){writeTag("team_num", String.valueOf(num));}
|
||||
|
||||
public int get_data_view_mode(){
|
||||
return Integer.parseInt(readTag("data_view_mode"));
|
||||
}
|
||||
|
||||
public void set_data_view_mode(int mode){
|
||||
writeTag("data_view_mode", String.valueOf(mode));
|
||||
}
|
||||
|
||||
public void setUUID(UUID uuid){
|
||||
writeTag("bt_uuid", uuid.toString());
|
||||
}
|
||||
|
||||
public UUID getUUID(){
|
||||
return UUID.fromString(readTag("bt_uuid"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.ridgebotics.ridgescout.scoutingData;
|
||||
|
||||
import com.ridgebotics.ridgescout.scoutingData.transfer.transferType;
|
||||
import com.ridgebotics.ridgescout.types.ScoutingArray;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.data.stringType;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.types.data.intType;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ScoutingDataWriter {
|
||||
// private static final int int_type_id = 255;
|
||||
// private static final int string_type_id = 254;
|
||||
|
||||
public static boolean save(int version, String username, String filename, dataType[] data){
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
try {
|
||||
bb.addInt(version);
|
||||
bb.addString(username);
|
||||
for(int i = 0; i < data.length; i++){
|
||||
switch (data[i].getValueType()){
|
||||
case NUM:
|
||||
bb.addInt((int) data[i].forceGetValue());
|
||||
System.out.println("Saved INT: " + data[i].getName() + ", ("+ data[i].get() +")");
|
||||
break;
|
||||
case STRING:
|
||||
bb.addString((String) data[i].forceGetValue());
|
||||
System.out.println("Saved STR: " + data[i].getName() + ", ("+ data[i].get() +")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte[] bytes = bb.build();
|
||||
fileEditor.writeFile(filename, bytes);
|
||||
return true;
|
||||
} catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParsedScoutingDataResult {
|
||||
public String filename;
|
||||
public String username;
|
||||
public int version;
|
||||
public ScoutingArray data;
|
||||
}
|
||||
|
||||
public static ParsedScoutingDataResult load(String filename, inputType[][] values , transferType[][] transferValues){
|
||||
byte[] bytes = fileEditor.readFile(filename);
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
dataType[] dataTypes = new dataType[objects.size()-2];
|
||||
|
||||
int version = ((int)objects.get(0).get());
|
||||
// System.out.println(version);
|
||||
String username = (String) objects.get(1).get();
|
||||
|
||||
for(int i = 0; i < values[version].length; i++){
|
||||
switch (objects.get(i+2).getType()){
|
||||
case 1: // Int
|
||||
dataTypes[i] = intType.newNull(values[version][i].name);
|
||||
dataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
System.out.println("Loaded INT: " + values[version][i].name + ", ("+ dataTypes[i].get() +")");
|
||||
break;
|
||||
case 2: // String
|
||||
dataTypes[i] = stringType.newNull(values[version][i].name);
|
||||
dataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
System.out.println("Loaded STR: " + values[version][i].name + ", ("+ dataTypes[i].get() +")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ScoutingArray msa = new ScoutingArray(version, dataTypes, values, transferValues);
|
||||
msa.update();
|
||||
|
||||
ParsedScoutingDataResult psda = new ParsedScoutingDataResult();
|
||||
|
||||
psda.filename = filename;
|
||||
psda.username = username;
|
||||
psda.version = version;
|
||||
psda.data = msa;
|
||||
|
||||
return psda;
|
||||
|
||||
} catch (BuiltByteParser.byteParsingExeption e){
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.ridgebotics.ridgescout.scoutingData;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.input.dropdownType;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.types.input.tallyType;
|
||||
import com.ridgebotics.ridgescout.types.input.textType;
|
||||
import com.ridgebotics.ridgescout.types.input.sliderType;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class fields {
|
||||
// public static ScoutingVersion sv = new ScoutingVersion();
|
||||
|
||||
public static final String matchFieldsFilename = "matches.fields";
|
||||
public static final String pitsFieldsFilename = "pits.fields";
|
||||
|
||||
public static final inputType[][] default_match_fields = new inputType[][] {
|
||||
{
|
||||
new tallyType("Auto Notes", 0),
|
||||
new sliderType("Auto Performance", 5, 0, 10),
|
||||
new textType("Auto Comments", ""),
|
||||
new tallyType("Teleop Notes", 0),
|
||||
new sliderType("Teleop Performance", 5, 0, 10),
|
||||
new textType("Teleop Comments", ""),
|
||||
new sliderType("Overall Driving Performance", 5, 0, 10),
|
||||
new textType("Overall Driving Comments", ""),
|
||||
new sliderType("Score area (AMP <-> Speaker)", 5, 0, 10),
|
||||
new dropdownType("End Condition", new String[]{"Nothing", "Attempted Climb", "Successful Climbed", "Climbed with multiple robots", "Climbed with trap"}, 0),
|
||||
new dropdownType("Robot Condition", new String[]{"Everything was working", "Something seemed to be broken", "Something was broken", "Missing robot (Joe Johnson)"}, 0),
|
||||
new textType("Other Comments", "")
|
||||
}
|
||||
};
|
||||
|
||||
public static final inputType[][] default_pit_fields = new inputType[][] {
|
||||
{
|
||||
new sliderType("How good is robot", 5, 0, 10),
|
||||
new textType("notes", ""),
|
||||
},{
|
||||
new sliderType("How good is robot", 5, 0, 10),
|
||||
new sliderType("Test", 1, 0, 10),
|
||||
new textType("notes", ""),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static boolean save(String filename, inputType[][] values){
|
||||
try {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
bb.addRaw(127, save_version(values[i]));
|
||||
}
|
||||
fileEditor.writeFile(filename, bb.build());
|
||||
return true;
|
||||
}catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
return false;
|
||||
// throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] save_version(inputType[] values) throws ByteBuilder.buildingException {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
for(int i =0; i < values.length; i++){
|
||||
bb.addRaw(values[i].get_byte_id(), values[i].encode());
|
||||
}
|
||||
return bb.build();
|
||||
}
|
||||
|
||||
public static inputType[][] load(String filename){
|
||||
byte[] bytes = fileEditor.readFile(filename);
|
||||
|
||||
// System.out.println(bytes);
|
||||
|
||||
try {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
inputType[][] values = new inputType[objects.size()][];
|
||||
|
||||
for(int i = 0 ; i < objects.size(); i++){
|
||||
values[i] = load_version((byte[]) objects.get(i).get());
|
||||
}
|
||||
|
||||
|
||||
return values;
|
||||
} catch (Exception e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static inputType[] load_version(byte[] bytes) throws BuiltByteParser.byteParsingExeption{
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
inputType[] output = new inputType[objects.size()];
|
||||
|
||||
for(int i = 0 ; i < objects.size(); i++){
|
||||
BuiltByteParser.parsedObject obj = objects.get(i);
|
||||
inputType t = null;
|
||||
switch (obj.getType()){
|
||||
case inputType.slider_type_id:
|
||||
t = new sliderType();
|
||||
break;
|
||||
case inputType.dropdownType:
|
||||
t = new dropdownType();
|
||||
break;
|
||||
case inputType.notesType:
|
||||
t = new textType();
|
||||
break;
|
||||
case inputType.tallyType:
|
||||
t = new tallyType();
|
||||
break;
|
||||
}
|
||||
|
||||
t.decode((byte[]) obj.get());
|
||||
output[i] = t;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// public static void test(){
|
||||
// ScoutingVersion.transferType[][] transferValues = sv.get_transfer_values(values);
|
||||
//
|
||||
// ScoutingVersion.ScoutingArray msa = sv.new ScoutingArray(0, new ScoutingVersion.dataType[]{
|
||||
// sv.new stringType("name", "test-username"),
|
||||
// sv.new intType("How good is robot", 12)
|
||||
// }, values, transferValues);
|
||||
//
|
||||
// msa.update();
|
||||
//
|
||||
// for(ScoutingVersion.dataType dt : msa.array){
|
||||
// if(dt == null) continue;
|
||||
// switch (dt.getValueType()){
|
||||
// case NUM:
|
||||
// System.out.println(dt.name + " " + (int) dt.get());
|
||||
// break;
|
||||
// case STRING:
|
||||
// System.out.println(dt.name + " " + (String) dt.get());
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.ridgebotics.ridgescout.scoutingData.transfer;
|
||||
|
||||
public class createTransferType extends transferType {
|
||||
public transferValue getType() {return transferValue.CREATE;}
|
||||
public createTransferType(String name){
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.ridgebotics.ridgescout.scoutingData.transfer;
|
||||
|
||||
public class directTransferType extends transferType {
|
||||
public transferValue getType() {return transferValue.DIRECT;}
|
||||
public directTransferType(String name){
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.ridgebotics.ridgescout.scoutingData.transfer;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
|
||||
public abstract class transferType {
|
||||
public enum transferValue {
|
||||
DIRECT,
|
||||
CREATE
|
||||
}
|
||||
public String name;
|
||||
public abstract transferValue getType();
|
||||
public transferType(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private static inputType get_input_type_by_name(inputType[] values, String name){
|
||||
for(inputType it : values){
|
||||
if(it.name.equals(name)){
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static transferType[][] get_transfer_values(inputType[][] values) {
|
||||
transferType[][] output = new transferType[values.length][];
|
||||
for(int a = 1; a < values.length; a++){
|
||||
transferType[] v = new transferType[values[a].length];
|
||||
for(int b = 0; b < values[a].length; b++){
|
||||
String name = values[a][b].name;
|
||||
if(get_input_type_by_name(values[a-1], name) != null){
|
||||
v[b] = new directTransferType(name);
|
||||
}else{
|
||||
v[b] = new createTransferType(name);
|
||||
}
|
||||
}
|
||||
output[a-1] = v;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.ridgebotics.ridgescout.types;
|
||||
|
||||
import com.ridgebotics.ridgescout.scoutingData.transfer.createTransferType;
|
||||
import com.ridgebotics.ridgescout.scoutingData.transfer.directTransferType;
|
||||
import com.ridgebotics.ridgescout.scoutingData.transfer.transferType;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.data.intType;
|
||||
import com.ridgebotics.ridgescout.types.data.stringType;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
|
||||
public class ScoutingArray {
|
||||
public int version;
|
||||
public dataType[] array;
|
||||
public inputType[][] values;
|
||||
public int latest_version_num;
|
||||
public transferType[][] transfer_values;
|
||||
|
||||
public ScoutingArray(int version, dataType[] array, inputType[][] values, transferType[][] transfer_values){
|
||||
this.version = version;
|
||||
this.array = array;
|
||||
this.values = values;
|
||||
this.latest_version_num = values.length-1;
|
||||
this.transfer_values = transfer_values;
|
||||
}
|
||||
|
||||
public ScoutingArray(int version, dataType[] array, inputType[][] values){
|
||||
this(version, array, values, transferType.get_transfer_values(values));
|
||||
}
|
||||
|
||||
public void update(){
|
||||
while(version<latest_version_num){
|
||||
dataType[] new_values = new dataType[transfer_values[version].length];
|
||||
for(int i = 0; i < transfer_values[version].length; i++){
|
||||
transferType tv = transfer_values[version][i];
|
||||
switch (tv.getType()){
|
||||
case DIRECT:
|
||||
new_values[i] = direct_transfer((directTransferType) tv);
|
||||
continue;
|
||||
// case RENAME:
|
||||
// new_values[i] = rename_transfer((renameTransferType) tv);
|
||||
// continue;
|
||||
case CREATE:
|
||||
new_values[i] = create_transfer((createTransferType) tv);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.array = new_values;
|
||||
version++;
|
||||
System.out.println("Updated to " + version);
|
||||
}
|
||||
}
|
||||
|
||||
private inputType get_input_type_by_name(int version, String name){
|
||||
for(inputType it : values[version]){
|
||||
if(it.name.equals(name)){
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private dataType get_data_type_by_name(String name){
|
||||
for(dataType dt : array){
|
||||
if(dt.getName().equals(name)){
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private dataType direct_transfer(directTransferType tv){
|
||||
return get_data_type_by_name(tv.name);
|
||||
}
|
||||
|
||||
// private dataType rename_transfer(renameTransferType tv){
|
||||
// dataType dt = get_data_type_by_name(tv.name);
|
||||
// dt.name = tv.new_name;
|
||||
// return dt;
|
||||
// }
|
||||
|
||||
private dataType create_transfer(createTransferType tv){
|
||||
inputType it = get_input_type_by_name(version+1, tv.name);
|
||||
switch (it.getValueType()){
|
||||
case NUM:
|
||||
return intType.newNull(it.name);
|
||||
case STRING:
|
||||
return stringType.newNull(it.name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ridgebotics.ridgescout.types.data;
|
||||
|
||||
public abstract class dataType {
|
||||
public enum valueTypes {
|
||||
NUM,
|
||||
STRING
|
||||
}
|
||||
|
||||
private Object value;
|
||||
private final String name;
|
||||
|
||||
public abstract valueTypes getValueType();
|
||||
|
||||
public Object forceGetValue(){return value;}
|
||||
public void forceSetValue(Object value){this.value = value;}
|
||||
|
||||
public abstract Object get();
|
||||
public abstract void set(Object value);
|
||||
|
||||
// public abstract Object getNullValue();
|
||||
// public abstract Object getUnselectedValue();
|
||||
|
||||
public abstract boolean isNull();
|
||||
// public abstract boolean isUnselected();
|
||||
|
||||
public String getName() {return name;}
|
||||
|
||||
public dataType(String name){
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.ridgebotics.ridgescout.types.data;
|
||||
|
||||
public class intType extends dataType {
|
||||
public static final int nullval = 255;
|
||||
// public static final int unselectedval = 1;
|
||||
|
||||
public valueTypes getValueType() {
|
||||
return valueTypes.NUM;
|
||||
}
|
||||
|
||||
// public Object getNullValue(){
|
||||
// return nullval;
|
||||
// }
|
||||
// public Object getUnselectedValue(){
|
||||
// return unselectedval;
|
||||
// }
|
||||
|
||||
public Object get(){
|
||||
return (int) forceGetValue();
|
||||
}
|
||||
|
||||
public void set(Object value){
|
||||
forceSetValue((int) value);
|
||||
}
|
||||
|
||||
public intType(String name, int value) {
|
||||
super(name);
|
||||
set(value);
|
||||
}
|
||||
|
||||
public static intType newNull(String name){
|
||||
final intType a = new intType(name, 0);
|
||||
a.forceSetValue(nullval);
|
||||
return a;
|
||||
}
|
||||
|
||||
// public static intType newUnselected(String name){
|
||||
// final intType a = new intType(name, 0);
|
||||
// a.forceSetValue(unselectedval);
|
||||
// return a;
|
||||
// }
|
||||
|
||||
public static boolean isNull(int obj){
|
||||
return obj == nullval;
|
||||
}
|
||||
public boolean isNull() {
|
||||
return isNull((int) forceGetValue());
|
||||
}
|
||||
|
||||
// public static boolean isUnselected(int obj){
|
||||
// return obj == unselectedval;
|
||||
// }
|
||||
// public boolean isUnselected() {
|
||||
// return isUnselected((int) forceGetValue());
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.ridgebotics.ridgescout.types.data;
|
||||
|
||||
public class stringType extends dataType{
|
||||
public static final String nullval = "null";
|
||||
// public static final String unselectedval = "■";
|
||||
|
||||
public valueTypes getValueType() {
|
||||
return valueTypes.STRING;
|
||||
}
|
||||
|
||||
// public Object getNullValue(){
|
||||
// return nullval;
|
||||
// }
|
||||
// public Object getUnselectedValue(){
|
||||
// return unselectedval;
|
||||
// }
|
||||
|
||||
public Object get(){
|
||||
return forceGetValue();
|
||||
}
|
||||
|
||||
public void set(Object value){
|
||||
forceSetValue(value);
|
||||
}
|
||||
|
||||
public stringType(String name, String value) {
|
||||
super(name);
|
||||
forceSetValue(value);
|
||||
}
|
||||
|
||||
public static stringType newNull(String name){
|
||||
final stringType a = new stringType(name, "");
|
||||
a.forceSetValue(nullval);
|
||||
return a;
|
||||
}
|
||||
|
||||
// public static stringType newUnselected(String name){
|
||||
// final stringType a = new stringType(name, "");
|
||||
// a.forceSetValue(unselectedval);
|
||||
// return a;
|
||||
// }
|
||||
|
||||
public static boolean isNull(String obj){
|
||||
return obj.equals(nullval);
|
||||
}
|
||||
public boolean isNull() {
|
||||
return isNull((String) forceGetValue());
|
||||
}
|
||||
|
||||
|
||||
// public static boolean isUnselected(String obj){
|
||||
// return obj.equals(unselectedval);
|
||||
// }
|
||||
// public boolean isUnselected() {
|
||||
// return isUnselected((String) forceGetValue());
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ridgebotics.ridgescout.types;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
public class file {
|
||||
public static final int typecode = 255;
|
||||
public String filename;
|
||||
public byte[] data;
|
||||
|
||||
|
||||
public file(){}
|
||||
|
||||
public file(String filename){
|
||||
this(filename, fileEditor.readFile(filename));
|
||||
}
|
||||
|
||||
public file(String filename, byte[] data){
|
||||
this.filename = filename;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] encode(){
|
||||
try {
|
||||
ByteBuilder bb = new ByteBuilder()
|
||||
.addString(filename)
|
||||
.addRaw(255, Objects.requireNonNull(fileEditor.readFile(filename)));
|
||||
|
||||
return bb.build();
|
||||
|
||||
} catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static file decode(byte[] bytes){
|
||||
try{
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = new BuiltByteParser(bytes).parse();
|
||||
|
||||
file f = new file();
|
||||
|
||||
f.filename = (String) objects.get(0).get();
|
||||
f.data = (byte[]) objects.get(1).get();
|
||||
|
||||
return f;
|
||||
|
||||
}catch (BuiltByteParser.byteParsingExeption e){
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean write(){
|
||||
if(data == null || filename == null) return false;
|
||||
return fileEditor.writeFile(filename, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.ridgebotics.ridgescout.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class frcEvent {
|
||||
|
||||
public static final int typecode = 254;
|
||||
public String eventCode;
|
||||
public String name;
|
||||
public ArrayList<frcMatch> matches;
|
||||
public ArrayList<frcTeam> teams;
|
||||
|
||||
public byte[] encode() {
|
||||
try {
|
||||
ByteBuilder bb = new ByteBuilder()
|
||||
.addString(eventCode)
|
||||
.addString(name);
|
||||
|
||||
for (frcTeam teams : teams) {
|
||||
bb.addRaw(frcTeam.typecode, teams.encode());
|
||||
}
|
||||
|
||||
for (frcMatch match : matches) {
|
||||
bb.addRaw(frcMatch.typecode, match.encode());
|
||||
}
|
||||
|
||||
return bb.build();
|
||||
} catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static frcEvent decode(byte[] bytes) {
|
||||
try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects =
|
||||
new BuiltByteParser(bytes).parse();
|
||||
|
||||
frcEvent frc = new frcEvent();
|
||||
|
||||
frc.eventCode = (String) objects.get(0).get();
|
||||
frc.name = (String) objects.get(1).get();
|
||||
|
||||
frc.matches = new ArrayList<>();
|
||||
frc.teams = new ArrayList<>();
|
||||
|
||||
for (BuiltByteParser.parsedObject object : objects) {
|
||||
if (object.getType() == frcTeam.typecode) {
|
||||
frc.teams.add(frcTeam.decode((byte[]) object.get()));
|
||||
} else if (object.getType() == frcMatch.typecode) {
|
||||
frc.matches.add(frcMatch.decode((byte[]) object.get()));
|
||||
}
|
||||
}
|
||||
|
||||
return frc;
|
||||
} catch (BuiltByteParser.byteParsingExeption e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return (
|
||||
"frcEvent Name: " +
|
||||
name +
|
||||
", Code: " +
|
||||
eventCode +
|
||||
" numTeams: " +
|
||||
teams.size() +
|
||||
" numMatches: " +
|
||||
matches.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ridgebotics.ridgescout.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class frcMatch {
|
||||
public static final int typecode = 253;
|
||||
public frcMatch(){}
|
||||
public int matchIndex = 0;
|
||||
public int[] blueAlliance = new int[3];
|
||||
public int[] redAlliance = new int[3];
|
||||
|
||||
public byte[] encode(){
|
||||
try {
|
||||
return new ByteBuilder()
|
||||
.addInt(matchIndex)
|
||||
.addInt(blueAlliance[0])
|
||||
.addInt(blueAlliance[1])
|
||||
.addInt(blueAlliance[2])
|
||||
.addInt(redAlliance[0])
|
||||
.addInt(redAlliance[1])
|
||||
.addInt(redAlliance[2])
|
||||
.build();
|
||||
} catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
return new byte[1];
|
||||
}
|
||||
}
|
||||
public static frcMatch decode(byte[] bytes){
|
||||
try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = new BuiltByteParser(bytes).parse();
|
||||
|
||||
frcMatch frc = new frcMatch();
|
||||
|
||||
frc.matchIndex = (int) objects.get(0).get();
|
||||
frc.blueAlliance[0] = (int) objects.get(1).get();
|
||||
frc.blueAlliance[1] = (int) objects.get(2).get();
|
||||
frc.blueAlliance[2] = (int) objects.get(3).get();
|
||||
frc.redAlliance[0] = (int) objects.get(4).get();
|
||||
frc.redAlliance[1] = (int) objects.get(5).get();
|
||||
frc.redAlliance[2] = (int) objects.get(6).get();
|
||||
|
||||
|
||||
return frc;
|
||||
|
||||
} catch (BuiltByteParser.byteParsingExeption e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String toString(){
|
||||
return "frcMatch Num: " + matchIndex + ", Blue: " + Arrays.toString(blueAlliance) + ", Red: " + Arrays.toString(redAlliance);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.ridgebotics.ridgescout.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class frcTeam {
|
||||
public static final int typecode = 252;
|
||||
public int teamNumber = 0;
|
||||
public String teamName = "null";
|
||||
public String city = "null";
|
||||
public String stateOrProv = "null";
|
||||
public String school = "null";
|
||||
public String country = "null";
|
||||
public int startingYear = 0;
|
||||
|
||||
public String getDescription(){
|
||||
return teamName + " Started in " + startingYear + ", and are from " + school + " in " + city + ", " + stateOrProv + ", " + country;
|
||||
}
|
||||
|
||||
public byte[] encode(){
|
||||
try {
|
||||
return new ByteBuilder()
|
||||
.addInt(teamNumber)
|
||||
.addString(teamName)
|
||||
.addString(city)
|
||||
.addString(stateOrProv)
|
||||
.addString(school)
|
||||
.addString(country)
|
||||
.addInt(startingYear)
|
||||
.build();
|
||||
} catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static frcTeam decode(byte[] bytes){
|
||||
try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = new BuiltByteParser(bytes).parse();
|
||||
|
||||
frcTeam frc = new frcTeam();
|
||||
|
||||
frc.teamNumber = (int) objects.get(0).get();
|
||||
frc.teamName = (String) objects.get(1).get();
|
||||
frc.city = (String) objects.get(2).get();
|
||||
frc.stateOrProv = (String) objects.get(3).get();
|
||||
frc.school = (String) objects.get(4).get();
|
||||
frc.country = (String) objects.get(5).get();
|
||||
frc.startingYear = (int) objects.get(6).get();
|
||||
|
||||
return frc;
|
||||
|
||||
} catch (BuiltByteParser.byteParsingExeption e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String toString(){
|
||||
return "frcTeam Num: " + teamNumber + ", " + getDescription();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
package com.ridgebotics.ridgescout.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.data.intType;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.charts.PieChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.LineDataSet;
|
||||
import com.github.mikephil.charting.data.PieData;
|
||||
import com.github.mikephil.charting.data.PieDataSet;
|
||||
import com.github.mikephil.charting.data.PieEntry;
|
||||
import com.skydoves.powerspinner.IconSpinnerAdapter;
|
||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
||||
import com.skydoves.powerspinner.PowerSpinnerView;
|
||||
import com.skydoves.powerspinner.SpinnerGravity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class dropdownType extends inputType {
|
||||
public String[] text_options;
|
||||
public int get_byte_id() {return dropdownType;}
|
||||
public inputTypes getInputType(){return inputTypes.DROPDOWN;}
|
||||
public dataType.valueTypes getValueType(){return dataType.valueTypes.NUM;}
|
||||
public Object get_fallback_value(){return 0;}
|
||||
public dropdownType(){};
|
||||
public String get_type_name(){return "Dropdown";}
|
||||
public dropdownType(String name, String[] text_options, int defaultSelIndex){
|
||||
super(name);
|
||||
this.text_options = text_options;
|
||||
this.default_value = defaultSelIndex;
|
||||
}
|
||||
|
||||
|
||||
public byte[] encode() throws ByteBuilder.buildingException {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
bb.addString(name);
|
||||
bb.addInt((int)default_value);
|
||||
bb.addStringArray(text_options);
|
||||
return bb.build();
|
||||
}
|
||||
public void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
|
||||
name = (String) objects.get(0).get();
|
||||
default_value = objects.get(1).get();
|
||||
text_options = (String[]) objects.get(2).get();
|
||||
}
|
||||
|
||||
public PowerSpinnerView dropdown = null;
|
||||
|
||||
public View createView(Context context, Function<dataType, Integer> onUpdate){
|
||||
dropdown = new PowerSpinnerView(context);
|
||||
|
||||
List<IconSpinnerItem> iconSpinnerItems = new ArrayList<>();
|
||||
for(int i = 0; i < text_options.length; i++){
|
||||
iconSpinnerItems.add(new IconSpinnerItem(text_options[i]));
|
||||
}
|
||||
IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown);
|
||||
|
||||
dropdown.setGravity(Gravity.CENTER);
|
||||
|
||||
dropdown.setSpinnerAdapter(iconSpinnerAdapter);
|
||||
dropdown.setItems(iconSpinnerItems);
|
||||
|
||||
dropdown.selectItemByIndex((int) default_value);
|
||||
|
||||
dropdown.setPadding(10,20,10,20);
|
||||
dropdown.setBackgroundColor(0xf0000000);
|
||||
dropdown.setTextColor(0xff00ff00);
|
||||
dropdown.setTextSize(14.5f);
|
||||
dropdown.setArrowGravity(SpinnerGravity.END);
|
||||
dropdown.setArrowPadding(8);
|
||||
// dropdown.setSpinnerItemHeight(46);
|
||||
dropdown.setSpinnerPopupElevation(14);
|
||||
|
||||
|
||||
|
||||
|
||||
dropdown.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener<IconSpinnerItem>() {
|
||||
@Override
|
||||
public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex,
|
||||
IconSpinnerItem newItem) {
|
||||
onUpdate.apply(getViewValue());
|
||||
}
|
||||
});
|
||||
|
||||
// dropdown.setLifecycleOwner(context.life);
|
||||
// slider.addOnChangeListener(new Slider.OnChangeListener() {
|
||||
// @Override
|
||||
// public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
||||
// onUpdate.apply(getViewValue());
|
||||
// }
|
||||
// });
|
||||
return dropdown;
|
||||
|
||||
}
|
||||
public void setViewValue(Object value) {
|
||||
if(dropdown == null) return;
|
||||
if(intType.isNull((int) value)){
|
||||
nullify();
|
||||
return;
|
||||
}
|
||||
|
||||
isBlank = false;
|
||||
|
||||
dropdown.setVisibility(View.VISIBLE);
|
||||
dropdown.selectItemByIndex((int) value);
|
||||
}
|
||||
public void nullify(){
|
||||
isBlank = true;
|
||||
dropdown.setVisibility(View.GONE);
|
||||
}
|
||||
public dataType getViewValue(){
|
||||
if(dropdown == null) return null;
|
||||
if(dropdown.getVisibility() == View.GONE) return new intType(name, intType.nullval);
|
||||
return new intType(name, dropdown.getSelectedIndex());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_individual_view(LinearLayout parent, dataType data){
|
||||
if(data.isNull()) return;
|
||||
TextView tv = new TextView(parent.getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(20,20,20,20);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(text_options[(int) data.get()]);
|
||||
tv.setTextSize(18);
|
||||
parent.addView(tv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static int[] generateEquidistantColors(int N) {
|
||||
int[] colors = new int[N];
|
||||
float[] hsv = new float[3]; // Hue, Saturation, Value
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
float hue = i * 1.0F / N;
|
||||
hsv[0] = hue * 360; // Convert hue to degrees (0 to 360)
|
||||
hsv[1] = 1; // Maximum saturation
|
||||
hsv[2] = 1; // Maximum brightness (value)
|
||||
|
||||
colors[i] = Color.HSVToColor(hsv);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
public void add_compiled_view(LinearLayout parent, dataType[] data){
|
||||
PieChart chart = new PieChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
parent.addView(chart);
|
||||
|
||||
int[] data_2 = new int[text_options.length];
|
||||
for(int i = 0; i < data.length; i++)
|
||||
if(!data[i].isNull())
|
||||
data_2[(int) data[i].get()]++;
|
||||
|
||||
List<PieEntry> entries = new ArrayList<>();
|
||||
for(int i = 0; i < data_2.length; i++) {
|
||||
PieEntry entry = new PieEntry((float) data_2[i], text_options[i]);
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
PieDataSet pieDataSet = new PieDataSet(entries, name);
|
||||
pieDataSet.setColors(generateEquidistantColors(text_options.length));
|
||||
PieData pieData = new PieData(pieDataSet);
|
||||
chart.setDrawHoleEnabled(false);
|
||||
chart.setData(pieData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_history_view(LinearLayout parent, dataType[] data){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
|
||||
|
||||
int[] colors = generateEquidistantColors(text_options.length);
|
||||
|
||||
LineData lineData = new LineData();
|
||||
|
||||
for(int i = 0; i < text_options.length; i++){
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int a = 0; a < data.length; a++) {
|
||||
if(data[a].isNull()) continue;
|
||||
|
||||
entries.add(
|
||||
new Entry(a,
|
||||
((int) data[a].get()) == i ? 1.f : 0.f
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, text_options[i]);
|
||||
dataSet.setColor(colors[i]);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setDrawValues(false);
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
lineData.addDataSet(dataSet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
chart.setData(lineData);
|
||||
chart.invalidate();
|
||||
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.setTouchEnabled(false);
|
||||
chart.setDragEnabled(false);
|
||||
chart.setScaleEnabled(false);
|
||||
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
chart.getAxisLeft().setAxisMinimum(0.f);
|
||||
chart.getAxisLeft().setAxisMaximum(1.f);
|
||||
|
||||
chart.getAxisRight().setAxisMinimum(0.f);
|
||||
chart.getAxisRight().setAxisMaximum(1.f);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
chart.invalidate();
|
||||
parent.addView(chart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.ridgebotics.ridgescout.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class inputType {
|
||||
public static final int slider_type_id = 255;
|
||||
public static final int dropdownType = 254;
|
||||
public static final int notesType = 253;
|
||||
public static final int tallyType = 252;
|
||||
public enum inputTypes {
|
||||
SLIDER,
|
||||
DROPDOWN,
|
||||
NOTES_INPUT,
|
||||
TALLY
|
||||
}
|
||||
public String name;
|
||||
public Object default_value;
|
||||
public abstract inputTypes getInputType();
|
||||
public abstract dataType.valueTypes getValueType();
|
||||
public abstract Object get_fallback_value();
|
||||
public abstract int get_byte_id();
|
||||
public inputType(){}
|
||||
public inputType(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public abstract String get_type_name();
|
||||
|
||||
public abstract byte[] encode() throws ByteBuilder.buildingException;
|
||||
public abstract void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption;
|
||||
|
||||
// public abstract dataType[] getConfig();
|
||||
// public abstract void setConfig(dataType[] config);
|
||||
|
||||
public abstract View createView(Context context, Function<dataType, Integer> onUpdate);
|
||||
public boolean isBlank = false;
|
||||
public abstract void nullify();
|
||||
public void setViewValue(dataType type){setViewValue(type.get());}
|
||||
public abstract void setViewValue(Object value);
|
||||
public abstract dataType getViewValue();
|
||||
|
||||
|
||||
|
||||
// private enum parameterTypeEnum {
|
||||
// paramNumber,
|
||||
// paramString,
|
||||
// paramStringArray
|
||||
// }
|
||||
//
|
||||
// public static class parameterType {
|
||||
// public String name;
|
||||
// public parameterTypeEnum id;
|
||||
// }
|
||||
//
|
||||
// public static class paramNumber extends parameterType {
|
||||
// public int val;
|
||||
// public paramNumber(String name, int val){
|
||||
// this.name = name + " (Number)";
|
||||
// this.val = val;
|
||||
// this.id = parameterTypeEnum.paramNumber;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public static class paramString extends parameterType {
|
||||
// public String val;
|
||||
// public paramString(String name, String val){
|
||||
// this.name = name + " (String)";
|
||||
// this.val = val;
|
||||
// this.id = parameterTypeEnum.paramString;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public static class paramStringArray extends parameterType {
|
||||
// public String[] val;
|
||||
// public paramStringArray(String name, String[] val){
|
||||
// this.name = name + " (String array)";
|
||||
// this.val = val;
|
||||
// this.id = parameterTypeEnum.paramStringArray;
|
||||
// }
|
||||
// }
|
||||
|
||||
// public abstract parameterType[] getDefaultParameters();
|
||||
|
||||
|
||||
public abstract void add_individual_view(LinearLayout parent, dataType data);
|
||||
|
||||
|
||||
public abstract void add_compiled_view(LinearLayout parent, dataType[] data);
|
||||
|
||||
|
||||
public abstract void add_history_view(LinearLayout parent, dataType[] data);
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
package com.ridgebotics.ridgescout.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.data.intType;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.LineDataSet;
|
||||
import com.google.android.material.slider.Slider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class sliderType extends inputType {
|
||||
// public int defaultValue;
|
||||
public int min;
|
||||
public int max;
|
||||
public int get_byte_id() {return slider_type_id;}
|
||||
public inputTypes getInputType(){return inputTypes.SLIDER;}
|
||||
public dataType.valueTypes getValueType(){return dataType.valueTypes.NUM;}
|
||||
public Object get_fallback_value(){return 0;}
|
||||
public sliderType(){};
|
||||
public String get_type_name(){return "Slider";}
|
||||
public sliderType(String name, int defaultValue, int min, int max){
|
||||
super(name);
|
||||
this.default_value = defaultValue;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] encode() throws ByteBuilder.buildingException {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
bb.addString(name);
|
||||
bb.addInt((int)default_value);
|
||||
bb.addInt(min);
|
||||
bb.addInt(max);
|
||||
return bb.build();
|
||||
}
|
||||
public void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
|
||||
name = (String) objects.get(0).get();
|
||||
default_value = objects.get(1).get();
|
||||
min = (int) objects.get(2).get();
|
||||
max = (int) objects.get(3).get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public Slider slider = null;
|
||||
|
||||
public View createView(Context context, Function<dataType, Integer> onUpdate){
|
||||
slider = new Slider(context);
|
||||
setViewValue(default_value);
|
||||
slider.setStepSize((float) 1 / (max-min));
|
||||
slider.addOnChangeListener(new Slider.OnChangeListener() {
|
||||
@Override
|
||||
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
||||
onUpdate.apply(getViewValue());
|
||||
}
|
||||
});
|
||||
return slider;
|
||||
}
|
||||
|
||||
public void setViewValue(Object value) {
|
||||
if(slider == null) return;
|
||||
if(intType.isNull((int) value)){
|
||||
nullify();
|
||||
return;
|
||||
}
|
||||
float slider_position = (float) ((int) value-min) / (max-min);
|
||||
float step_size = (float) 1/(max-min);
|
||||
int round_position = Math.round(slider_position / step_size);
|
||||
isBlank = false;
|
||||
|
||||
float slidervalue = round_position*step_size;
|
||||
if(slidervalue > 1 || slidervalue < 0) {
|
||||
AlertManager.error("Error loading slider " + name);
|
||||
slider.setValue(0);
|
||||
}else{
|
||||
slider.setValue(slidervalue);
|
||||
}
|
||||
|
||||
|
||||
slider.setVisibility(View.VISIBLE);
|
||||
}
|
||||
public dataType getViewValue(){
|
||||
if(slider == null) return null;
|
||||
if(slider.getVisibility() == View.GONE) return intType.newNull(name);
|
||||
return new intType(name, min + (int) (slider.getValue() * (max-min)));
|
||||
}
|
||||
public void nullify(){
|
||||
isBlank = true;
|
||||
slider.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_individual_view(LinearLayout parent, dataType data){
|
||||
if(data.isNull()) return;
|
||||
Slider slider = new Slider(parent.getContext());
|
||||
|
||||
float slider_position = (float) ((int) data.get()-min) / (max-min);
|
||||
float step_size = (float) 1/(max-min);
|
||||
int round_position = Math.round(slider_position / step_size);
|
||||
float value = round_position*step_size;
|
||||
if(value > 1 || value < 0) {
|
||||
AlertManager.error("Error loading slider " + name);
|
||||
slider.setValue(0);
|
||||
}else{
|
||||
slider.setValue(value);
|
||||
slider.setStepSize((float) 1 / (max-min));
|
||||
}
|
||||
|
||||
slider.setEnabled(false);
|
||||
parent.addView(slider);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private float calculateMean(int[] data) {
|
||||
float sum = 0;
|
||||
for (int value : data) {
|
||||
sum += (float) value;
|
||||
}
|
||||
return sum / data.length;
|
||||
}
|
||||
|
||||
private float calculateStandardDeviation(int[] data, float mean) {
|
||||
float sum = 0;
|
||||
for (int value : data) {
|
||||
sum += Math.pow((float) value - mean, 2);
|
||||
}
|
||||
return (float) Math.sqrt(sum / (data.length - 1));
|
||||
}
|
||||
|
||||
private List<Entry> generateNormalDistribution(float mean, float stdDev, int count, int scale) {
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
float x = i;
|
||||
float y = (float) ((1 / (stdDev * Math.sqrt(2 * Math.PI)))
|
||||
* Math.exp(-0.5 * Math.pow((x - mean) / stdDev, 2)));
|
||||
entries.add(new Entry(x, y*scale)); // Scale y for visibility
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void add_compiled_view(LinearLayout parent, dataType[] data){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
int[] values = new int[max-min+1];
|
||||
|
||||
for (int i = 0; i < data.length; i++)
|
||||
if(!data[i].isNull())
|
||||
values[(int) data[i].get()-min]++;
|
||||
|
||||
|
||||
ArrayList<Integer> mean_temp = new ArrayList<>();
|
||||
for (int i = 0; i < data.length; i++)
|
||||
if(!data[i].isNull())
|
||||
mean_temp.add((int) data[i].get());
|
||||
|
||||
int[] mean_vals = mean_temp.stream().mapToInt(Integer::intValue).toArray();
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < values.length; i++)
|
||||
entries.add(new Entry(i, values[i]));
|
||||
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, name);
|
||||
dataSet.setColor(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setDrawValues(false);
|
||||
|
||||
|
||||
|
||||
// Calculate mean and standard deviation
|
||||
float mean = calculateMean(mean_vals);
|
||||
float stdDev = calculateStandardDeviation(mean_vals, mean);
|
||||
|
||||
// Generate normal distribution curve
|
||||
List<Entry> normalDistEntries = generateNormalDistribution(mean-min, stdDev, max-min+1, (max-min)/data.length);
|
||||
|
||||
|
||||
LineDataSet normalDistSet = new LineDataSet(normalDistEntries, "Normal Distribution");
|
||||
normalDistSet.setColor(Color.RED);
|
||||
normalDistSet.setDrawCircles(false);
|
||||
normalDistSet.setDrawValues(false);
|
||||
normalDistSet.setLineWidth(2f);
|
||||
|
||||
LineData lineData = new LineData(dataSet, normalDistSet);
|
||||
|
||||
chart.setData(lineData);
|
||||
chart.invalidate();
|
||||
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.setTouchEnabled(false);
|
||||
chart.setDragEnabled(false);
|
||||
chart.setScaleEnabled(false);
|
||||
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_history_view(LinearLayout parent, dataType[] data){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < data.length; i++){
|
||||
if(data[i] == null) continue;
|
||||
if(data[i].isNull()) continue;
|
||||
|
||||
entries.add(new Entry(i, (float)(int) data[i].get()));
|
||||
}
|
||||
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, name);
|
||||
dataSet.setColor(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setDrawValues(false);
|
||||
|
||||
LineData lineData = new LineData(dataSet);
|
||||
|
||||
chart.setData(lineData);
|
||||
chart.invalidate();
|
||||
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.setTouchEnabled(false);
|
||||
chart.setDragEnabled(false);
|
||||
chart.setScaleEnabled(false);
|
||||
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
|
||||
chart.getAxisLeft().setAxisMinimum(min);
|
||||
chart.getAxisLeft().setAxisMaximum(max);
|
||||
|
||||
chart.getAxisRight().setAxisMinimum(min);
|
||||
chart.getAxisRight().setAxisMaximum(max);
|
||||
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.ridgebotics.ridgescout.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.data.intType;
|
||||
import com.ridgebotics.ridgescout.ui.scouting.TallyCounterView;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.LineDataSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class tallyType extends inputType {
|
||||
public int get_byte_id() {return tallyType;}
|
||||
public inputTypes getInputType(){return inputTypes.TALLY;}
|
||||
public dataType.valueTypes getValueType(){return dataType.valueTypes.NUM;}
|
||||
public Object get_fallback_value(){return 0;}
|
||||
public tallyType(){}
|
||||
public String get_type_name(){return "Tally";}
|
||||
public tallyType(String name, int default_value){
|
||||
super(name);
|
||||
this.default_value = default_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] encode() throws ByteBuilder.buildingException {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
bb.addString(name);
|
||||
bb.addInt((int)default_value);
|
||||
return bb.build();
|
||||
}
|
||||
public void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
|
||||
name = (String) objects.get(0).get();
|
||||
default_value = objects.get(1).get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public TallyCounterView tally = null;
|
||||
|
||||
public View createView(Context context, Function<dataType, Integer> onUpdate){
|
||||
tally = new TallyCounterView(context);
|
||||
tally.setOnCountChangedListener(n -> onUpdate.apply(getViewValue()));
|
||||
|
||||
setViewValue(default_value);
|
||||
|
||||
return tally;
|
||||
|
||||
}
|
||||
|
||||
public void setViewValue(Object value) {
|
||||
if(tally == null) return;
|
||||
System.out.println(value);
|
||||
if(intType.isNull((int)value)){
|
||||
nullify();
|
||||
return;
|
||||
}
|
||||
|
||||
isBlank = false;
|
||||
tally.setVisibility(View.VISIBLE);
|
||||
tally.setValue((int) value);
|
||||
}
|
||||
public void nullify(){
|
||||
isBlank = true;
|
||||
tally.setVisibility(View.GONE);
|
||||
}
|
||||
public dataType getViewValue(){
|
||||
if(tally == null) return null;
|
||||
if(tally.getVisibility() == View.GONE) return intType.newNull(name);
|
||||
return new intType(name, tally.getValue());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_individual_view(LinearLayout parent, dataType data){
|
||||
if(data.isNull()) return;
|
||||
|
||||
TextView tv = new TextView(parent.getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(String.valueOf((int) data.get()));
|
||||
tv.setTextSize(24);
|
||||
parent.addView(tv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static float calculateMean(int[] data) {
|
||||
float sum = 0;
|
||||
for (int value : data) {
|
||||
sum += (float) value;
|
||||
}
|
||||
return sum / data.length;
|
||||
}
|
||||
|
||||
private static float calculateStandardDeviation(int[] data, float mean) {
|
||||
float sum = 0;
|
||||
for (int value : data) {
|
||||
sum += (float) Math.pow((float) value - mean, 2);
|
||||
}
|
||||
return (float) Math.sqrt(sum / (data.length - 1));
|
||||
}
|
||||
|
||||
private static List<Entry> generateNormalDistribution(float mean, float stdDev, int count, int scale) {
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
float y = (float) ((1 / (stdDev * Math.sqrt(2 * Math.PI)))
|
||||
* Math.exp(-0.5 * Math.pow(((float) i - mean) / stdDev, 2)));
|
||||
entries.add(new Entry((float) i, y*scale)); // Scale y for visibility
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static int findMin(dataType[] data){
|
||||
int min = (int)data[0].get();
|
||||
for(int i = 1; i < data.length; i++)
|
||||
if((int)data[i].get() < min)
|
||||
min = (int)data[i].get();
|
||||
return min;
|
||||
}
|
||||
|
||||
private static int findMax(dataType[] data){
|
||||
int max = (int)data[0].get();
|
||||
for(int i = 1; i < data.length; i++)
|
||||
if((int)data[i].get() > max)
|
||||
max = (int)data[i].get();
|
||||
return max;
|
||||
}
|
||||
|
||||
public void add_compiled_view(LinearLayout parent, dataType[] data){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
int min = findMin(data);
|
||||
int max = findMax(data);
|
||||
|
||||
int[] values = new int[max-min+1];
|
||||
|
||||
for (int i = 0; i < data.length; i++)
|
||||
if(data[i] != null && data[i].isNull())
|
||||
values[(int) data[i].get()-min]++;
|
||||
|
||||
|
||||
ArrayList<Integer> mean_temp = new ArrayList<>();
|
||||
for (int i = 0; i < data.length; i++)
|
||||
if((int)data[i].get() != 0)
|
||||
mean_temp.add((int) data[i].get());
|
||||
|
||||
int[] mean_vals = mean_temp.stream().mapToInt(Integer::intValue).toArray();
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < values.length; i++)
|
||||
entries.add(new Entry(i, values[i]));
|
||||
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, name);
|
||||
dataSet.setColor(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setDrawValues(false);
|
||||
|
||||
|
||||
|
||||
// Calculate mean and standard deviation
|
||||
float mean = calculateMean(mean_vals);
|
||||
float stdDev = calculateStandardDeviation(mean_vals, mean);
|
||||
|
||||
// Generate normal distribution curve
|
||||
List<Entry> normalDistEntries = generateNormalDistribution(mean-min, stdDev, max-min+1, (max-min)/data.length);
|
||||
|
||||
|
||||
LineDataSet normalDistSet = new LineDataSet(normalDistEntries, "Normal Distribution");
|
||||
normalDistSet.setColor(Color.RED);
|
||||
normalDistSet.setDrawCircles(false);
|
||||
normalDistSet.setDrawValues(false);
|
||||
normalDistSet.setLineWidth(2f);
|
||||
|
||||
LineData lineData = new LineData(dataSet, normalDistSet);
|
||||
|
||||
chart.setData(lineData);
|
||||
chart.invalidate();
|
||||
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.setTouchEnabled(false);
|
||||
chart.setDragEnabled(false);
|
||||
chart.setScaleEnabled(false);
|
||||
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_history_view(LinearLayout parent, dataType[] data){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
int min = findMin(data);
|
||||
int max = findMax(data);
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < data.length; i++){
|
||||
if(data[i] == null) continue;
|
||||
if(data[i].isNull()) continue;
|
||||
|
||||
entries.add(new Entry(i, (float)(int) data[i].get()));
|
||||
}
|
||||
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, name);
|
||||
dataSet.setColor(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setDrawValues(false);
|
||||
|
||||
LineData lineData = new LineData(dataSet);
|
||||
|
||||
chart.setData(lineData);
|
||||
chart.invalidate();
|
||||
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.setTouchEnabled(false);
|
||||
chart.setDragEnabled(false);
|
||||
chart.setScaleEnabled(false);
|
||||
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
|
||||
chart.getAxisLeft().setAxisMinimum(min);
|
||||
chart.getAxisLeft().setAxisMaximum(max);
|
||||
|
||||
chart.getAxisRight().setAxisMinimum(min);
|
||||
chart.getAxisRight().setAxisMaximum(max);
|
||||
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
package com.ridgebotics.ridgescout.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.data.stringType;
|
||||
import com.ridgebotics.ridgescout.utility.SentimentAnalysis;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.LineDataSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class textType extends inputType {
|
||||
|
||||
public int get_byte_id() {return notesType;}
|
||||
public inputTypes getInputType(){return inputTypes.NOTES_INPUT;}
|
||||
public dataType.valueTypes getValueType(){return dataType.valueTypes.STRING;}
|
||||
public Object get_fallback_value(){return "<no-notes>";}
|
||||
public textType(){}
|
||||
public textType(String name, String default_text){
|
||||
super(name);
|
||||
this.default_value = default_text;
|
||||
}
|
||||
public String get_type_name(){return "Text";}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] encode() throws ByteBuilder.buildingException {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
bb.addString(name);
|
||||
bb.addString((String) default_value);
|
||||
return bb.build();
|
||||
}
|
||||
public void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
|
||||
name = (String) objects.get(0).get();
|
||||
default_value = objects.get(1).get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public EditText text = null;
|
||||
|
||||
public View createView(Context context, Function<dataType, Integer> onUpdate){
|
||||
text = new EditText(context);
|
||||
text.setText((String)default_value);
|
||||
text.addTextChangedListener(new TextWatcher() {
|
||||
public void afterTextChanged(Editable s) {
|
||||
onUpdate.apply(getViewValue()); }
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
public void setViewValue(Object value) {
|
||||
if(text == null) return;
|
||||
if(stringType.isNull((String) value)){
|
||||
nullify();
|
||||
return;
|
||||
}
|
||||
isBlank = false;
|
||||
text.setVisibility(View.VISIBLE);
|
||||
text.setText((String) value);
|
||||
}
|
||||
public void nullify(){
|
||||
isBlank = true;
|
||||
text.setVisibility(View.GONE);
|
||||
}
|
||||
public dataType getViewValue(){
|
||||
if(text == null) return null;
|
||||
if(text.getVisibility() == View.GONE) return new stringType(name, stringType.nullval);
|
||||
return new stringType(name, text.getText().toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_individual_view(LinearLayout parent, dataType data){
|
||||
if(data.isNull()) return;
|
||||
TextView tv = new TextView(parent.getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText((String) data.get());
|
||||
tv.setTextSize(18);
|
||||
parent.addView(tv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
float positive_mean = 0;
|
||||
int count = 0;
|
||||
|
||||
TextView positive_text;
|
||||
|
||||
public void add_compiled_view(LinearLayout parent, dataType[] data) {
|
||||
positive_mean = 0;
|
||||
count = 0;
|
||||
|
||||
positive_text = new TextView(parent.getContext());
|
||||
positive_text.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
positive_text.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
positive_text.setTextSize(20);
|
||||
parent.addView(positive_text);
|
||||
|
||||
for (int i = 0; i < data.length; i++){
|
||||
if (!data[i].isNull()) {
|
||||
SentimentAnalysis.analyse((String) data[i].get(), new SentimentAnalysis.resultCallback() {
|
||||
@Override
|
||||
public void onFinish(float sentiment) {
|
||||
positive_mean += sentiment;
|
||||
count++;
|
||||
|
||||
positive_text.setText("Sentiment: " + (positive_mean / count));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void add_history_view(LinearLayout parent, dataType[] data){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if(data[i] == null) continue;
|
||||
if(data[i].isNull()) continue;
|
||||
|
||||
entries.add(
|
||||
new Entry(i,
|
||||
SentimentAnalysis.analyse_sync( (String) data[i].get() )
|
||||
)
|
||||
);
|
||||
}
|
||||
LineDataSet dataSet = new LineDataSet(entries, "Sentiment");
|
||||
dataSet.setColor(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
dataSet.setDrawCircles(false);
|
||||
dataSet.setDrawValues(false);
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
|
||||
|
||||
LineData lineData = new LineData(dataSet);
|
||||
|
||||
chart.setData(lineData);
|
||||
chart.invalidate();
|
||||
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.setTouchEnabled(false);
|
||||
chart.setDragEnabled(false);
|
||||
chart.setScaleEnabled(false);
|
||||
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
chart.getAxisLeft().setAxisMinimum(0.f);
|
||||
chart.getAxisLeft().setAxisMaximum(1.f);
|
||||
|
||||
chart.getAxisRight().setAxisMinimum(0.f);
|
||||
chart.getAxisRight().setAxisMaximum(1.f);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
chart.invalidate();
|
||||
parent.addView(chart);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.ridgebotics.ridgescout.ui;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTeamSelectorBinding;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TeamSelectorFragment extends Fragment {
|
||||
private FragmentTeamSelectorBinding binding;
|
||||
|
||||
private static boolean pits_mode;
|
||||
public static void setPits_mode(boolean mode){
|
||||
pits_mode = mode;
|
||||
}
|
||||
|
||||
private static onTeamSelected onSelect = new onTeamSelected() {@Override public void onSelect(TeamSelectorFragment self, frcTeam team) {}};
|
||||
|
||||
public interface onTeamSelected {
|
||||
void onSelect(TeamSelectorFragment self, frcTeam team);
|
||||
}
|
||||
public static void setOnSelect(onTeamSelected tmponSelect){
|
||||
onSelect = tmponSelect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentTeamSelectorBinding.inflate(inflater, container, false);
|
||||
|
||||
// event = fileEditor.g
|
||||
DataManager.reload_event();
|
||||
|
||||
if(evcode == null || evcode.equals("unset")){
|
||||
AlertManager.error("You somehow have not loaded an event!");
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
load_teams();
|
||||
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
public void load_teams(){
|
||||
// binding.pitFileIndicator.setVisibility(View.GONE);
|
||||
// binding.pitTeamName.setVisibility(View.GONE);
|
||||
// binding.pitTeamDescription.setVisibility(View.GONE);
|
||||
//
|
||||
// clear_fields();
|
||||
|
||||
|
||||
int[] teamNums = new int[event.teams.size()];
|
||||
|
||||
for(int i = 0 ; i < event.teams.size(); i++){
|
||||
teamNums[i] = event.teams.get(i).teamNumber;
|
||||
}
|
||||
|
||||
Arrays.sort(teamNums);
|
||||
|
||||
TableLayout table = new TableLayout(getContext());
|
||||
table.setStretchAllColumns(true);
|
||||
binding.teams.addView(table);
|
||||
|
||||
|
||||
for(int i = 0; i < event.teams.size(); i++){
|
||||
frcTeam team = null;
|
||||
for(int a = 0 ; a < event.teams.size(); a++){
|
||||
if(event.teams.get(a).teamNumber == teamNums[i]){
|
||||
team = event.teams.get(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TableRow tr = new TableRow(getContext());
|
||||
TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
rowParams.setMargins(20,20,20,20);
|
||||
tr.setLayoutParams(rowParams);
|
||||
tr.setPadding(20,20,20,20);
|
||||
table.addView(tr);
|
||||
|
||||
if(!pits_mode || fileEditor.fileExist(evcode + "-" + team.teamNumber + ".pitscoutdata")){
|
||||
tr.setBackgroundColor(0x3000FF00);
|
||||
}else{
|
||||
tr.setBackgroundColor(0x30FF0000);
|
||||
}
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText(String.valueOf(team.teamNumber));
|
||||
tv.setTextSize(20);
|
||||
tr.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setText(team.teamName);
|
||||
tv.setTextSize(16);
|
||||
tr.addView(tv);
|
||||
|
||||
frcTeam finalTeam = team;
|
||||
tr.setOnClickListener(v -> {
|
||||
onSelect.onSelect(this, finalTeam);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataCompareBinding;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataReportBinding;
|
||||
|
||||
public class CompareFragment extends Fragment {
|
||||
FragmentDataCompareBinding binding;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentDataCompareBinding.inflate(inflater, container, false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
|
||||
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataBinding;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.ui.TeamSelectorFragment;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
|
||||
public class DataFragment extends Fragment {
|
||||
|
||||
private FragmentDataBinding binding;
|
||||
|
||||
private boolean submenu = false;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentDataBinding.inflate(inflater, container, false);
|
||||
View root = binding.getRoot();
|
||||
|
||||
String evcode = latestSettings.settings.get_evcode();
|
||||
|
||||
binding.fieldsButton.setOnClickListener(v -> {
|
||||
findNavController(this).navigate(R.id.action_navigation_data_to_navigation_data_fields_chooser);
|
||||
});
|
||||
|
||||
if(evcode.equals("unset")){
|
||||
binding.noEventError.setVisibility(View.VISIBLE);
|
||||
|
||||
binding.buttons.setVisibility(View.VISIBLE);
|
||||
binding.teamsButton.setEnabled(false);
|
||||
binding.compareButton.setEnabled(false);
|
||||
binding.reportButton.setEnabled(false);
|
||||
binding.fieldsButton.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
frcEvent event = frcEvent.decode(fileEditor.readFile(evcode + ".eventdata"));
|
||||
|
||||
binding.teamsButton.setOnClickListener(v -> {
|
||||
TeamSelectorFragment.setPits_mode(false);
|
||||
TeamSelectorFragment.setOnSelect(new TeamSelectorFragment.onTeamSelected() {
|
||||
@Override
|
||||
public void onSelect(TeamSelectorFragment self, frcTeam team) {
|
||||
TeamsFragment.setTeam(team);
|
||||
findNavController(self).navigate(R.id.action_navigation_team_selector_to_navigation_data_teams);
|
||||
}
|
||||
});
|
||||
findNavController(this).navigate(R.id.action_navigation_data_to_navigation_team_selector);
|
||||
});
|
||||
|
||||
binding.compareButton.setOnClickListener(v -> {
|
||||
findNavController(this).navigate(R.id.action_navigation_data_to_navigation_data_compare);
|
||||
});
|
||||
|
||||
binding.reportButton.setOnClickListener(v -> {
|
||||
findNavController(this).navigate(R.id.action_navigation_data_to_navigation_data_report);
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import static android.text.InputType.TYPE_CLASS_NUMBER;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.input.dropdownType;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.types.input.sliderType;
|
||||
import com.ridgebotics.ridgescout.types.input.tallyType;
|
||||
import com.ridgebotics.ridgescout.types.input.textType;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
|
||||
public class FieldEditorHelper {
|
||||
private enum parameterTypeEnum {
|
||||
paramNumber,
|
||||
paramString,
|
||||
paramStringArray
|
||||
}
|
||||
|
||||
public static class parameterType {
|
||||
public String name;
|
||||
public parameterTypeEnum id;
|
||||
}
|
||||
|
||||
public static class paramNumber extends parameterType{
|
||||
public int val;
|
||||
public paramNumber(String name, int val){
|
||||
this.name = name + " (Number)";
|
||||
this.val = val;
|
||||
this.id = parameterTypeEnum.paramNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public static class paramString extends parameterType {
|
||||
public String val;
|
||||
public paramString(String name, String val){
|
||||
this.name = name + " (String)";
|
||||
this.val = val;
|
||||
this.id = parameterTypeEnum.paramString;
|
||||
}
|
||||
}
|
||||
|
||||
public static class paramStringArray extends parameterType{
|
||||
public String[] val;
|
||||
public paramStringArray(String name, String[] val){
|
||||
this.name = name + " (String array)";
|
||||
this.val = val;
|
||||
this.id = parameterTypeEnum.paramStringArray;
|
||||
}
|
||||
}
|
||||
|
||||
public static final parameterType[] defaultSliderParams = new parameterType[]{
|
||||
new paramNumber("Min", 0),
|
||||
new paramNumber("Max", 10),
|
||||
new paramNumber("Default Value", 5)
|
||||
};
|
||||
public static final parameterType[] defaultDropdownParams = new parameterType[]{
|
||||
new paramStringArray("Default Value", new String[]{"Zero","One","Two","Three"}),
|
||||
new paramNumber("Default Option", 0),
|
||||
};
|
||||
public static final parameterType[] defaultTextParams = new parameterType[]{
|
||||
new paramString("Default Value", "")
|
||||
};
|
||||
public static final parameterType[] defaultTallyParams = new parameterType[]{
|
||||
new paramNumber("Default Value", 0)
|
||||
};
|
||||
|
||||
|
||||
private static parameterType[] getSliderParams(sliderType s){
|
||||
return new parameterType[]{
|
||||
new paramNumber("Min", s.min),
|
||||
new paramNumber("Max", s.max),
|
||||
new paramNumber("Default Value", (int) s.default_value)
|
||||
};
|
||||
}
|
||||
|
||||
private static parameterType[] getDropdownParams(dropdownType s){
|
||||
return new parameterType[]{
|
||||
new paramStringArray("Default Value",s.text_options),
|
||||
new paramNumber("Default Option", (int) s.default_value),
|
||||
};
|
||||
}
|
||||
|
||||
private static parameterType[] getTextParams(textType s){
|
||||
return new parameterType[]{
|
||||
new paramString("Default Value", (String) s.default_value)
|
||||
};
|
||||
}
|
||||
|
||||
private static parameterType[] getTallyParams(tallyType s){
|
||||
return new parameterType[]{
|
||||
new paramNumber("Default Value", (int) s.default_value)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void setSliderParams(sliderType s, parameterType[] types){
|
||||
s.min = ((paramNumber) types[0]).val;
|
||||
s.max = ((paramNumber) types[1]).val;
|
||||
s.default_value = ((paramNumber) types[2]).val;
|
||||
}
|
||||
|
||||
public static void setDropdownParams(dropdownType s, parameterType[] types){
|
||||
s.text_options = ((paramStringArray) types[0]).val;
|
||||
s.default_value = ((paramNumber) types[1]).val;
|
||||
}
|
||||
|
||||
public static void setTextParams(textType s, parameterType[] types){
|
||||
s.default_value = ((paramString) types[0]).val;
|
||||
}
|
||||
|
||||
public static void setTallyParams(tallyType s, parameterType[] types){
|
||||
s.default_value = ((paramNumber) types[0]).val;
|
||||
}
|
||||
|
||||
private static void setInputParameter(inputType t, parameterType[] types){
|
||||
switch (t.getInputType()){
|
||||
case TALLY:
|
||||
setTallyParams((tallyType) t, types);
|
||||
break;
|
||||
case SLIDER:
|
||||
setSliderParams((sliderType) t, types);
|
||||
break;
|
||||
case DROPDOWN:
|
||||
setDropdownParams((dropdownType) t, types);
|
||||
break;
|
||||
case NOTES_INPUT:
|
||||
setTextParams((textType) t, types);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static parameterType[] getParamsFromInputType(inputType t){
|
||||
switch (t.getInputType()){
|
||||
case TALLY:
|
||||
return getTallyParams((tallyType) t);
|
||||
case SLIDER:
|
||||
return getSliderParams((sliderType) t);
|
||||
case DROPDOWN:
|
||||
return getDropdownParams((dropdownType) t);
|
||||
case NOTES_INPUT:
|
||||
return getTextParams((textType) t);
|
||||
}
|
||||
return new parameterType[]{};
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static View createNumberEdit(Context c, int value){
|
||||
EditText text = new EditText(c);
|
||||
text.setInputType(TYPE_CLASS_NUMBER);
|
||||
text.setText(String.valueOf(value));
|
||||
return text;
|
||||
}
|
||||
|
||||
private static View createStringEdit(Context c, String value){
|
||||
EditText text = new EditText(c);
|
||||
text.setText(value);
|
||||
return text;
|
||||
}
|
||||
|
||||
private static View createStringArrayEdit(Context c, String[] value){
|
||||
EditText text = new EditText(c);
|
||||
text.setText(String.join("\n", value));
|
||||
return text;
|
||||
}
|
||||
|
||||
private static View createEdit(Context c, parameterType t){
|
||||
switch (t.id){
|
||||
case paramNumber:
|
||||
return createNumberEdit(c, ((paramNumber) t).val);
|
||||
case paramString:
|
||||
return createStringEdit(c, ((paramString) t).val);
|
||||
case paramStringArray:
|
||||
return createStringArrayEdit(c, ((paramStringArray) t).val);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static boolean readEdit(View v, parameterType t){
|
||||
try{
|
||||
String val;
|
||||
switch (t.id) {
|
||||
case paramNumber:
|
||||
val = ((EditText) v).getText().toString();
|
||||
if(val.isEmpty() || val.isBlank()) return false;
|
||||
((paramNumber) t).val = Integer.parseInt(val);
|
||||
break;
|
||||
case paramString:
|
||||
val = ((EditText) v).getText().toString();
|
||||
//if(val.isEmpty() || val.isBlank()) return false;
|
||||
((paramString) t).val = val;
|
||||
break;
|
||||
case paramStringArray:
|
||||
val = ((EditText) v).getText().toString();
|
||||
if(val.isEmpty() || val.isBlank()) return false;
|
||||
((paramStringArray) t).val = val.split("\n");
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlertManager.error(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private parameterType[] types;
|
||||
private View[] views;
|
||||
private inputType t;
|
||||
public FieldEditorHelper(Context c, inputType t, TableLayout parentView, parameterType[] tmptypes){
|
||||
this.types = tmptypes;
|
||||
this.t = t;
|
||||
views = new View[types.length];
|
||||
for(int i = 0; i < types.length; i++){
|
||||
TextView tv = new TextView(c);
|
||||
tv.setText(types[i].name);
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
tv.setTextSize(20);
|
||||
parentView.addView(tv);
|
||||
|
||||
views[i] = createEdit(c, types[i]);
|
||||
parentView.addView(views[i]);
|
||||
}
|
||||
}
|
||||
public FieldEditorHelper(Context c, inputType t, TableLayout parentView){
|
||||
this(c,t,parentView,getParamsFromInputType(t));
|
||||
}
|
||||
|
||||
public boolean save(){
|
||||
for(int i = 0; i < types.length; i++){
|
||||
if(!readEdit(views[i], types[i]))
|
||||
return false;
|
||||
}
|
||||
setInputParameter(t, types);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataFieldsChooserBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.fields;
|
||||
|
||||
public class FieldsChooserFragment extends Fragment {
|
||||
|
||||
FragmentDataFieldsChooserBinding binding;
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentDataFieldsChooserBinding.inflate(inflater, container, false);
|
||||
|
||||
binding.matchScoutingButton.setOnClickListener(v -> {
|
||||
FieldsFragment.set_filename(fields.matchFieldsFilename);
|
||||
findNavController(this).navigate(R.id.action_navigation_data_fields_chooser_to_navigation_data_fields);
|
||||
});
|
||||
|
||||
binding.pitScoutingButton.setOnClickListener(v -> {
|
||||
FieldsFragment.set_filename(fields.pitsFieldsFilename);
|
||||
findNavController(this).navigate(R.id.action_navigation_data_fields_chooser_to_navigation_data_fields);
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,522 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataFieldsBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.fields;
|
||||
import com.ridgebotics.ridgescout.types.input.dropdownType;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.types.input.sliderType;
|
||||
import com.ridgebotics.ridgescout.types.input.tallyType;
|
||||
import com.ridgebotics.ridgescout.types.input.textType;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.skydoves.powerspinner.IconSpinnerAdapter;
|
||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||
import com.skydoves.powerspinner.PowerSpinnerView;
|
||||
import com.skydoves.powerspinner.SpinnerGravity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FieldsFragment extends Fragment {
|
||||
FragmentDataFieldsBinding binding;
|
||||
|
||||
private static String filename;
|
||||
public static void set_filename(String tmpfilename){
|
||||
filename = tmpfilename;
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentDataFieldsBinding.inflate(inflater, container, false);
|
||||
|
||||
binding.revertVersionButton.setVisibility(View.VISIBLE);
|
||||
binding.valueEditScrollview.setOnTouchListener((v, event) -> true);
|
||||
|
||||
|
||||
binding.saveButton.setVisibility(View.GONE);
|
||||
binding.cancelEditButton.setVisibility(View.GONE);
|
||||
binding.editButton.setVisibility(View.GONE);
|
||||
binding.upButton.setVisibility(View.GONE);
|
||||
binding.addButton.setVisibility(View.GONE);
|
||||
binding.downButton.setVisibility(View.GONE);
|
||||
binding.deleteButton.setVisibility(View.GONE);
|
||||
|
||||
binding.valueEditContainer.setVisibility(View.GONE);
|
||||
|
||||
load_field_menu();
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private static final int background_color = 0x5000ff00;
|
||||
private static final int unfocused_background_color = 0x2000ff00;
|
||||
|
||||
inputType[][] values;
|
||||
|
||||
private void load_field_menu() {
|
||||
|
||||
values = fields.load(filename);
|
||||
|
||||
binding.fieldsArea.bringToFront();
|
||||
binding.fieldsArea.setStretchAllColumns(true);
|
||||
binding.fieldsArea.removeAllViews();
|
||||
binding.fieldsArea.setReorderingEnabled(false);
|
||||
|
||||
if(values == null) return;
|
||||
|
||||
for(int i = 0; i < values.length; i++){
|
||||
|
||||
TableRow tr = new TableRow(getContext());
|
||||
TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
|
||||
rowParams.setMargins(20,20,20,20);
|
||||
tr.setLayoutParams(rowParams);
|
||||
tr.setPadding(20,20,20,20);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText("v" + i);
|
||||
tv.setTextSize(20);
|
||||
tr.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setText(values[i].length + " Fields");
|
||||
tv.setTextSize(16);
|
||||
tr.addView(tv);
|
||||
|
||||
binding.fieldsArea.addView(tr);
|
||||
|
||||
if(i == values.length-1) {
|
||||
tr.setBackgroundColor(background_color);
|
||||
int fi = i;
|
||||
tr.setOnClickListener(v -> {
|
||||
display_fields(values[fi]);
|
||||
});
|
||||
}else{
|
||||
tr.setBackgroundColor(unfocused_background_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void display_fields(inputType[] version_values) {
|
||||
binding.fieldsArea.removeAllViews();
|
||||
binding.fieldsArea.setReorderingEnabled(false);
|
||||
|
||||
binding.revertVersionButton.setVisibility(View.GONE);
|
||||
|
||||
binding.saveButton.setVisibility(View.GONE);
|
||||
binding.editButton.setVisibility(View.GONE);
|
||||
binding.upButton.setVisibility(View.VISIBLE);
|
||||
binding.addButton.setVisibility(View.VISIBLE);
|
||||
binding.downButton.setVisibility(View.VISIBLE);
|
||||
|
||||
binding.valueEditContainer.setVisibility(View.GONE);
|
||||
|
||||
for(int i = 0; i < version_values.length; i++){
|
||||
addRow(version_values[i]);
|
||||
}
|
||||
selindex = -1;
|
||||
|
||||
|
||||
binding.addButton.setOnClickListener(this::addField);
|
||||
binding.saveButton.setOnClickListener(this::buttonfunc);
|
||||
}
|
||||
|
||||
private void addRow(inputType field){
|
||||
TableRow tr = getTableRow(field);
|
||||
|
||||
binding.fieldsArea.addView(tr);
|
||||
|
||||
tr.setOnClickListener(v -> {
|
||||
binding.editButton.setVisibility(View.VISIBLE);
|
||||
trOnClick(values[values.length-1], tr);
|
||||
});
|
||||
|
||||
binding.upButton.setOnClickListener(v -> {
|
||||
if(selindex != 0) {
|
||||
binding.saveButton.setVisibility(View.VISIBLE);
|
||||
binding.fieldsArea.updateRowOrder(selindex, selindex - 1);
|
||||
selindex -= 1;
|
||||
}
|
||||
});
|
||||
|
||||
binding.downButton.setOnClickListener(v -> {
|
||||
if(selindex != values[values.length-1].length-1) {
|
||||
binding.saveButton.setVisibility(View.VISIBLE);
|
||||
binding.fieldsArea.updateRowOrder(selindex, selindex + 1);
|
||||
selindex += 1;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void buttonfunc(View v){
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||
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.setPositiveButton("OK", null);
|
||||
alert.setNegativeButton("Cancel", null);
|
||||
alert.setCancelable(true);
|
||||
alert.setOnDismissListener(b -> {
|
||||
inputType[][] currentValues = fields.load(filename);
|
||||
assert currentValues != null;
|
||||
inputType[][] newValues = new inputType[currentValues.length+1][];
|
||||
System.arraycopy(currentValues, 0, newValues, 0, currentValues.length);
|
||||
|
||||
newValues[newValues.length-1] = new inputType[values[values.length-1].length];
|
||||
|
||||
for(int i = 0; i < values[values.length-1].length; i++){
|
||||
newValues[newValues.length-1][i] = values[values.length-1][binding.fieldsArea.getReorderedIndexes().get(i)];
|
||||
}
|
||||
// newValues[newValues.length-1] = values[values.length-1];
|
||||
|
||||
boolean saved = fields.save(filename, newValues);
|
||||
AlertManager.alert("Saved", String.valueOf(saved));
|
||||
|
||||
Navigation.findNavController((Activity) getContext(), R.id.nav_host_fragment_activity_main).navigate(R.id.action_navigation_data_fields_to_navigation_data_fields_chooser);
|
||||
});
|
||||
alert.create().show();
|
||||
}
|
||||
|
||||
private int selindex = -1;
|
||||
|
||||
private void trOnClick(inputType[] version_values, TableRow tr){
|
||||
selindex = -1;
|
||||
for(int i = 0; i < binding.fieldsArea.getChildCount(); i++){
|
||||
View v = binding.fieldsArea.getChildAt(i);
|
||||
|
||||
if(v.equals(tr)) {
|
||||
tr.setBackgroundColor(background_color);
|
||||
selindex = i;
|
||||
} else
|
||||
binding.fieldsArea.getChildAt(i).setBackgroundColor(unfocused_background_color);
|
||||
}
|
||||
|
||||
onFieldSelect(version_values[binding.fieldsArea.getReorderedIndexes().get(selindex)]);
|
||||
}
|
||||
|
||||
private void onFieldSelect(inputType field){
|
||||
//System.out.println(field.name);
|
||||
|
||||
binding.editButton.setOnClickListener(v -> {
|
||||
binding.editButton.setVisibility(View.GONE);
|
||||
binding.addButton.setVisibility(View.GONE);
|
||||
binding.upButton.setVisibility(View.GONE);
|
||||
binding.downButton.setVisibility(View.GONE);
|
||||
|
||||
binding.ValueEditTable.removeAllViews();
|
||||
binding.valueEditContainer.setVisibility(View.VISIBLE);
|
||||
TextView tv = new TextView(getContext());
|
||||
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
tv.setText(field.name);
|
||||
tv.setPadding(8,8,8,8);
|
||||
tv.setTextSize(24);
|
||||
|
||||
binding.ValueEditTable.addView(tv);
|
||||
|
||||
final FieldEditorHelper fe = new FieldEditorHelper(
|
||||
getContext(),
|
||||
field,
|
||||
binding.ValueEditTable
|
||||
);
|
||||
|
||||
binding.saveButton.setVisibility(View.VISIBLE);
|
||||
binding.saveButton.setOnClickListener(a -> {
|
||||
System.out.println(fe.save());
|
||||
defaultVisibility();
|
||||
});
|
||||
|
||||
binding.cancelEditButton.setVisibility(View.VISIBLE);
|
||||
binding.cancelEditButton.setOnClickListener(a -> {
|
||||
defaultVisibility();
|
||||
});
|
||||
|
||||
binding.deleteButton.setVisibility(View.VISIBLE);
|
||||
binding.deleteButton.setOnClickListener(a -> {
|
||||
deleteField(field);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void deleteField(inputType field){
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||
alert.setTitle("Warning!");
|
||||
alert.setMessage("Removing a value will result in data being deleted in subsequent field versions!");
|
||||
alert.setNegativeButton("Cancel", null);
|
||||
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
defaultVisibility();
|
||||
|
||||
int oldindex = -1;
|
||||
for(int i = 0; i < values[values.length - 1].length; i++){
|
||||
if(values[values.length - 1][i].equals(field)){
|
||||
oldindex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(oldindex != -1) {
|
||||
System.out.println(Arrays.toString(values[values.length - 1]));
|
||||
binding.fieldsArea.removeViewAt(selindex);
|
||||
binding.fieldsArea.removeElement(oldindex);
|
||||
values[values.length - 1] = removeElement(values[values.length - 1], oldindex);
|
||||
selindex = -1;
|
||||
AlertManager.toast("Removed!");
|
||||
binding.editButton.setVisibility(View.GONE);
|
||||
System.out.println(Arrays.toString(values[values.length - 1]));
|
||||
//System.out.println(values[values.length-1].length);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
alert.setCancelable(true);
|
||||
alert.create().show();
|
||||
}
|
||||
|
||||
public inputType[] removeElement(inputType[] src, int i) {
|
||||
inputType[] newArray = new inputType[src.length - 1];
|
||||
if (i > 0){
|
||||
System.arraycopy(src, 0, newArray, 0, i);
|
||||
}
|
||||
|
||||
if (newArray.length > i){
|
||||
System.arraycopy(src, i + 1, newArray, i, newArray.length - i);
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void defaultVisibility() {
|
||||
binding.editButton.setVisibility(View.VISIBLE);
|
||||
binding.addButton.setVisibility(View.VISIBLE);
|
||||
binding.upButton.setVisibility(View.VISIBLE);
|
||||
binding.downButton.setVisibility(View.VISIBLE);
|
||||
binding.ValueEditTable.removeAllViews();
|
||||
binding.valueEditContainer.setVisibility(View.GONE);
|
||||
binding.cancelEditButton.setVisibility(View.GONE);
|
||||
binding.deleteButton.setVisibility(View.GONE);
|
||||
binding.saveButton.setOnClickListener(this::buttonfunc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void addField(View v) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
builder.setTitle("Title");
|
||||
|
||||
final EditText input = new EditText(getContext());
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
builder.setView(input);
|
||||
|
||||
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String title = input.getText().toString();
|
||||
if(title.isEmpty() || title.isBlank()) {
|
||||
AlertManager.error("Title cannot be blank!");
|
||||
return;
|
||||
}
|
||||
addField_Part_2(title);
|
||||
}
|
||||
});
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void addField_Part_2(String title) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
builder.setTitle("Title");
|
||||
|
||||
final PowerSpinnerView dropdown = new PowerSpinnerView(getContext());
|
||||
|
||||
List<IconSpinnerItem> iconSpinnerItems = new ArrayList<>();
|
||||
|
||||
iconSpinnerItems.add(new IconSpinnerItem("Slider"));
|
||||
iconSpinnerItems.add(new IconSpinnerItem("Text"));
|
||||
iconSpinnerItems.add(new IconSpinnerItem("Dropdown"));
|
||||
iconSpinnerItems.add(new IconSpinnerItem("Tally"));
|
||||
|
||||
IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown);
|
||||
|
||||
dropdown.setGravity(Gravity.CENTER);
|
||||
|
||||
dropdown.setSpinnerAdapter(iconSpinnerAdapter);
|
||||
dropdown.setItems(iconSpinnerItems);
|
||||
|
||||
dropdown.selectItemByIndex(0);
|
||||
|
||||
dropdown.setPadding(10,20,10,20);
|
||||
dropdown.setBackgroundColor(0xf0000000);
|
||||
dropdown.setTextColor(0xff00ff00);
|
||||
dropdown.setTextSize(14.5f);
|
||||
dropdown.setArrowGravity(SpinnerGravity.END);
|
||||
dropdown.setArrowPadding(8);
|
||||
// dropdown.setSpinnerItemHeight(46);
|
||||
dropdown.setSpinnerPopupElevation(14);
|
||||
|
||||
builder.setView(dropdown);
|
||||
|
||||
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
addField_Part_3(title, dropdown.getSelectedIndex());
|
||||
}
|
||||
});
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void addField_Part_3(String title, int typeIndex) {
|
||||
switch (typeIndex){
|
||||
case 0:
|
||||
sliderType slider = new sliderType();
|
||||
slider.name = title;
|
||||
FieldEditorHelper.setSliderParams(slider, FieldEditorHelper.defaultSliderParams);
|
||||
addField_Part_4(slider);
|
||||
break;
|
||||
case 1:
|
||||
textType text = new textType();
|
||||
text.name = title;
|
||||
FieldEditorHelper.setTextParams(text, FieldEditorHelper.defaultTextParams);
|
||||
addField_Part_4(text);
|
||||
break;
|
||||
case 2:
|
||||
dropdownType dropdown = new dropdownType();
|
||||
dropdown.name = title;
|
||||
FieldEditorHelper.setDropdownParams(dropdown, FieldEditorHelper.defaultDropdownParams);
|
||||
addField_Part_4(dropdown);
|
||||
break;
|
||||
case 3:
|
||||
tallyType tally = new tallyType();
|
||||
tally.name = title;
|
||||
FieldEditorHelper.setTallyParams(tally, FieldEditorHelper.defaultTallyParams);
|
||||
addField_Part_4(tally);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private void addField_Part_4(inputType field) {
|
||||
binding.editButton.setVisibility(View.GONE);
|
||||
binding.addButton.setVisibility(View.GONE);
|
||||
binding.upButton.setVisibility(View.GONE);
|
||||
binding.downButton.setVisibility(View.GONE);
|
||||
|
||||
binding.ValueEditTable.removeAllViews();
|
||||
binding.valueEditContainer.setVisibility(View.VISIBLE);
|
||||
TextView tv = new TextView(getContext());
|
||||
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
tv.setText(field.name);
|
||||
tv.setPadding(8,8,8,8);
|
||||
tv.setTextSize(24);
|
||||
|
||||
binding.ValueEditTable.addView(tv);
|
||||
|
||||
final FieldEditorHelper fe = new FieldEditorHelper(
|
||||
getContext(),
|
||||
field,
|
||||
binding.ValueEditTable
|
||||
);
|
||||
|
||||
binding.saveButton.setVisibility(View.VISIBLE);
|
||||
binding.saveButton.setOnClickListener(a -> {
|
||||
inputType[] newValues = new inputType[values[values.length-1].length+1];
|
||||
System.arraycopy(values[values.length-1], 0, newValues, 0, values[values.length-1].length);
|
||||
newValues[newValues.length-1] = field;
|
||||
values[values.length-1] = newValues;
|
||||
|
||||
AlertManager.alert("Test", String.valueOf(binding.fieldsArea.getReorderedIndexes()));
|
||||
|
||||
//TableRow tr = getTableRow(field);
|
||||
//binding.fieldsArea.addView(tr);
|
||||
addRow(field);
|
||||
|
||||
System.out.println(fe.save());
|
||||
defaultVisibility();
|
||||
});
|
||||
|
||||
binding.cancelEditButton.setVisibility(View.VISIBLE);
|
||||
binding.cancelEditButton.setOnClickListener(a -> {
|
||||
defaultVisibility();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private @NonNull TableRow getTableRow(inputType field) {
|
||||
TableRow tr = new TableRow(getContext());
|
||||
TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
|
||||
rowParams.setMargins(20,20,20,20);
|
||||
tr.setLayoutParams(rowParams);
|
||||
tr.setPadding(20,20,20,20);
|
||||
tr.setBackgroundColor(unfocused_background_color);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText(field.get_type_name());
|
||||
tv.setTextSize(12);
|
||||
tr.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setText(field.name);
|
||||
tv.setTextSize(20);
|
||||
tr.addView(tv);
|
||||
return tr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataReportBinding;
|
||||
|
||||
public class ReportFragment extends Fragment {
|
||||
FragmentDataReportBinding binding;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentDataReportBinding.inflate(inflater, container, false);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_transferValues;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_transferValues;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.google.android.material.divider.MaterialDivider;
|
||||
import com.skydoves.powerspinner.IconSpinnerAdapter;
|
||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
||||
import com.skydoves.powerspinner.PowerSpinnerView;
|
||||
import com.skydoves.powerspinner.SpinnerGravity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TeamsFragment extends Fragment {
|
||||
FragmentDataTeamsBinding binding;
|
||||
|
||||
private static frcTeam team;
|
||||
public static void setTeam(frcTeam tmpteam){
|
||||
team = tmpteam;
|
||||
}
|
||||
|
||||
private static final int background_color = 0x5000ff00;
|
||||
private static final int unsaved_background_color = 0x2000ff00;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentDataTeamsBinding.inflate(inflater, container, false);
|
||||
|
||||
binding.teamsArea.removeAllViews();
|
||||
|
||||
DataManager.reload_match_fields();
|
||||
DataManager.reload_pit_fields();
|
||||
|
||||
TableLayout table = new TableLayout(getContext());
|
||||
table.setStretchAllColumns(true);
|
||||
binding.teamsArea.addView(table);
|
||||
|
||||
loadTeam(latestSettings.settings.get_data_view_mode());
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
public void loadTeam(int mode) {
|
||||
binding.teamsArea.removeAllViews();
|
||||
|
||||
LinearLayout ll = new LinearLayout(getContext());
|
||||
ll.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
ll.setOrientation(LinearLayout.VERTICAL);
|
||||
binding.teamsArea.addView(ll);
|
||||
|
||||
|
||||
|
||||
PowerSpinnerView dropdown = new PowerSpinnerView(getContext());
|
||||
|
||||
List<IconSpinnerItem> iconSpinnerItems = new ArrayList<>();
|
||||
|
||||
iconSpinnerItems.add(new IconSpinnerItem("Individual"));
|
||||
iconSpinnerItems.add(new IconSpinnerItem("Compiled"));
|
||||
iconSpinnerItems.add(new IconSpinnerItem("History"));
|
||||
|
||||
IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown);
|
||||
dropdown.setSpinnerAdapter(iconSpinnerAdapter);
|
||||
dropdown.setItems(iconSpinnerItems);
|
||||
|
||||
dropdown.selectItemByIndex(0);
|
||||
|
||||
dropdown.setPadding(10,20,10,20);
|
||||
dropdown.setBackgroundColor(0xf0000000);
|
||||
dropdown.setTextColor(0xff00ff00);
|
||||
dropdown.setTextSize(15);
|
||||
dropdown.setArrowGravity(SpinnerGravity.END);
|
||||
dropdown.setArrowPadding(8);
|
||||
// dropdown.setSpinnerItemHeight(46);
|
||||
dropdown.setSpinnerPopupElevation(14);
|
||||
|
||||
|
||||
dropdown.selectItemByIndex(mode);
|
||||
|
||||
|
||||
dropdown.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener<IconSpinnerItem>() {
|
||||
@Override
|
||||
public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex,
|
||||
IconSpinnerItem newItem) {
|
||||
|
||||
latestSettings.settings.set_data_view_mode(newIndex);
|
||||
loadTeam(newIndex);
|
||||
}
|
||||
});
|
||||
|
||||
ll.addView(dropdown);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(String.valueOf(team.teamNumber));
|
||||
tv.setTextSize(28);
|
||||
ll.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(team.teamName);
|
||||
tv.setTextSize(28);
|
||||
ll.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(team.getDescription());
|
||||
tv.setTextSize(16);
|
||||
ll.addView(tv);
|
||||
|
||||
add_pit_data(ll, team);
|
||||
add_match_data(ll, team, mode);
|
||||
}
|
||||
|
||||
public void add_pit_data(LinearLayout ll, frcTeam team){
|
||||
final String filename = evcode+"-"+team.teamNumber+".pitscoutdata";
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setPadding(0,10,0,10);
|
||||
tv.setText("----- Pit data -----");
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
if(!fileEditor.fileExist(filename)){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("No pit data has been collected!");
|
||||
tv.setTextSize(23);
|
||||
ll.addView(tv);
|
||||
return;
|
||||
}
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Pit scouting 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(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(psda.data.array[a].getName());
|
||||
tv.setTextSize(25);
|
||||
|
||||
if(psda.data.array[a].isNull()){
|
||||
tv.setBackgroundColor(0xffff0000);
|
||||
tv.setTextColor(0xff000000);
|
||||
}
|
||||
|
||||
|
||||
ll.addView(tv);
|
||||
|
||||
|
||||
pit_latest_values[a].add_individual_view(ll, psda.data.array[a]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_match_data(LinearLayout ll, frcTeam team, int mode){
|
||||
String[] files = fileEditor.getMatchesByTeamNum(evcode, team.teamNumber);
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("----- Match data -----");
|
||||
tv.setPadding(0,10,0,10);
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
|
||||
|
||||
if(files.length == 0){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("No match data has been collected!");
|
||||
tv.setTextSize(23);
|
||||
ll.addView(tv);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mode){
|
||||
case 0:
|
||||
add_individual_views(ll,files);
|
||||
break;
|
||||
case 1:
|
||||
add_compiled_views(ll,files);
|
||||
break;
|
||||
case 2:
|
||||
add_history_views(ll,files);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_individual_views(LinearLayout ll, String[] files) {
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
String[] split = files[i].split("-");
|
||||
int match_num = Integer.parseInt(split[1]);
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
||||
|
||||
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(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(psda.data.array[a].getName());
|
||||
tv.setTextSize(25);
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_compiled_views(LinearLayout ll, String[] files){
|
||||
dataType[][] data = new dataType[match_latest_values.length][files.length];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
||||
for (int a = 0; a < data.length; a++) {
|
||||
data[a][i] = psda.data.array[a];
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < match_latest_values.length; i++){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(match_latest_values[i].name);
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
match_latest_values[i].add_compiled_view(ll, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_history_views(LinearLayout ll, String[] files){
|
||||
dataType[][] data = new dataType[match_latest_values.length][files.length];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[i], match_values, match_transferValues);
|
||||
for (int a = 0; a < data.length; a++) {
|
||||
data[a][i] = psda.data.array[a];
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < match_latest_values.length; i++){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(match_latest_values[i].name);
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
match_latest_values[i].add_history_view(ll, data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
package com.ridgebotics.ridgescout.ui.scouting;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingMatchBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.AutoSaveManager;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class MatchScoutingFragment extends Fragment {
|
||||
|
||||
private FragmentScoutingMatchBinding binding;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentScoutingMatchBinding.inflate(inflater, container, false);
|
||||
|
||||
DataManager.reload_match_fields();
|
||||
|
||||
alliance_position = latestSettings.settings.get_alliance_pos();
|
||||
username = latestSettings.settings.get_username();
|
||||
|
||||
binding.username.setText(username);
|
||||
binding.alliancePosText.setText(alliance_position);
|
||||
|
||||
binding.teamDescription.setVisibility(View.GONE);
|
||||
binding.teamName.setVisibility(View.GONE);
|
||||
clear_fields();
|
||||
binding.teamDescription.setVisibility(View.VISIBLE);
|
||||
binding.teamName.setVisibility(View.VISIBLE);
|
||||
|
||||
if(DataManager.match_values == null || DataManager.match_values.length == 0){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText("Failed to load fields.\nTry to either download or create match scouting fields.");
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
binding.MatchScoutArea.addView(tv);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cur_match_num = latestSettings.settings.get_match_num();
|
||||
update_match_num();
|
||||
|
||||
binding.nextButton.setOnClickListener(v -> {
|
||||
if(edited) save();
|
||||
latestSettings.settings.set_match_num(cur_match_num+1);
|
||||
cur_match_num += 1;
|
||||
update_match_num();
|
||||
update_scouting_data();
|
||||
});
|
||||
|
||||
|
||||
boolean fileIndicatorTapped = false;
|
||||
binding.fileIndicator.setOnClickListener(v -> {
|
||||
// if(e.getAction() != MotionEvent.ACTION_MOVE) return true;
|
||||
// System.out.println(e.getAxisValue(0));
|
||||
if(edited) save();
|
||||
|
||||
alliance_position = incrementMatchPos(alliance_position);
|
||||
latestSettings.settings.set_alliance_pos(alliance_position);
|
||||
binding.alliancePosText.setText(alliance_position);
|
||||
|
||||
update_match_num();
|
||||
update_scouting_data();
|
||||
// return true;
|
||||
});
|
||||
|
||||
binding.backButton.setOnClickListener(v -> {
|
||||
if(edited) save();
|
||||
latestSettings.settings.set_match_num(cur_match_num-1);
|
||||
cur_match_num -= 1;
|
||||
update_match_num();
|
||||
update_scouting_data();
|
||||
});
|
||||
|
||||
// binding.middleButton.setOnClickListener(v -> {
|
||||
// if(edited) save();
|
||||
// });
|
||||
|
||||
create_fields();
|
||||
update_scouting_data();
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private static String incrementMatchPos(String input){
|
||||
switch(input){ // There's probably a better solution than this.
|
||||
case "red-1":
|
||||
return "red-2";
|
||||
case "red-2":
|
||||
return "red-3";
|
||||
case "red-3":
|
||||
return "blue-1";
|
||||
case "blue-1":
|
||||
return "blue-2";
|
||||
case "blue-2":
|
||||
return "blue-3";
|
||||
case "blue-3":
|
||||
return "red-1";
|
||||
}
|
||||
return "red-1";
|
||||
}
|
||||
|
||||
private static final int unsaved_color = 0x60ff0000;
|
||||
private static final int saved_color = 0x6000ff00;
|
||||
|
||||
String alliance_position;
|
||||
int cur_match_num;
|
||||
String username;
|
||||
String filename;
|
||||
|
||||
boolean edited = false;
|
||||
|
||||
TextView[] titles;
|
||||
|
||||
AutoSaveManager asm = new AutoSaveManager(this::save);
|
||||
|
||||
ArrayList<dataType> dataTypes;
|
||||
|
||||
|
||||
|
||||
public void save(){
|
||||
System.out.println("Saved!");
|
||||
edited = false;
|
||||
set_indicator_color(saved_color);
|
||||
AlertManager.toast("Saved " + filename);
|
||||
save_fields();
|
||||
}
|
||||
|
||||
public void set_indicator_color(int color){
|
||||
binding.fileIndicator.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
public void update_asm(){
|
||||
// v.getBackground().setColorFilter(Color.parseColor("#00ff00"), PorterDuff.Mode.DARKEN);
|
||||
edited = true;
|
||||
set_indicator_color(unsaved_color);
|
||||
asm.update();
|
||||
}
|
||||
|
||||
|
||||
public void clear_fields(){
|
||||
int childCount = binding.MatchScoutArea.getChildCount();
|
||||
View[] views = new View[childCount];
|
||||
|
||||
for(int i = 0; i < childCount; i++){
|
||||
views[i] = binding.MatchScoutArea.getChildAt(i);
|
||||
}
|
||||
|
||||
for(int i = 0; i < childCount; i++){
|
||||
if(!views[i].isShown()) continue;
|
||||
binding.MatchScoutArea.removeView(views[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private int default_text_color = 0;
|
||||
|
||||
private void create_fields(){
|
||||
if(asm.isRunning){
|
||||
asm.stop();
|
||||
}
|
||||
|
||||
titles = new TextView[DataManager.match_latest_values.length];
|
||||
|
||||
for(int i = 0 ; i < DataManager.match_latest_values.length; i++) {
|
||||
final TextView tv = new TextView(getContext());
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
tv.setText(DataManager.match_latest_values[i].name);
|
||||
tv.setPadding(8,8,8,8);
|
||||
tv.setTextSize(24);
|
||||
titles[i] = tv;
|
||||
|
||||
default_text_color = tv.getCurrentTextColor();
|
||||
|
||||
final View v = DataManager.match_latest_values[i].createView(getContext(), new Function<dataType, Integer>() {
|
||||
@Override
|
||||
public Integer apply(dataType dataType) {
|
||||
// edited = true;
|
||||
if(asm.isRunning)
|
||||
update_asm();
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
binding.MatchScoutArea.addView(tv);
|
||||
int fi = i;
|
||||
tv.setOnClickListener(p -> {
|
||||
// boolean blank = !latest_values[fi].getViewValue().isNull();
|
||||
|
||||
// System.out.println(blank);
|
||||
if(asm.isRunning)
|
||||
update_asm();
|
||||
|
||||
if(!DataManager.match_latest_values[fi].isBlank){
|
||||
tv.setBackgroundColor(0xffff0000);
|
||||
tv.setTextColor(0xff000000);
|
||||
DataManager.match_latest_values[fi].nullify();
|
||||
}else{
|
||||
tv.setBackgroundColor(0x00000000);
|
||||
tv.setTextColor(default_text_color);
|
||||
DataManager.match_latest_values[fi].setViewValue(DataManager.match_latest_values[fi].default_value);
|
||||
}
|
||||
});
|
||||
|
||||
binding.MatchScoutArea.addView(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void update_match_num(){
|
||||
// cur_match_num = latestSettings.settings.get_match_num();
|
||||
|
||||
edited = false;
|
||||
|
||||
binding.matchnum.setText(String.valueOf(cur_match_num+1));
|
||||
|
||||
if(cur_match_num <= 0){
|
||||
binding.backButton.setVisibility(View.GONE);
|
||||
}else{
|
||||
binding.backButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if(cur_match_num >= event.matches.size()-1){
|
||||
binding.nextButton.setVisibility(View.GONE);
|
||||
}else{
|
||||
binding.nextButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private frcTeam get_team(frcMatch match){
|
||||
|
||||
// Get team number
|
||||
String[] split = alliance_position.split("-");
|
||||
Integer team_num = null;
|
||||
|
||||
switch (split[0]){
|
||||
case "red":
|
||||
team_num = match.redAlliance[Integer.parseInt(split[1])-1];
|
||||
break;
|
||||
case "blue":
|
||||
team_num = match.blueAlliance[Integer.parseInt(split[1])-1];
|
||||
break;
|
||||
}
|
||||
|
||||
binding.barTeamNum.setText(String.valueOf(team_num));
|
||||
|
||||
frcTeam team = null;
|
||||
for(int i=0; i < event.teams.size(); i++){
|
||||
frcTeam tmpteam = event.teams.get(i);
|
||||
if(tmpteam.teamNumber == team_num){
|
||||
team = tmpteam;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
filename = evcode + "-" + (cur_match_num+1) + "-" + alliance_position + "-" + team_num + ".matchscoutdata";
|
||||
|
||||
return team;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void update_scouting_data(){
|
||||
|
||||
frcMatch match = event.matches.get(cur_match_num);
|
||||
frcTeam team = get_team(match);
|
||||
|
||||
binding.teamName.setText(team.teamName);
|
||||
binding.teamDescription.setText(team.getDescription());
|
||||
|
||||
boolean new_file = !fileEditor.fileExist(filename);
|
||||
|
||||
if(asm.isRunning){
|
||||
asm.stop();
|
||||
}
|
||||
|
||||
if(new_file){
|
||||
default_fields();
|
||||
set_indicator_color(unsaved_color);
|
||||
}else{
|
||||
get_fields();
|
||||
set_indicator_color(saved_color);
|
||||
}
|
||||
|
||||
asm.start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void default_fields(){
|
||||
for(int i = 0; i < DataManager.match_latest_values.length; i++){
|
||||
inputType input = DataManager.match_latest_values[i];
|
||||
input.setViewValue(input.default_value);
|
||||
|
||||
titles[i].setBackgroundColor(0x00000000);
|
||||
titles[i].setTextColor(default_text_color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void get_fields(){
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues);
|
||||
dataType[] types = psdr.data.array;
|
||||
|
||||
for(int i = 0; i < DataManager.match_latest_values.length; i++){
|
||||
// types[i] = latest_values[i].getViewValue();
|
||||
try {
|
||||
DataManager.match_latest_values[i].setViewValue(types[i].get());
|
||||
} catch (Exception e){
|
||||
AlertManager.error(e);
|
||||
DataManager.match_latest_values[i].setViewValue(DataManager.match_latest_values[i].default_value);
|
||||
}
|
||||
|
||||
|
||||
if(DataManager.match_latest_values[i].isBlank){
|
||||
titles[i].setBackgroundColor(0xffff0000);
|
||||
titles[i].setTextColor(0xff000000);
|
||||
}else{
|
||||
titles[i].setBackgroundColor(0x00000000);
|
||||
titles[i].setTextColor(default_text_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void save_fields(){
|
||||
|
||||
dataType[] types = new dataType[DataManager.match_latest_values.length];
|
||||
|
||||
for(int i = 0; i < DataManager.match_latest_values.length; i++){
|
||||
types[i] = DataManager.match_latest_values[i].getViewValue();
|
||||
}
|
||||
|
||||
if(ScoutingDataWriter.save(DataManager.match_values.length-1, username, filename, types))
|
||||
System.out.println("Saved!");
|
||||
else
|
||||
System.out.println("Error saving");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package com.ridgebotics.ridgescout.ui.scouting;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_transferValues;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.utility.AutoSaveManager;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PitScoutingFragment extends Fragment {
|
||||
|
||||
FragmentScoutingPitBinding binding;
|
||||
|
||||
private static frcTeam team;
|
||||
public static void setTeam(frcTeam tmpteam){
|
||||
team = tmpteam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentScoutingPitBinding.inflate(inflater, container, false);
|
||||
|
||||
username = latestSettings.settings.get_username();
|
||||
DataManager.reload_pit_fields();
|
||||
|
||||
loadTeam();
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
private static final int unsaved_color = 0x60ff0000;
|
||||
private static final int saved_color = 0x6000ff00;
|
||||
|
||||
boolean edited = false;
|
||||
|
||||
String filename;
|
||||
String username;
|
||||
|
||||
TextView[] titles;
|
||||
|
||||
AutoSaveManager asm = new AutoSaveManager(this::save);
|
||||
|
||||
ArrayList<dataType> dataTypes;
|
||||
|
||||
public void save(){
|
||||
edited = false;
|
||||
set_indicator_color(saved_color);
|
||||
|
||||
dataType[] types = new dataType[pit_latest_values.length];
|
||||
|
||||
for(int i = 0; i < pit_latest_values.length; i++){
|
||||
types[i] = pit_latest_values[i].getViewValue();
|
||||
}
|
||||
|
||||
if(ScoutingDataWriter.save(pit_values.length-1, username, filename, types))
|
||||
System.out.println("Saved!");
|
||||
else
|
||||
System.out.println("Error saving");
|
||||
}
|
||||
|
||||
public void set_indicator_color(int color){
|
||||
binding.pitFileIndicator.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
public void update_asm(){
|
||||
// v.getBackground().setColorFilter(Color.parseColor("#00ff00"), PorterDuff.Mode.DARKEN);
|
||||
edited = true;
|
||||
set_indicator_color(unsaved_color);
|
||||
asm.update();
|
||||
}
|
||||
|
||||
|
||||
// public void init(frcEvent event){
|
||||
//
|
||||
// evcode = event.eventCode;
|
||||
// this.event = event;
|
||||
// username = latestSettings.settings.get_username();
|
||||
//
|
||||
//// binding.eventcode.setText(evcode);
|
||||
//
|
||||
// binding.pitBackButton.setOnClickListener(view -> {
|
||||
// if(edited) save();
|
||||
// binding.pitTeamName.setVisibility(View.GONE);
|
||||
// binding.pitTeamDescription.setVisibility(View.GONE);
|
||||
// clear_fields();
|
||||
// load_teams();
|
||||
// });
|
||||
//
|
||||
// values = fields.load(fields.pitsFieldsFilename);
|
||||
//
|
||||
// if(values == null || values.length == 0){
|
||||
// TextView tv = new TextView(getContext());
|
||||
// tv.setText("Failed to load fields.\nTry to either download or create pit scouting fields.");
|
||||
// tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
// binding.pitScoutArea.addView(tv);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// latest_values = values[values.length-1];
|
||||
// transferValues = transferType.get_transfer_values(values);
|
||||
// }
|
||||
//
|
||||
// public void clear_fields(){
|
||||
// int childCount = binding.pitScoutArea.getChildCount();
|
||||
// View[] views = new View[childCount];
|
||||
//
|
||||
// for(int i = 0; i < childCount; i++){
|
||||
// views[i] = binding.pitScoutArea.getChildAt(i);
|
||||
// }
|
||||
//
|
||||
// for(int i = 0; i < childCount; i++){
|
||||
// if(!views[i].isShown()) continue;
|
||||
// binding.pitScoutArea.removeView(views[i]);
|
||||
// }
|
||||
// }
|
||||
|
||||
public void loadTeam(){
|
||||
// clear_fields();
|
||||
|
||||
binding.pitFileIndicator.setVisibility(View.VISIBLE);
|
||||
binding.pitTeamName.setVisibility(View.VISIBLE);
|
||||
binding.pitTeamDescription.setVisibility(View.VISIBLE);
|
||||
|
||||
binding.pitTeamName.setText(team.teamName);
|
||||
binding.pitTeamDescription.setText(team.getDescription());
|
||||
binding.pitBarTeamNum.setText(String.valueOf(team.teamNumber));
|
||||
|
||||
// binding.teamName.setText(team.teamName);
|
||||
// binding.teamDescription.setText(team.getDescription());
|
||||
|
||||
filename = evcode + "-" + team.teamNumber + ".pitscoutdata";
|
||||
|
||||
boolean new_file = !fileEditor.fileExist(filename);
|
||||
|
||||
if(asm.isRunning){
|
||||
asm.stop();
|
||||
}
|
||||
|
||||
create_fields();
|
||||
|
||||
if(new_file){
|
||||
default_fields();
|
||||
set_indicator_color(unsaved_color);
|
||||
}else{
|
||||
get_fields();
|
||||
set_indicator_color(saved_color);
|
||||
}
|
||||
|
||||
asm.start();
|
||||
|
||||
}
|
||||
|
||||
private int default_text_color = 0;
|
||||
|
||||
|
||||
private void create_fields() {
|
||||
if(asm.isRunning){
|
||||
asm.stop();
|
||||
}
|
||||
|
||||
titles = new TextView[pit_latest_values.length];
|
||||
|
||||
for(int i = 0 ; i < pit_latest_values.length; i++) {
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
tv.setText(pit_latest_values[i].name);
|
||||
tv.setTextSize(24);
|
||||
tv.setPadding(8,8,8,8);
|
||||
titles[i] = tv;
|
||||
binding.pitScoutArea.addView(tv);
|
||||
|
||||
default_text_color = tv.getCurrentTextColor();
|
||||
|
||||
int fi = i;
|
||||
tv.setOnClickListener(p -> {
|
||||
// boolean blank = !latest_values[fi].getViewValue().isNull();
|
||||
|
||||
// System.out.println(blank);
|
||||
|
||||
asm.update();
|
||||
|
||||
if(!pit_latest_values[fi].isBlank){
|
||||
tv.setBackgroundColor(0xffff0000);
|
||||
tv.setTextColor(0xff000000);
|
||||
pit_latest_values[fi].nullify();
|
||||
}else{
|
||||
tv.setBackgroundColor(0x00000000);
|
||||
tv.setTextColor(default_text_color);
|
||||
pit_latest_values[fi].setViewValue(pit_latest_values[fi].default_value);
|
||||
}
|
||||
});
|
||||
|
||||
View v = pit_latest_values[i].createView(getContext(), new Function<dataType, Integer>() {
|
||||
@Override
|
||||
public Integer apply(dataType dataType) {
|
||||
// edited = true;
|
||||
if(asm.isRunning)
|
||||
update_asm();
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
binding.pitScoutArea.addView(v);
|
||||
}
|
||||
}
|
||||
|
||||
public void default_fields(){
|
||||
for(int i = 0; i < pit_latest_values.length; i++){
|
||||
inputType input = pit_latest_values[i];
|
||||
input.setViewValue(input.default_value);
|
||||
|
||||
titles[i].setBackgroundColor(0x00000000);
|
||||
titles[i].setTextColor(default_text_color);
|
||||
}
|
||||
}
|
||||
|
||||
public void get_fields(){
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||
dataType[] types = psdr.data.array;
|
||||
|
||||
for(int i = 0; i < pit_latest_values.length; i++){
|
||||
// types[i] = latest_values[i].getViewValue();
|
||||
pit_latest_values[i].setViewValue(types[i]);
|
||||
|
||||
if(pit_latest_values[i].isBlank){
|
||||
titles[i].setBackgroundColor(0xffff0000);
|
||||
titles[i].setTextColor(0xff000000);
|
||||
}else{
|
||||
titles[i].setBackgroundColor(0x00000000);
|
||||
titles[i].setTextColor(default_text_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.ridgebotics.ridgescout.ui.scouting;
|
||||
|
||||
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingBinding;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.ui.TeamSelectorFragment;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
|
||||
public class ScoutingFragment extends Fragment {
|
||||
|
||||
private FragmentScoutingBinding binding;
|
||||
private boolean is_main_page = true;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentScoutingBinding.inflate(inflater, container, false);
|
||||
|
||||
binding.buttons.setVisibility(View.VISIBLE);
|
||||
|
||||
String evcode = latestSettings.settings.get_evcode();
|
||||
|
||||
if(evcode.equals("unset")){
|
||||
binding.noEventError.setVisibility(View.VISIBLE);
|
||||
binding.matchScoutingButton.setEnabled(false);
|
||||
binding.pitScoutingButton.setEnabled(false);
|
||||
binding.statusButton.setEnabled(false);
|
||||
is_main_page = false;
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
DataManager.reload_event();
|
||||
|
||||
if(event.matches.isEmpty())
|
||||
binding.matchScoutingButton.setVisibility(View.GONE);
|
||||
|
||||
binding.matchScoutingButton.setOnClickListener(v -> {
|
||||
findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_match_scouting);
|
||||
});
|
||||
|
||||
binding.pitScoutingButton.setOnClickListener(v -> {
|
||||
TeamSelectorFragment.setPits_mode(true);
|
||||
TeamSelectorFragment.setOnSelect(new TeamSelectorFragment.onTeamSelected() {
|
||||
@Override
|
||||
public void onSelect(TeamSelectorFragment self, frcTeam team) {
|
||||
PitScoutingFragment.setTeam(team);
|
||||
findNavController(self).navigate(R.id.action_navigation_team_selector_to_navigation_pit_scouting);
|
||||
}
|
||||
});
|
||||
findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_team_selector);
|
||||
});
|
||||
|
||||
binding.statusButton.setOnClickListener(v -> {
|
||||
findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_scouting_status);
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if(getView() == null){
|
||||
return;
|
||||
}
|
||||
|
||||
getView().setFocusableInTouchMode(true);
|
||||
getView().requestFocus();
|
||||
getView().setOnKeyListener(new View.OnKeyListener() {
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
|
||||
if (event.getAction() == KeyEvent.ACTION_UP
|
||||
&& keyCode == KeyEvent.KEYCODE_BACK
|
||||
&& !is_main_page){
|
||||
|
||||
// binding.buttons.setVisibility(View.VISIBLE);
|
||||
// binding.matchScoutingView.setVisibility(View.GONE);
|
||||
// binding.pitScoutingView.setVisibility(View.GONE);
|
||||
is_main_page = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.ridgebotics.ridgescout.ui.scouting;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingStatusBinding;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class StatusFragment extends Fragment {
|
||||
FragmentScoutingStatusBinding binding;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentScoutingStatusBinding.inflate(inflater, container, false);
|
||||
|
||||
DataManager.reload_event();
|
||||
binding.matchTable.removeAllViews();
|
||||
binding.matchTable.setStretchAllColumns(true);
|
||||
add_pit_scouting(event);
|
||||
add_match_scouting(event);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
public static int color_found = 0x7f00ff00;
|
||||
public static int color_not_found = 0x7f7f0000;
|
||||
private void addTableText(TableRow tr, String textStr){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
text.setText(textStr);
|
||||
tr.addView(text);
|
||||
}
|
||||
|
||||
public void add_pit_scouting(frcEvent event){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Pit Scouting");
|
||||
tv.setTextSize(28);
|
||||
binding.matchTable.addView(tv);
|
||||
|
||||
int[] teams = new int[event.teams.size()];
|
||||
|
||||
for(int i = 0 ; i < event.teams.size(); i++){
|
||||
teams[i] = event.teams.get(i).teamNumber;
|
||||
}
|
||||
|
||||
Arrays.sort(teams);
|
||||
|
||||
TableRow tr = null;
|
||||
for(int i=0; i < event.teams.size(); i++){
|
||||
// frcTeam team = event.teams.get(i);
|
||||
int num = teams[i];
|
||||
|
||||
if(i % 7 == 0){
|
||||
if(i != 0)
|
||||
binding.matchTable.addView(tr);
|
||||
tr = new TableRow(getContext());
|
||||
}
|
||||
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
|
||||
text.setText(String.valueOf(num));
|
||||
if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){
|
||||
text.setBackgroundColor(color_found);
|
||||
}else{
|
||||
text.setBackgroundColor(color_not_found);
|
||||
}
|
||||
tr.addView(text);
|
||||
}
|
||||
if(tr != null)
|
||||
binding.matchTable.addView(tr);
|
||||
}
|
||||
|
||||
|
||||
public void add_match_scouting(frcEvent event){
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Match Scouting");
|
||||
tv.setTextSize(28);
|
||||
binding.matchTable.addView(tv);
|
||||
|
||||
TableRow tr = new TableRow(getContext());
|
||||
addTableText(tr, "#");
|
||||
addTableText(tr, "Red-1");
|
||||
addTableText(tr, "Red-2");
|
||||
addTableText(tr, "Red-3");
|
||||
addTableText(tr, "Blue-1");
|
||||
addTableText(tr, "Blue-2");
|
||||
addTableText(tr, "Blue-3");
|
||||
binding.matchTable.addView(tr);
|
||||
|
||||
for(frcMatch match : event.matches){
|
||||
|
||||
tr = new TableRow(getContext());
|
||||
addTableText(tr, String.valueOf(match.matchIndex));
|
||||
//
|
||||
for(int i=0;i<6;i++){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
|
||||
int team_num;
|
||||
String alliance_position;
|
||||
|
||||
if(i < 3){
|
||||
team_num = match.redAlliance[i];
|
||||
alliance_position = "red-"+(i+1);
|
||||
}else{
|
||||
team_num = match.blueAlliance[i-3];
|
||||
alliance_position = "blue-"+(i-2);
|
||||
}
|
||||
|
||||
text.setText(String.valueOf(team_num));
|
||||
if(fileEditor.fileExist(event.eventCode + "-" + match.matchIndex + "-" + alliance_position + "-" + team_num + ".matchscoutdata")){
|
||||
text.setBackgroundColor(color_found);
|
||||
}else{
|
||||
text.setBackgroundColor(color_not_found);
|
||||
}
|
||||
tr.addView(text);
|
||||
}
|
||||
|
||||
// addTableText(tr, String.valueOf(match.matchIndex));
|
||||
// addTableText(tr, String.valueOf(match.blueAlliance[0]));
|
||||
// addTableText(tr, String.valueOf(match.blueAlliance[1]));
|
||||
// addTableText(tr, String.valueOf(match.blueAlliance[2]));
|
||||
// addTableText(tr, String.valueOf(match.redAlliance[0]));
|
||||
// addTableText(tr, String.valueOf(match.redAlliance[1]));
|
||||
// addTableText(tr, String.valueOf(match.redAlliance[2]));
|
||||
// if (toggle) {
|
||||
// tr.setBackgroundColor(0x30000000);
|
||||
// }
|
||||
//
|
||||
// toggle = !toggle;
|
||||
binding.matchTable.addView(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.ridgebotics.ridgescout.ui.scouting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
|
||||
public class TallyCounterView extends LinearLayout {
|
||||
private int count = 0;
|
||||
private TextView countDisplay;
|
||||
private Button minusButton;
|
||||
private Button plusButton;
|
||||
private OnCountChangedListener onCountChangedListener;
|
||||
|
||||
public interface OnCountChangedListener {
|
||||
void onCountChanged(int newCount);
|
||||
}
|
||||
|
||||
public TallyCounterView(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public TallyCounterView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public TallyCounterView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.view_tally_counter, this, true);
|
||||
|
||||
countDisplay = findViewById(R.id.count_display);
|
||||
minusButton = findViewById(R.id.minus_button);
|
||||
plusButton = findViewById(R.id.plus_button);
|
||||
|
||||
updateDisplay();
|
||||
|
||||
minusButton.setOnClickListener(v -> {
|
||||
if(count > 0) {
|
||||
count--;
|
||||
updateDisplay();
|
||||
}
|
||||
});
|
||||
|
||||
plusButton.setOnClickListener(v -> {
|
||||
count++;
|
||||
updateDisplay();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateDisplay() {
|
||||
countDisplay.setText(String.valueOf(count));
|
||||
if (onCountChangedListener != null) {
|
||||
onCountChangedListener.onCountChanged(count);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
count = value;
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setOnCountChangedListener(OnCountChangedListener listener) {
|
||||
this.onCountChangedListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
package com.ridgebotics.ridgescout.ui.settings;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentSettingsBinding;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
|
||||
import com.skydoves.powerspinner.IconSpinnerAdapter;
|
||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
||||
import com.skydoves.powerspinner.PowerSpinnerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class settingsFragment extends Fragment {
|
||||
private FragmentSettingsBinding binding;
|
||||
private android.widget.ScrollView ScrollArea;
|
||||
private android.widget.TableLayout Table;
|
||||
|
||||
private void setDropdownItems(Spinner dropdown, String[] items){
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_spinner_item, items);
|
||||
dropdown.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentSettingsBinding.inflate(inflater, container, false);
|
||||
View root = binding.getRoot();
|
||||
|
||||
EditText username = binding.username;
|
||||
username.setText(latestSettings.settings.get_username());
|
||||
username.addTextChangedListener(new TextWatcher() {
|
||||
|
||||
public void afterTextChanged(Editable s) {
|
||||
latestSettings.settings.set_username(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 = latestSettings.settings.get_evcode();
|
||||
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) {
|
||||
latestSettings.settings.set_evcode(newItem.getText().toString());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
PowerSpinnerView alliance_pos_spinnerView = binding.alliancePosDropdown;
|
||||
|
||||
List<IconSpinnerItem> alliance_pos_iconSpinnerItems = new ArrayList<>();
|
||||
|
||||
String target_alliance_pos = latestSettings.settings.get_alliance_pos();
|
||||
int alliance_pos_target_index = -1;
|
||||
|
||||
String[] alliance_pos_list = new String[]{"red-1", "red-2", "red-3",
|
||||
"blue-1", "blue-2", "blue-3"};
|
||||
|
||||
for(int i = 0; i < alliance_pos_list.length; i++){
|
||||
if(alliance_pos_list[i].equals(target_alliance_pos)){
|
||||
alliance_pos_target_index = i;
|
||||
}
|
||||
alliance_pos_iconSpinnerItems.add(new IconSpinnerItem(alliance_pos_list[i]));
|
||||
}
|
||||
|
||||
IconSpinnerAdapter alliance_pos_iconSpinnerAdapter = new IconSpinnerAdapter(alliance_pos_spinnerView);
|
||||
alliance_pos_spinnerView.setSpinnerAdapter(alliance_pos_iconSpinnerAdapter);
|
||||
alliance_pos_spinnerView.setItems(alliance_pos_iconSpinnerItems);
|
||||
alliance_pos_spinnerView.setLifecycleOwner(this);
|
||||
|
||||
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) {
|
||||
latestSettings.settings.set_alliance_pos(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(latestSettings.settings.get_team_num()));
|
||||
team_num.addTextChangedListener(new TextWatcher() {
|
||||
|
||||
public void afterTextChanged(Editable s) {
|
||||
latestSettings.settings.set_team_num(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) {
|
||||
latestSettings.settings.set_wifi_mode(isChecked);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
wifi_mode.setChecked(latestSettings.settings.get_wifi_mode());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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) -> {
|
||||
latestSettings.settings.defaultSettings();
|
||||
username.setText(latestSettings.settings.get_username());
|
||||
spinnerView.clearSelectedItem();
|
||||
// practice_mode.setChecked(latestSettings.settings.get_practice_mode());
|
||||
wifi_mode.setChecked(latestSettings.settings.get_wifi_mode());
|
||||
alliance_pos_spinnerView.selectItemByIndex(0);
|
||||
team_num.setText(String.valueOf(latestSettings.settings.get_team_num()));
|
||||
});
|
||||
|
||||
alert.setNegativeButton("Cancel", null);
|
||||
alert.create().show();
|
||||
}
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.SharePrompt.shareContent;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.ridgebotics.ridgescout.MainActivity;
|
||||
import com.ridgebotics.ridgescout.types.file;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.SharePrompt;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FileBundle {
|
||||
private static final Intent FILE_SELECT_CODE = new Intent();
|
||||
|
||||
public static void send(String[] files, Context c){
|
||||
try {
|
||||
ByteBuilder b = new ByteBuilder();
|
||||
|
||||
for(int i = 0; i < files.length; i++){
|
||||
if(!fileEditor.fileExist(files[i])) continue;
|
||||
// byte[] data = fileEditor.readFile(files[i]);
|
||||
file f = new file(files[i]);
|
||||
b.addRaw(file.typecode, f.encode());
|
||||
}
|
||||
|
||||
byte[] data = b.build();
|
||||
send(data, c);
|
||||
|
||||
} catch (ByteBuilder.buildingException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void send(byte[] data, Context c){
|
||||
String filename = DataManager.getevcode() + "-" + System.currentTimeMillis() + ".scoutbundle";
|
||||
SharePrompt.shareContent(c, filename, data, "application/ridgescout");
|
||||
}
|
||||
|
||||
|
||||
public static void receive(Activity b){
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("*/*");
|
||||
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||
|
||||
MainActivity.setResultRelay(new MainActivity.activityResultRelay() {
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Uri uri = data.getData();
|
||||
if(uri == null) return;
|
||||
|
||||
try (InputStream is = b.getContentResolver().openInputStream(uri)) {
|
||||
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
|
||||
int bufferSize = 1024;
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
int len = 0;
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
byteBuffer.write(buffer, 0, len);
|
||||
}
|
||||
byte[] bytes = byteBuffer.toByteArray();
|
||||
saveFiles(bytes);
|
||||
// AlertManager.error(""+(bytes.length));
|
||||
} catch (IOException e) {
|
||||
// Handle the exception
|
||||
}
|
||||
}
|
||||
});
|
||||
b.startActivityForResult(intent, 1);
|
||||
}
|
||||
|
||||
|
||||
private static void saveFiles(byte[] data){
|
||||
BuiltByteParser bbp = new BuiltByteParser(data);
|
||||
try{
|
||||
List<BuiltByteParser.parsedObject> parsedObjectList = bbp.parse();
|
||||
|
||||
ArrayList<String> filenames = new ArrayList<>();
|
||||
|
||||
for(int i = 0; i < parsedObjectList.size(); i++){
|
||||
BuiltByteParser.parsedObject pa = parsedObjectList.get(i);
|
||||
if(pa.getType() != file.typecode) continue;
|
||||
file f = file.decode((byte[]) pa.get());
|
||||
if(f == null) continue;
|
||||
filenames.add(f.filename);
|
||||
fileEditor.writeFile(f.filename, f.data);
|
||||
}
|
||||
|
||||
AlertManager.alert("Saved",
|
||||
String.join("\n", filenames));
|
||||
|
||||
}catch (BuiltByteParser.byteParsingExeption e){
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferFileSelectorBinding;
|
||||
import com.ridgebotics.ridgescout.types.file;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FileSelectorFragment extends Fragment {
|
||||
private static final int background_color = 0x5000ff00;
|
||||
private static final int unselected_background_color = 0x2000ff00;
|
||||
|
||||
private static on_file_select onSelect = files -> {};
|
||||
|
||||
public static void setOnSelect(on_file_select tmp){onSelect = tmp;}
|
||||
|
||||
public interface on_file_select {
|
||||
void onSelect(byte[] data);
|
||||
}
|
||||
|
||||
FragmentTransferFileSelectorBinding binding;
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentTransferFileSelectorBinding.inflate(inflater, container, false);
|
||||
|
||||
|
||||
meta_string_array = new String[]{
|
||||
"matches.fields",
|
||||
"pits.fields",
|
||||
evcode+".eventdata"
|
||||
};
|
||||
|
||||
String[] files = fileEditor.getEventFiles(evcode);
|
||||
|
||||
Boolean[] selected_arr = new Boolean[files.length];
|
||||
Arrays.fill(selected_arr, Boolean.TRUE);
|
||||
|
||||
for(int i = 0; i < files.length; i++){
|
||||
TableRow tr = new TableRow(getContext());
|
||||
TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
rowParams.setMargins(20,20,20,20);
|
||||
tr.setLayoutParams(rowParams);
|
||||
tr.setPadding(20,20,20,20);
|
||||
binding.fileSelectorTable.addView(tr);
|
||||
|
||||
tr.setBackgroundColor(background_color);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText(String.valueOf(files[i]));
|
||||
tv.setTextSize(20);
|
||||
tr.addView(tv);
|
||||
|
||||
final int fi = i;
|
||||
tr.setOnClickListener(view -> {
|
||||
boolean sel = !selected_arr[fi];
|
||||
selected_arr[fi] = sel;
|
||||
|
||||
tr.setBackgroundColor(sel ? background_color : unselected_background_color);
|
||||
});
|
||||
}
|
||||
|
||||
binding.fileSelectorSearchbar.setOnKeyListener((view, a, keyEvent) -> {
|
||||
|
||||
String search_param = binding.fileSelectorSearchbar.getText().toString();
|
||||
List<Integer> match_num_nums = get_matches_from_search_params(search_param);
|
||||
|
||||
Arrays.fill(selected_arr, Boolean.TRUE);
|
||||
|
||||
for(int i = 0; i < files.length; i++){
|
||||
View child = binding.fileSelectorTable.getChildAt(i);
|
||||
child.setBackgroundColor(background_color);
|
||||
child.setVisibility(is_in_search_param(files[i], search_param, match_num_nums) ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
binding.fileSelectorButton.setText("Send");
|
||||
binding.fileSelectorButton.setOnClickListener(view -> {
|
||||
List<String> filenames = new ArrayList<>();
|
||||
for(int i = 0; i < files.length; i++){
|
||||
View child = binding.fileSelectorTable.getChildAt(i);
|
||||
if(child.getVisibility() == View.VISIBLE && selected_arr[i])
|
||||
filenames.add(files[i]);
|
||||
}
|
||||
onSelect.onSelect(get_bytes_of_filenames(filenames));
|
||||
});
|
||||
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String[] meta_string_array;
|
||||
|
||||
private boolean is_in_search_param(String filename, String search_param, List<Integer> nums){
|
||||
return
|
||||
("meta".contains(search_param) && Arrays.asList(meta_string_array).contains(filename)) ||
|
||||
filename.contains(search_param) ||
|
||||
match_file_is_match_num(filename, nums);
|
||||
}
|
||||
|
||||
|
||||
private boolean match_file_is_match_num(String filename, List<Integer> nums){
|
||||
if(!filename.endsWith(".matchscoutdata")) return false;
|
||||
String[] dash_split = filename.split("-");
|
||||
if(dash_split.length != 5) return false;
|
||||
String s = dash_split[1];
|
||||
if(!is_int(s)) return false;
|
||||
int n = Integer.parseInt(s);
|
||||
return nums.contains(n);
|
||||
}
|
||||
|
||||
private List<Integer> get_matches_from_search_params(String search_param){
|
||||
List<Integer> nums = new ArrayList<>();
|
||||
String[] comma_split = search_param.split(",");
|
||||
|
||||
for(int i = 0; i < comma_split.length; i++){
|
||||
if(comma_split[i].contains("-")){
|
||||
|
||||
String[] dash_split = comma_split[i].split("-");
|
||||
if(dash_split.length != 2) continue;
|
||||
String stra = dash_split[0];
|
||||
String strb = dash_split[1];
|
||||
|
||||
if(!(is_int(stra) && is_int(strb))) continue;
|
||||
|
||||
int a = Integer.parseUnsignedInt(stra);
|
||||
int b = Integer.parseUnsignedInt(strb);
|
||||
|
||||
for(int x = a; x <= b; x++)
|
||||
nums.add(x);
|
||||
} else if(is_int(comma_split[i]))
|
||||
nums.add(Integer.parseUnsignedInt(comma_split[i]));
|
||||
}
|
||||
|
||||
return nums;
|
||||
}
|
||||
|
||||
private boolean is_int(String num){
|
||||
try {
|
||||
Integer.parseUnsignedInt(num);
|
||||
return true;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static byte[] get_bytes_of_filenames(List<String> filenames){
|
||||
try {
|
||||
ByteBuilder b = new ByteBuilder();
|
||||
|
||||
for(int i = 0; i < filenames.size(); i++){
|
||||
file f = new file(filenames.get(i));
|
||||
b.addRaw(file.typecode, f.encode());
|
||||
}
|
||||
|
||||
return b.build();
|
||||
} catch (ByteBuilder.buildingException e){
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferTbaBinding;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.RequestTask;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.JSONUtil;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
||||
public class TBAFragment extends Fragment {
|
||||
private final String TBAAddress = "https://www.thebluealliance.com/api/v3/";
|
||||
private final String TBAHeader = "X-TBA-Auth-Key: tjEKSZojAU2pgbs2mBt06SKyOakVhLutj3NwuxLTxPKQPLih11aCIwRIVFXKzY4e";
|
||||
|
||||
private android.widget.TableLayout Table;
|
||||
private FragmentTransferTbaBinding binding;
|
||||
|
||||
private static final int year = 2024;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentTransferTbaBinding.inflate(inflater, container, false);
|
||||
|
||||
Table = binding.matchTable;
|
||||
|
||||
Table.setStretchAllColumns(true);
|
||||
|
||||
TableRow tr = new TableRow(getContext());
|
||||
addTableText(tr, "Loading Events...");
|
||||
Table.addView(tr);
|
||||
|
||||
final RequestTask rq = new RequestTask();
|
||||
rq.onResult(s -> {
|
||||
eventTable(s);
|
||||
return null;
|
||||
});
|
||||
rq.execute(TBAAddress + "events/"+year, TBAHeader);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void addTableText(TableRow tr, String textStr){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
text.setText(textStr);
|
||||
tr.addView(text);
|
||||
}
|
||||
|
||||
public void eventTable(String dataString){
|
||||
Table.removeAllViews();
|
||||
Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
Date currentTime = Calendar.getInstance().getTime();
|
||||
|
||||
try {
|
||||
JSONArray data = new JSONArray(dataString);
|
||||
|
||||
Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
boolean toggle = false;
|
||||
|
||||
for(int i=0;i<data.length();i++){
|
||||
TableRow tr = new TableRow(getContext());
|
||||
TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
TableRow.LayoutParams.WRAP_CONTENT,
|
||||
TableRow.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
rowParams.setMargins(20,20,20,20);
|
||||
tr.setLayoutParams(rowParams);
|
||||
tr.setPadding(20,20,20,20);
|
||||
tr.setBackgroundColor(0x30000000);
|
||||
|
||||
|
||||
JSONObject j = data.getJSONObject(i);
|
||||
|
||||
String matchKey = j.getString("key");
|
||||
String name = j.getString("short_name");
|
||||
|
||||
// Sometimes, a short name is not present on TBA Events
|
||||
if(name.isEmpty()){
|
||||
name = j.getString("name");
|
||||
}
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setGravity(Gravity.CENTER_VERTICAL);
|
||||
tv.setTextSize(12);
|
||||
tv.setText(j.getString("key"));
|
||||
tr.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setTextSize(18);
|
||||
tv.setText(name);
|
||||
tr.addView(tv);
|
||||
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
try {
|
||||
Date startDate = format.parse(j.getString("start_date"));
|
||||
Date endDate = format.parse(j.getString("end_date"));
|
||||
if(currentTime.after(endDate)){
|
||||
tr.setBackgroundColor(0x30FF0000);
|
||||
}else if(currentTime.before(startDate)){
|
||||
tr.setBackgroundColor(0x3000FF00);
|
||||
}else if(currentTime.after(startDate) && currentTime.before(endDate)){
|
||||
tr.setBackgroundColor(0x30FFFF00);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
|
||||
|
||||
tr.setOnClickListener(v -> {
|
||||
Table.removeAllViews();
|
||||
Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
TableRow tr1 = new TableRow(getContext());
|
||||
addTableText(tr1, "Downloading Teams...");
|
||||
Table.addView(tr1);
|
||||
|
||||
final RequestTask rq = new RequestTask();
|
||||
rq.onResult(teamsStr -> {
|
||||
TableRow tr11 = new TableRow(getContext());
|
||||
addTableText(tr11, "Downloading Matches...");
|
||||
Table.addView(tr11);
|
||||
|
||||
final RequestTask rq1 = new RequestTask();
|
||||
rq1.onResult(matchesStr -> {
|
||||
matchTable(matchesStr, teamsStr, j);
|
||||
return null;
|
||||
});
|
||||
rq1.execute((TBAAddress + "event/" + matchKey + "/matches"), TBAHeader);
|
||||
return null;
|
||||
});
|
||||
rq.execute((TBAAddress + "event/" + matchKey + "/teams"), TBAHeader);
|
||||
});
|
||||
|
||||
// tr.addView(cl);
|
||||
Table.addView(tr, rowParams);
|
||||
|
||||
toggle = !toggle;
|
||||
}
|
||||
}catch (JSONException j){
|
||||
AlertManager.alert("Error", "Invalid JSON");
|
||||
}
|
||||
}
|
||||
|
||||
static class matchComparator implements Comparator<JSONObject>
|
||||
{
|
||||
|
||||
public int compare(JSONObject a, JSONObject b)
|
||||
{
|
||||
try {
|
||||
return a.getInt("match_number") - b.getInt("match_number");
|
||||
}catch (JSONException j){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void matchTable(String matchesString, String teamsString, JSONObject eventData){
|
||||
Table.removeAllViews();
|
||||
Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
try {
|
||||
final JSONArray matchData = new JSONArray(matchesString);
|
||||
// final JSONArray matchData = new JSONArray();
|
||||
final JSONArray teamData = new JSONArray(teamsString);
|
||||
|
||||
String matchKey = eventData.getString("key");
|
||||
String matchName = eventData.getString("short_name");
|
||||
|
||||
// Sometimes, a short name is not present on TBA Events
|
||||
if(matchName.isEmpty()){
|
||||
matchName = eventData.getString("name");
|
||||
}
|
||||
|
||||
// Event code at top
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setText(matchKey);
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
|
||||
// Event Name
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(matchName);
|
||||
tv.setTextSize(28);
|
||||
Table.addView(tv);
|
||||
|
||||
|
||||
|
||||
// Save button
|
||||
Button btn = new Button(getContext());
|
||||
btn.setText("Save");
|
||||
btn.setTextSize(18);
|
||||
btn.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
Table.addView(btn);
|
||||
|
||||
|
||||
|
||||
|
||||
if(teamData.length() == 0){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("This event has no teams released yet...");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("This event has no teams released yet...");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
|
||||
btn.setVisibility(View.GONE);
|
||||
return;
|
||||
}else if(matchData.length() == 0){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("This event has no matches released yet...");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Try manually adding practice matches.");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Teams");
|
||||
tv.setTextSize(28);
|
||||
Table.addView(tv);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int[] teams = new int[teamData.length()];
|
||||
|
||||
for(int i = 0 ; i < teamData.length(); i++){
|
||||
teams[i] = teamData.getJSONObject(i).getInt("team_number");
|
||||
}
|
||||
|
||||
Arrays.sort(teams);
|
||||
|
||||
TableRow tr = null;
|
||||
for(int i=0; i < teamData.length(); i++){
|
||||
// frcTeam team = event.teams.get(i);
|
||||
int num = teams[i];
|
||||
|
||||
if(i % 7 == 0){
|
||||
if(i != 0)
|
||||
Table.addView(tr);
|
||||
tr = new TableRow(getContext());
|
||||
}
|
||||
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
|
||||
text.setText(String.valueOf(num));
|
||||
// if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){
|
||||
// text.setBackgroundColor(0x3000FF00);
|
||||
// }else{
|
||||
// text.setBackgroundColor(0x30FF0000);
|
||||
// }
|
||||
tr.addView(text);
|
||||
}
|
||||
if(tr != null)
|
||||
Table.addView(tr);
|
||||
|
||||
final ArrayList<frcMatch> matchesOBJ = new ArrayList<>();
|
||||
|
||||
btn.setOnClickListener(v -> {
|
||||
if(saveData(matchesOBJ, teamData, eventData)){
|
||||
AlertManager.alert("Info", "Saved!");
|
||||
}else{
|
||||
AlertManager.alert("Error", "Error saving files.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Matches");
|
||||
tv.setTextSize(28);
|
||||
Table.addView(tv);
|
||||
|
||||
|
||||
|
||||
|
||||
tr = new TableRow(getContext());
|
||||
addTableText(tr, "#");
|
||||
addTableText(tr, "Red-1");
|
||||
addTableText(tr, "Red-2");
|
||||
addTableText(tr, "Red-3");
|
||||
addTableText(tr, "Blue-1");
|
||||
addTableText(tr, "Blue-2");
|
||||
addTableText(tr, "Blue-3");
|
||||
Table.addView(tr);
|
||||
|
||||
|
||||
if(matchData.length() == 0)
|
||||
return;
|
||||
|
||||
|
||||
final JSONArray sortedMatchData = JSONUtil.sort(matchData, (a, b) -> {
|
||||
JSONObject ja = (JSONObject)a;
|
||||
JSONObject jb = (JSONObject)b;
|
||||
try {
|
||||
return ja.getInt("match_number") - jb.getInt("match_number");
|
||||
}catch (JSONException j){
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
boolean toggle = false;
|
||||
int matchCount = 1;
|
||||
|
||||
for(int a=0;a<sortedMatchData.length();a++){
|
||||
final JSONObject match = sortedMatchData.getJSONObject(a);
|
||||
|
||||
if(!match.getString("comp_level").equals("qm")){
|
||||
continue;
|
||||
}
|
||||
|
||||
final JSONObject alliances = match.getJSONObject("alliances");
|
||||
final JSONArray redAlliance = alliances.getJSONObject("red").getJSONArray("team_keys");
|
||||
final JSONArray blueAlliance = alliances.getJSONObject("blue").getJSONArray("team_keys");
|
||||
|
||||
tr = new TableRow(getContext());
|
||||
|
||||
if (toggle) {
|
||||
tr.setBackgroundColor(0x30000000);
|
||||
}
|
||||
|
||||
addTableText(tr, String.valueOf(matchCount));
|
||||
// addTableText(tr, match.getString("key"));
|
||||
|
||||
int[] blueKeys = new int[3];
|
||||
int[] redKeys = new int[3];
|
||||
|
||||
for(int b=0;b<6;b++){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
tr.addView(text);
|
||||
|
||||
if(b < 3){
|
||||
String str = redAlliance.getString(b).substring(3);
|
||||
redKeys[b] = Integer.parseInt(str);
|
||||
text.setText(str);
|
||||
text.setBackgroundColor(0x50ff0000);
|
||||
}else{
|
||||
String str = blueAlliance.getString(b-3).substring(3);
|
||||
blueKeys[b-3] = Integer.parseInt(str);
|
||||
text.setText(str);
|
||||
text.setBackgroundColor(0x500000ff);
|
||||
}
|
||||
}
|
||||
|
||||
Table.addView(tr);
|
||||
|
||||
frcMatch matchOBJ = new frcMatch();
|
||||
matchOBJ.matchIndex = matchCount;
|
||||
matchOBJ.blueAlliance = blueKeys;
|
||||
matchOBJ.redAlliance = redKeys;
|
||||
matchesOBJ.add(matchOBJ);
|
||||
|
||||
matchCount += 1;
|
||||
toggle = !toggle;
|
||||
}
|
||||
|
||||
// btn.setOnClickListener(v -> {
|
||||
// if(saveData(matchesOBJ, teamData, eventData)){
|
||||
// alert("Info", "Saved!");
|
||||
// }else{
|
||||
// alert("Error", "Error saving files.");
|
||||
// }
|
||||
// });
|
||||
|
||||
}catch (JSONException j){
|
||||
AlertManager.error(j);
|
||||
AlertManager.alert("Error", "Invalid JSON");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean saveData(ArrayList<frcMatch> matchData, JSONArray teamData, JSONObject eventData){
|
||||
try {
|
||||
final String matchKey = eventData.getString("key");
|
||||
String matchName = eventData.getString("short_name");
|
||||
|
||||
// Sometimes, a short name is not present on TBA Events
|
||||
if(matchName.isEmpty()){
|
||||
matchName = eventData.getString("name");
|
||||
}
|
||||
|
||||
|
||||
ArrayList<frcTeam> teams = new ArrayList<>();
|
||||
for(int i=0;i<teamData.length();i++){
|
||||
frcTeam teamObj = new frcTeam();
|
||||
JSONObject team = teamData.getJSONObject(i);
|
||||
|
||||
teamObj.teamNumber = team.getInt("team_number");
|
||||
teamObj.teamName = team.getString("nickname");
|
||||
teamObj.city = team.getString("city");
|
||||
teamObj.stateOrProv = team.getString("state_prov");
|
||||
teamObj.school = team.getString("school_name");
|
||||
teamObj.country = team.getString("country");
|
||||
teamObj.startingYear = team.getInt("rookie_year");
|
||||
|
||||
teams.add(teamObj);
|
||||
}
|
||||
|
||||
frcEvent event = new frcEvent();
|
||||
event.name = matchName;
|
||||
event.eventCode = matchKey;
|
||||
event.teams = teams;
|
||||
event.matches = matchData;
|
||||
|
||||
return fileEditor.setEvent(event);
|
||||
}catch (JSONException j){
|
||||
AlertManager.error(j);
|
||||
AlertManager.alert("Error", "Invalid JSON");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferBinding;
|
||||
import com.ridgebotics.ridgescout.ui.transfer.bluetooth.BluetoothSenderFragment;
|
||||
import com.ridgebotics.ridgescout.ui.transfer.codes.CodeGeneratorView;
|
||||
|
||||
public class TransferFragment extends Fragment {
|
||||
private FragmentTransferBinding binding;
|
||||
|
||||
// private enum TransferTypes {
|
||||
// CAMERA,
|
||||
// BLUETOOTH,
|
||||
// LOCAL_WIFI,
|
||||
// SCOUTING_SERVER
|
||||
// }
|
||||
|
||||
String evcode;
|
||||
|
||||
private static final int background_color = 0x5000ff00;
|
||||
private static final int unselected_background_color = 0x2000ff00;
|
||||
|
||||
// private Bundle b;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
// b = savedInstanceState;
|
||||
|
||||
binding = FragmentTransferBinding.inflate(inflater, container, false);
|
||||
|
||||
evcode = latestSettings.settings.get_evcode();
|
||||
|
||||
binding.downloadButton.setOnClickListener(v -> {
|
||||
start_download();
|
||||
});
|
||||
|
||||
binding.TBAButton.setOnClickListener(v -> {
|
||||
binding.noEventError.setVisibility(View.GONE);
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||
alert.setTitle("Warning");
|
||||
alert.setMessage("This action requires internet.");
|
||||
alert.setCancelable(true);
|
||||
|
||||
alert.setPositiveButton("Ok", (dialog, which) -> {
|
||||
findNavController(this).navigate(R.id.action_navigation_transfer_to_navigation_tba);
|
||||
});
|
||||
|
||||
alert.setNegativeButton("Cancel", null);
|
||||
alert.create().show();
|
||||
});
|
||||
|
||||
if(evcode.equals("unset")){
|
||||
binding.noEventError.setVisibility(View.VISIBLE);
|
||||
binding.uploadButton.setEnabled(false);
|
||||
binding.CSVButton.setEnabled(false);
|
||||
binding.downloadButton.setEnabled(true);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
binding.uploadButton.setOnClickListener(v -> {
|
||||
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())
|
||||
binding.TBAButton.setEnabled(false);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void start_upload() {
|
||||
FileSelectorFragment.setOnSelect(data -> {
|
||||
TransferSelectorFragment.setOnSelect(new TransferSelectorFragment.onSelect() {
|
||||
@Override
|
||||
public void onSelectCodes(TransferSelectorFragment self) {
|
||||
CodeGeneratorView.setData(data);
|
||||
findNavController(self).navigate(R.id.action_navigation_transfer_selector_to_navigation_code_generator);
|
||||
}
|
||||
@Override
|
||||
public void onSelectBluetooth(TransferSelectorFragment self) {
|
||||
BluetoothSenderFragment.set_data(data);
|
||||
findNavController(self).navigate(R.id.action_navigation_transfer_selector_to_navigation_bluetooth_sender);
|
||||
}
|
||||
@Override
|
||||
public void onSelectFileBundle(TransferSelectorFragment self) {
|
||||
FileBundle.send(data, getContext());
|
||||
}
|
||||
});
|
||||
findNavController(this).navigate(R.id.action_navigation_file_selector_to_navigation_transfer_selector);
|
||||
});
|
||||
findNavController(this).navigate(R.id.action_navigation_transfer_to_navigation_file_selector);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void start_download(){
|
||||
|
||||
TransferSelectorFragment.setOnSelect(new TransferSelectorFragment.onSelect() {
|
||||
@Override
|
||||
public void onSelectCodes(TransferSelectorFragment self) {
|
||||
findNavController(self).navigate(R.id.action_navigation_transfer_selector_to_navigation_code_scanner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectBluetooth(TransferSelectorFragment self) {
|
||||
findNavController(self).navigate(R.id.action_navigation_transfer_selector_to_navigation_bluetooth_receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectFileBundle(TransferSelectorFragment self) {
|
||||
FileBundle.receive(getActivity());
|
||||
}
|
||||
});
|
||||
findNavController(this).navigate(R.id.action_navigation_transfer_to_navigation_transfer_selector);
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferSelectorBinding;
|
||||
|
||||
public class TransferSelectorFragment extends Fragment {
|
||||
|
||||
// Declaring three blank funcs in one line lol
|
||||
private static onSelect onselect = new onSelect() {@Override public void onSelectCodes(TransferSelectorFragment self) {}@Override public void onSelectBluetooth(TransferSelectorFragment self) {} @Override public void onSelectFileBundle(TransferSelectorFragment self) {}};
|
||||
|
||||
public static void setOnSelect(onSelect tmp) {
|
||||
onselect = tmp;
|
||||
}
|
||||
|
||||
public interface onSelect {
|
||||
void onSelectCodes(TransferSelectorFragment self);
|
||||
void onSelectBluetooth(TransferSelectorFragment self);
|
||||
void onSelectFileBundle(TransferSelectorFragment self);
|
||||
}
|
||||
|
||||
FragmentTransferSelectorBinding binding;
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentTransferSelectorBinding.inflate(inflater, container, false);
|
||||
|
||||
binding.codesButton.setOnClickListener(view -> {
|
||||
onselect.onSelectCodes(this);
|
||||
});
|
||||
|
||||
binding.bluetoothButton.setOnClickListener(view -> {
|
||||
onselect.onSelectBluetooth(this);
|
||||
});
|
||||
|
||||
binding.fileBundleButton.setOnClickListener(view -> {
|
||||
onselect.onSelectFileBundle(this);
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.bluetooth;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothServerSocket;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BluetoothReceiver {
|
||||
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
||||
private static final String NAME = "BluetoothReceiverApp";
|
||||
private static final int REQUEST_ENABLE_BT = 1;
|
||||
private static final int REQUEST_PERMISSIONS = 2;
|
||||
|
||||
private Context context;
|
||||
private BluetoothAdapter bluetoothAdapter;
|
||||
private BluetoothServerSocket serverSocket;
|
||||
private BluetoothSocket socket;
|
||||
private InputStream inputStream;
|
||||
private boolean listening = false;
|
||||
private receivedData receiveddata;
|
||||
|
||||
public BluetoothReceiver(Context context, receivedData receiveddata) {
|
||||
this.context = context;
|
||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
this.receiveddata = receiveddata;
|
||||
}
|
||||
|
||||
public boolean isBluetoothSupported() {
|
||||
return bluetoothAdapter != null;
|
||||
}
|
||||
|
||||
public boolean isBluetoothEnabled() {
|
||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||
}
|
||||
|
||||
private static final int REQUEST_BLUETOOTH_PERMISSIONS = 1;
|
||||
|
||||
public static void
|
||||
requestBluetoothPermissions(Activity activity) {
|
||||
List<String> permissionsNeeded = new ArrayList<>();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// For Android 12 and above
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN);
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_CONNECT);
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_ADVERTISE);
|
||||
}
|
||||
} else {
|
||||
// For Android 11 and below
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH);
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_ADMIN);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!permissionsNeeded.isEmpty()) {
|
||||
ActivityCompat.requestPermissions(activity, permissionsNeeded.toArray(new String[0]), REQUEST_BLUETOOTH_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasBluetoothPermissions(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
return ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_ADVERTISE) == PackageManager.PERMISSION_GRANTED;
|
||||
} else {
|
||||
boolean hasBasicPermissions = ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return hasBasicPermissions && ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
|
||||
} else {
|
||||
return hasBasicPermissions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
public void startListening() throws IOException {
|
||||
if(!hasBluetoothPermissions(context)){
|
||||
requestBluetoothPermissions((Activity) context);
|
||||
return;
|
||||
}
|
||||
serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
|
||||
listening = true;
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (listening) {
|
||||
try {
|
||||
socket = serverSocket.accept();
|
||||
inputStream = socket.getInputStream();
|
||||
// Handle incoming data here
|
||||
handleIncomingData();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void handleIncomingData() throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytes;
|
||||
try {
|
||||
while (true) {
|
||||
bytes = inputStream.read(buffer);
|
||||
if (bytes != -1) {
|
||||
receiveddata.processReceivedData(buffer, bytes);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (e.getMessage() != null && e.getMessage().contains("bt socket closed, read return: -1")) {
|
||||
receiveddata.onConnectionStop();
|
||||
System.out.println("Bluetooth socket closed, treating as end of stream");
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface receivedData {
|
||||
public void processReceivedData(byte[] data, int bytes);
|
||||
public void onConnectionStop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void stopListening() throws IOException {
|
||||
listening = false;
|
||||
if (serverSocket != null) {
|
||||
serverSocket.close();
|
||||
}
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.bluetooth;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferBluetoothReceiverBinding;
|
||||
import com.ridgebotics.ridgescout.types.file;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
public class BluetoothReceiverFragment extends Fragment {
|
||||
private BluetoothReceiver bluetoothReceiver;
|
||||
private Button startListeningButton;
|
||||
private Button stopListeningButton;
|
||||
private TextView statusTextView;
|
||||
|
||||
|
||||
|
||||
// private void alert(String title, String content) {
|
||||
// AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
|
||||
// dialog.setCancelable(true);
|
||||
// dialog.setTitle(title);
|
||||
// dialog.setMessage(content);
|
||||
//
|
||||
// final AlertDialog alert = dialog.create();
|
||||
// alert.show();
|
||||
//
|
||||
// }
|
||||
|
||||
FragmentTransferBluetoothReceiverBinding binding;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentTransferBluetoothReceiverBinding.inflate(inflater, container, false);
|
||||
|
||||
|
||||
// bluetoothReceiver = new BluetoothReceiver(context);
|
||||
|
||||
bluetoothReceiver = new BluetoothReceiver(getContext(), new BluetoothReceiver.receivedData() {
|
||||
@Override
|
||||
public void processReceivedData(byte[] data, int bytes) {
|
||||
receiveData(data, bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStop() {
|
||||
finished_recieve();
|
||||
}
|
||||
});
|
||||
|
||||
startListeningButton = binding.startListeningButton;
|
||||
stopListeningButton = binding.stopListeningButton;
|
||||
statusTextView = binding.statusTextView;
|
||||
|
||||
if (!bluetoothReceiver.isBluetoothSupported()) {
|
||||
AlertManager.error("Bluetooth is not supported on this device");
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
if (!bluetoothReceiver.isBluetoothEnabled()) {
|
||||
AlertManager.error("Please enable Bluetooth");
|
||||
}
|
||||
|
||||
startListeningButton.setOnClickListener(v -> {
|
||||
startListening();
|
||||
});
|
||||
|
||||
stopListeningButton.setOnClickListener(v -> {
|
||||
stopListening();
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void startListening() {
|
||||
try {
|
||||
bluetoothReceiver.startListening();
|
||||
statusTextView.setText("Listening for incoming connections...");
|
||||
startListeningButton.setEnabled(false);
|
||||
stopListeningButton.setEnabled(true);
|
||||
|
||||
recievedBytes = new ArrayList<>();
|
||||
|
||||
} catch (IOException e) {
|
||||
AlertManager.error("Failed to start listening: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void stopListening() {
|
||||
try {
|
||||
bluetoothReceiver.stopListening();
|
||||
statusTextView.setText("Not listening");
|
||||
startListeningButton.setEnabled(true);
|
||||
stopListeningButton.setEnabled(false);
|
||||
} catch (IOException e) {
|
||||
AlertManager.error("Failed to stop listening: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<byte[]> recievedBytes;
|
||||
|
||||
private void receiveData(byte[] data, int bytes) {
|
||||
byte[] newBytes = fileEditor.getByteBlock(data, 0, bytes);
|
||||
System.out.println("Recieved " + bytes + " Bytes over bluetooth!");
|
||||
recievedBytes.add(newBytes);
|
||||
}
|
||||
|
||||
|
||||
private void finished_recieve() {
|
||||
String result_filenames = "";
|
||||
try {
|
||||
|
||||
byte[] resultBytes = fileEditor.combineByteArrays(recievedBytes);
|
||||
resultBytes = fileEditor.blockUncompress(resultBytes);
|
||||
|
||||
|
||||
BuiltByteParser bbp = new BuiltByteParser(resultBytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> result = bbp.parse();
|
||||
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
if (result.get(i).getType() != file.typecode) continue;
|
||||
file f = file.decode((byte[]) result.get(i).get());
|
||||
|
||||
if (f != null) {
|
||||
System.out.println(f.filename);
|
||||
if (f.write())
|
||||
result_filenames += f.filename + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} catch (DataFormatException e) {
|
||||
AlertManager.error(e);
|
||||
} catch (BuiltByteParser.byteParsingExeption e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
|
||||
AlertManager.alert("Completed!", result_filenames);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (bluetoothReceiver != null)
|
||||
try {
|
||||
bluetoothReceiver.stopListening();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.bluetooth;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BluetoothSender {
|
||||
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
||||
private static final int REQUEST_ENABLE_BT = 1;
|
||||
private static final int REQUEST_PERMISSIONS = 2;
|
||||
|
||||
private Context context;
|
||||
private BluetoothAdapter bluetoothAdapter;
|
||||
private BluetoothSocket socket;
|
||||
public OutputStream outputStream;
|
||||
|
||||
public BluetoothSender(Context context) {
|
||||
this.context = context;
|
||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
}
|
||||
|
||||
public boolean isBluetoothSupported() {
|
||||
return bluetoothAdapter != null;
|
||||
}
|
||||
|
||||
public boolean isBluetoothEnabled() {
|
||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||
}
|
||||
|
||||
private static final int REQUEST_BLUETOOTH_PERMISSIONS = 1;
|
||||
|
||||
public static void requestBluetoothPermissions(Activity activity) {
|
||||
List<String> permissionsNeeded = new ArrayList<>();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// For Android 12 and above
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN);
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_CONNECT);
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_ADVERTISE);
|
||||
}
|
||||
} else {
|
||||
// For Android 11 and below
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH);
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.BLUETOOTH_ADMIN);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!permissionsNeeded.isEmpty()) {
|
||||
ActivityCompat.requestPermissions(activity, permissionsNeeded.toArray(new String[0]), REQUEST_BLUETOOTH_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasBluetoothPermissions(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
return ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_ADVERTISE) == PackageManager.PERMISSION_GRANTED;
|
||||
} else {
|
||||
boolean hasBasicPermissions = ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return hasBasicPermissions && ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
|
||||
} else {
|
||||
return hasBasicPermissions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
public Set<BluetoothDevice> getPairedDevices() {
|
||||
if(!hasBluetoothPermissions(context)){
|
||||
requestBluetoothPermissions((Activity) context);
|
||||
return null;
|
||||
}
|
||||
return bluetoothAdapter.getBondedDevices();
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
public void connectToDevice(BluetoothDevice device) throws IOException {
|
||||
if(!hasBluetoothPermissions(context)){
|
||||
requestBluetoothPermissions((Activity) context);
|
||||
return;
|
||||
}
|
||||
socket = device.createRfcommSocketToServiceRecord(MY_UUID);
|
||||
socket.connect();
|
||||
outputStream = socket.getOutputStream();
|
||||
}
|
||||
|
||||
public void sendData(byte[] data) throws IOException {
|
||||
if (outputStream != null) {
|
||||
outputStream.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (outputStream != null) {
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.bluetooth;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferBluetoothSenderBinding;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
public class BluetoothSenderFragment extends Fragment {
|
||||
private BluetoothSender bluetoothSender;
|
||||
private ListView deviceListView;
|
||||
private Button sendFileButton;
|
||||
private ArrayAdapter<String> deviceArrayAdapter;
|
||||
private ArrayList<BluetoothDevice> deviceList;
|
||||
|
||||
private FragmentTransferBluetoothSenderBinding binding;
|
||||
|
||||
private static byte[] data_to_send = new byte[0];
|
||||
public static void set_data(byte[] data){
|
||||
data_to_send = data;
|
||||
}
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentTransferBluetoothSenderBinding.inflate(inflater, container, false);
|
||||
|
||||
bluetoothSender = new BluetoothSender(getContext());
|
||||
deviceListView = binding.deviceListView;
|
||||
sendFileButton = binding.sendFileButton;
|
||||
|
||||
deviceList = new ArrayList<>();
|
||||
deviceArrayAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1);
|
||||
deviceListView.setAdapter(deviceArrayAdapter);
|
||||
|
||||
if (!bluetoothSender.isBluetoothSupported()) {
|
||||
AlertManager.toast("Bluetooth is not supported on this device");
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
if (!bluetoothSender.isBluetoothEnabled()) {
|
||||
AlertManager.toast("Please enable Bluetooth");
|
||||
} else {
|
||||
listPairedDevices();
|
||||
}
|
||||
|
||||
deviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
BluetoothDevice selectedDevice = deviceList.get(position);
|
||||
try {
|
||||
bluetoothSender.connectToDevice(selectedDevice);
|
||||
AlertManager.toast("Connected to " + selectedDevice.getName());
|
||||
sendFileButton.setEnabled(true);
|
||||
} catch (IOException e) {
|
||||
AlertManager.toast("Failed to connect: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sendFileButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
sendData();
|
||||
}
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private void listPairedDevices() {
|
||||
Set<BluetoothDevice> pairedDevices = bluetoothSender.getPairedDevices();
|
||||
if (pairedDevices != null && !pairedDevices.isEmpty()) {
|
||||
deviceList.addAll(pairedDevices);
|
||||
for (BluetoothDevice device : pairedDevices) {
|
||||
deviceArrayAdapter.add(device.getName() + "\n" + device.getAddress());
|
||||
}
|
||||
} else {
|
||||
AlertManager.toast("No paired devices found");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendData() {
|
||||
try {
|
||||
byte[] compressed = fileEditor.blockCompress(data_to_send);
|
||||
|
||||
for(int i = 0; i < Math.ceil((double) compressed.length/1024); i++){
|
||||
bluetoothSender.sendData(fileEditor.getByteBlock(compressed, i*1024, (i+1)*1024));
|
||||
}
|
||||
|
||||
bluetoothSender.close();
|
||||
sendFileButton.setEnabled(false);
|
||||
|
||||
|
||||
|
||||
AlertManager.toast("File sent successfully");
|
||||
} catch (IOException e) {
|
||||
AlertManager.toast("Failed to send file: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
if (bluetoothSender != null)
|
||||
try {
|
||||
bluetoothSender.close();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferCodeSenderBinding;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class CodeGeneratorView extends Fragment {
|
||||
private ImageView qrImage;
|
||||
private SeekBar qrSpeedSlider;
|
||||
private SeekBar qrSizeSlider;
|
||||
private TextView qrIndexN;
|
||||
private TextView qrIndexD;
|
||||
|
||||
private final int maxQrCount = 256; //The max number that can be stored in a byte
|
||||
|
||||
private final int maxQrSpeed = 5;
|
||||
private final int minQrSpeed = 300 + maxQrSpeed - 1;
|
||||
|
||||
private int minQrSize = 0;
|
||||
private final int maxQrSize = 800;
|
||||
private int qrSize = 200;
|
||||
|
||||
private final int defaultQrDelay = 419;
|
||||
private int qrDelay = 0;
|
||||
private int qrIndex = 0;
|
||||
|
||||
private CountDownTimer timer;
|
||||
private int qrCount = 0;
|
||||
|
||||
private ArrayList<Bitmap> qrBitmaps;
|
||||
|
||||
private FragmentTransferCodeSenderBinding binding;
|
||||
|
||||
private static byte[] data;
|
||||
public static void setData(String data){
|
||||
setData(data.getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
public static void setData(byte[] tmpdata){
|
||||
data = tmpdata;
|
||||
}
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentTransferCodeSenderBinding.inflate(inflater, container, false);
|
||||
|
||||
qrImage = binding.qrImage;
|
||||
qrSpeedSlider = binding.qrSpeedSlider;
|
||||
qrSizeSlider = binding.qrSizeSlider;
|
||||
qrIndexN = binding.qrIndexN;
|
||||
qrIndexD = binding.qrIndexD;
|
||||
|
||||
String compressed = new String(fileEditor.blockCompress(data), StandardCharsets.ISO_8859_1);
|
||||
|
||||
if(compressed.isEmpty()){
|
||||
AlertManager.alert("Error!", "Empty data!");
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
minQrSize = Math.round((float)compressed.length() / maxQrCount)+1;
|
||||
|
||||
qrSizeSlider.setMax(maxQrSize-minQrSize);
|
||||
qrSpeedSlider.setMax((minQrSpeed-maxQrSpeed)*2);
|
||||
|
||||
qrSizeSlider.setProgress(minQrSize+qrSize);
|
||||
qrSpeedSlider.setProgress(defaultQrDelay+5);
|
||||
|
||||
sendData(compressed);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
private Bitmap generateQrCode(String contents) throws WriterException {
|
||||
|
||||
final int size = 512;
|
||||
|
||||
if (contents == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
|
||||
|
||||
// The Charset must be UTF-8, Or data will not be transferred properly. IDK why.
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "ISO-8859-1");
|
||||
// hints.put(EncodeHintType.);
|
||||
hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
|
||||
BitMatrix result;
|
||||
try {
|
||||
result = writer.encode(contents, BarcodeFormat.DATA_MATRIX, size, size, hints);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Unsupported format
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
int width = result.getWidth();
|
||||
int height = result.getHeight();
|
||||
int[] pixels = new int[width * height];
|
||||
for (int y = 0; y < height; y++) {
|
||||
int offset = y * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
|
||||
private void sendData(String data){
|
||||
|
||||
|
||||
|
||||
qrCount = (data.length()/qrSize)+1;
|
||||
qrIndexD.setText(String.valueOf(qrCount));
|
||||
|
||||
// alert("size", ""+binding.qrSizeSlider.getProgress()+"\n"+binding.qrSizeSlider.getMax());
|
||||
|
||||
qrSpeedSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
qrDelay = -(minQrSpeed - progress - maxQrSpeed + 1);
|
||||
}
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
|
||||
qrSizeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
qrSize = seekBar.getProgress() + minQrSize;
|
||||
// qrCount = (int)Math.ceil((double) (data.length()+1)/qrSize);
|
||||
qrCount = ((data.length()+1)/qrSize) +1;
|
||||
qrIndexD.setText(String.valueOf(qrCount));
|
||||
sendData(data);
|
||||
}
|
||||
});
|
||||
|
||||
// qrSizeSlider.setProgress(qr);
|
||||
|
||||
qrBitmaps = new ArrayList<>();
|
||||
|
||||
int randID = new Random().nextInt(255);
|
||||
|
||||
for(int i=0;i<=((data.length()+1)/qrSize);i++){
|
||||
final int start = i*qrSize;
|
||||
int end = (i+1)*qrSize;
|
||||
if(end >= data.length()){
|
||||
end = data.length();
|
||||
}
|
||||
try {
|
||||
// alert("test", ""+Math.ceil((double)data.length()/(double)qrSize));
|
||||
qrBitmaps.add(generateQrCode(
|
||||
fileEditor.byteToChar(fileEditor.internalDataVersion) +
|
||||
String.valueOf(fileEditor.byteToChar(randID)) +
|
||||
fileEditor.byteToChar(i) +
|
||||
fileEditor.byteToChar(qrCount - 1) +
|
||||
data.substring(start, end)
|
||||
));
|
||||
// alert("title", ""+(qrCount-1));
|
||||
}catch (WriterException e){
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
qrIndex = 0;
|
||||
if(timer != null){
|
||||
timer.cancel();
|
||||
}
|
||||
qrLoop();
|
||||
}
|
||||
|
||||
private void updateQr(){
|
||||
qrImage.setImageBitmap(qrBitmaps.get(qrIndex));
|
||||
if(qrDelay > 0) {
|
||||
this.qrIndex += 1;
|
||||
if (this.qrIndex >= this.qrCount) {
|
||||
this.qrIndex = 0;
|
||||
}
|
||||
}else{
|
||||
this.qrIndex -= 1;
|
||||
if (this.qrIndex < 0) {
|
||||
this.qrIndex = this.qrCount-1;
|
||||
}
|
||||
}
|
||||
|
||||
qrIndexN.setText(String.valueOf(qrIndex+1));
|
||||
}
|
||||
|
||||
private void qrLoop(){
|
||||
timer = new CountDownTimer(minQrSpeed-Math.abs(qrDelay)+1, 1000) {
|
||||
public void onTick(long millisUntilFinished) {}
|
||||
public void onFinish() {
|
||||
updateQr();
|
||||
qrLoop();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||
|
||||
// From https://github.com/dlazaro66/QRCodeReaderView/blob/master/samples/src/main/java/com/example/qr_readerexample/PointsOverlayView.java
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class CodeOverlayView extends View {
|
||||
|
||||
PointF[] points;
|
||||
int[] barColors;
|
||||
private Paint paint;
|
||||
private final int barHeight = 50;
|
||||
|
||||
public CodeOverlayView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public CodeOverlayView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public CodeOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
paint = new Paint();
|
||||
paint.setColor(Color.YELLOW);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
}
|
||||
|
||||
public void setPoints(PointF[] points) {
|
||||
this.points = points;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setBar(int[] barColors){
|
||||
this.barColors = barColors;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
if (points != null) {
|
||||
for (PointF pointF : points) {
|
||||
canvas.drawCircle(pointF.x, pointF.y, 10, paint);
|
||||
}
|
||||
}
|
||||
if(barColors != null){
|
||||
final double width = getWidth()/barColors.length;
|
||||
|
||||
final int top = 0;
|
||||
final int bottom = barHeight;
|
||||
|
||||
for(int i=0;i<barColors.length;i++){
|
||||
|
||||
final int num = barColors[i];
|
||||
|
||||
int c = Color.RED;
|
||||
|
||||
if(num == 2){
|
||||
c = Color.GREEN;
|
||||
}else if(num == 1){
|
||||
c = Color.YELLOW;
|
||||
}
|
||||
|
||||
final Paint p = new Paint();
|
||||
p.setColor(c);
|
||||
|
||||
canvas.drawRect(new Rect(
|
||||
(int)(i*width), top,
|
||||
(int)((i+1)*width), bottom
|
||||
), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.ChecksumException;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.RGBLuminanceSource;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.google.zxing.datamatrix.DataMatrixReader;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CodeScanTask extends AsyncTask<String, String, String>{
|
||||
private Function<String, String> resultFunction = null;
|
||||
private Bitmap image;
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... str) {
|
||||
if(image == null){return null;}
|
||||
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
int[] pixels = new int[width * height];
|
||||
image.getPixels(pixels, 0, width, 0, 0, width, height);
|
||||
|
||||
RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
|
||||
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
|
||||
Map<DecodeHintType, Object> hints = new HashMap<>();
|
||||
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
|
||||
// hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.of(BarcodeFormat.DATA_MATRIX));
|
||||
|
||||
Reader reader = new DataMatrixReader();
|
||||
try {
|
||||
Result result = reader.decode(binaryBitmap, hints);
|
||||
return result.getText();
|
||||
} catch (NotFoundException | ChecksumException | FormatException e) {
|
||||
// AlertManager.error(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public void setImage(Bitmap image){this.image = image;}
|
||||
public void onResult(Function<String, String> func) {
|
||||
this.resultFunction = func;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
super.onPostExecute(result);
|
||||
if(resultFunction != null){
|
||||
resultFunction.apply(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||
|
||||
import static androidx.core.math.MathUtils.clamp;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.Image;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.camera.core.AspectRatio;
|
||||
import androidx.camera.core.CameraSelector;
|
||||
import androidx.camera.core.ExperimentalGetImage;
|
||||
import androidx.camera.core.ImageAnalysis;
|
||||
import androidx.camera.core.ImageProxy;
|
||||
import androidx.camera.core.Preview;
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferCodeReceiverBinding;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferCodeSenderBinding;
|
||||
import com.ridgebotics.ridgescout.types.file;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
//public class scannerView extends androidx.appcompat.widget.AppCompatImageView {
|
||||
public class CodeScannerView extends Fragment {
|
||||
private CodeOverlayView CodeOverlayView;
|
||||
private Handler uiHandler;
|
||||
|
||||
|
||||
private void alert(String title, String content) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||
alert.setMessage(content);
|
||||
alert.setTitle(title);
|
||||
alert.setPositiveButton("OK", null);
|
||||
alert.setCancelable(true);
|
||||
alert.create().show();
|
||||
}
|
||||
|
||||
|
||||
private float scale = 0;
|
||||
private final int downscale = 1;
|
||||
private LifecycleOwner lifecycle;
|
||||
|
||||
private void setImage(Bitmap bmp){
|
||||
if(scale == 0) {
|
||||
scale = ((float) binding.container.getWidth() / bmp.getWidth()) * ((float) 16 / 9);
|
||||
binding.scannerImage.setTranslationX(0);
|
||||
binding.scannerImage.setTranslationY(0);
|
||||
}
|
||||
scanQRCode(bmp);
|
||||
binding.scannerImage.setImageBitmap(bmp);
|
||||
binding.scannerThreshold.bringToFront();
|
||||
// alert("test", getChildCount()+"");
|
||||
}
|
||||
|
||||
// private Bitmap img
|
||||
|
||||
int[] levelMap = new int[256];
|
||||
private void recalcMap(){
|
||||
for (int i = 0; i < 256; i++) {
|
||||
levelMap[i] = clamp(
|
||||
(clamp(
|
||||
i-thresholdOffset, 0, 255) / (256 / numColors)) * (256 / numColors
|
||||
)+brightness, 0, 255
|
||||
);
|
||||
}
|
||||
}
|
||||
private Bitmap toGreyscale(Image image){
|
||||
// Turns out the "Y" In YUV is the Luminance of the pixel.
|
||||
// Makes converting to greyscale 1000x easier
|
||||
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
|
||||
final int width = image.getWidth();
|
||||
final int height = image.getHeight();
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int L = levelMap[yBuffer.get() & 0xff];
|
||||
pixels[y * width + x] = 0xff000000 | (L << 16) | (L << 8) | L;
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
public void scanQRCode(Bitmap bitmap) {
|
||||
|
||||
CodeScanTask async = new CodeScanTask();
|
||||
async.setImage(bitmap);
|
||||
async.onResult(data -> {
|
||||
if(data != null){
|
||||
// alert("test", ""+fileEditor.byteFromChar(data.charAt(0)));
|
||||
compileData(
|
||||
fileEditor.byteFromChar(data.charAt(0)),
|
||||
fileEditor.byteFromChar(data.charAt(1)),
|
||||
fileEditor.byteFromChar(data.charAt(2)),
|
||||
(fileEditor.byteFromChar(data.charAt(3))+1),
|
||||
data.substring(4)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
async.execute();
|
||||
|
||||
|
||||
|
||||
// return contents;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private int numColors = 3;
|
||||
private int thresholdOffset = 128;
|
||||
private int brightness = 128;
|
||||
|
||||
private FragmentTransferCodeReceiverBinding binding;
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentTransferCodeReceiverBinding.inflate(inflater, container, false);
|
||||
|
||||
this.lifecycle = getViewLifecycleOwner();
|
||||
|
||||
|
||||
|
||||
uiHandler = new Handler();
|
||||
|
||||
|
||||
binding.scannerThreshold.setProgress(thresholdOffset);
|
||||
binding.scannerThreshold.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
thresholdOffset = 127-progress;
|
||||
recalcMap();
|
||||
}
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
binding.scannerThreshold.setMax(255);
|
||||
|
||||
binding.scannerColors.setProgress(numColors);
|
||||
binding.scannerColors.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
numColors = 18-(progress-2);
|
||||
recalcMap();
|
||||
}
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
binding.scannerColors.setMax(18);
|
||||
binding.scannerBrightness.setProgress(brightness);
|
||||
binding.scannerBrightness.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
brightness = progress-128;
|
||||
recalcMap();
|
||||
}
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
binding.scannerBrightness.setMax(256);
|
||||
|
||||
|
||||
recalcMap();
|
||||
|
||||
CodeOverlayView = new CodeOverlayView(getContext());
|
||||
CodeOverlayView.bringToFront();
|
||||
ConstraintLayout.LayoutParams pointsOverlayViewParams = new ConstraintLayout.LayoutParams(
|
||||
ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT
|
||||
);
|
||||
|
||||
CodeOverlayView.setLayoutParams(pointsOverlayViewParams);
|
||||
binding.container.addView(CodeOverlayView);
|
||||
|
||||
ListenableFuture<ProcessCameraProvider> cameraProviderFuture
|
||||
= ProcessCameraProvider.getInstance(getContext());
|
||||
|
||||
cameraProviderFuture.addListener(() -> {
|
||||
try {
|
||||
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
|
||||
bindPreview(cameraProvider);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
// No errors need to be handled for this Future.
|
||||
// This should never be reached.
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(getContext()));
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
|
||||
|
||||
Preview preview = new Preview.Builder()
|
||||
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
|
||||
.setTargetRotation(Surface.ROTATION_180)
|
||||
.build();
|
||||
|
||||
CameraSelector cameraSelector = new CameraSelector.Builder()
|
||||
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
|
||||
// .addCameraFilter(CameraFilters.NON)
|
||||
.build();
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
|
||||
// .setTargetResolution(new Size(224, 224))
|
||||
.setOutputImageRotationEnabled(false)
|
||||
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||
.build();
|
||||
|
||||
|
||||
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
|
||||
@OptIn(markerClass = ExperimentalGetImage.class) @Override
|
||||
public void analyze(@NonNull ImageProxy image) {
|
||||
Image img = Objects.requireNonNull(image.getImage());
|
||||
uiHandler.post(new Runnable() {
|
||||
final Bitmap bmp = toGreyscale(img);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// setImage(toGreyscale(bmp));
|
||||
setImage(bmp);
|
||||
}
|
||||
});
|
||||
image.close();
|
||||
}
|
||||
});
|
||||
|
||||
cameraProvider.unbindAll();
|
||||
|
||||
cameraProvider.bindToLifecycle(lifecycle,
|
||||
cameraSelector, imageAnalysis, preview);
|
||||
|
||||
// preview.setSurfaceProvider(binding.previewView.getSurfaceProvider());
|
||||
|
||||
}
|
||||
|
||||
private String[] qrDataArr;
|
||||
private int qrScannedCount;
|
||||
private int[] barColors;
|
||||
private int randID;
|
||||
private int prevQrIndex;
|
||||
private void compileData(int dataVersion, int randID, int qrIndex, int qrCount, String qrData){
|
||||
if(dataVersion != fileEditor.internalDataVersion){
|
||||
alert("Error", "Incorrect data version ("+dataVersion+" != "+fileEditor.internalDataVersion+")");
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset code array if ID Changes
|
||||
if(randID != this.randID){
|
||||
this.randID = randID;
|
||||
qrDataArr = new String[qrCount];
|
||||
Log.i("title", ""+qrCount);
|
||||
barColors = new int[qrCount];
|
||||
prevQrIndex = qrIndex;
|
||||
}
|
||||
|
||||
final boolean updated;
|
||||
|
||||
if(qrDataArr[qrIndex] == null) {
|
||||
qrDataArr[qrIndex] = qrData;
|
||||
updated = true;
|
||||
qrScannedCount += 1;
|
||||
}else{
|
||||
updated = false;
|
||||
}
|
||||
|
||||
barColors[prevQrIndex] = 2;
|
||||
barColors[qrIndex] = 1;
|
||||
CodeOverlayView.setBar(barColors);
|
||||
|
||||
if(updated && qrScannedCount >= qrCount){
|
||||
|
||||
String compiledString = "";
|
||||
for(int i=0;i<qrCount;i++){
|
||||
compiledString += qrDataArr[i];
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] compiledBytes = compiledString.getBytes(StandardCharsets.ISO_8859_1);
|
||||
byte[] resultBytes = fileEditor.blockUncompress(compiledBytes);
|
||||
|
||||
|
||||
String result_filenames = "";
|
||||
|
||||
BuiltByteParser bbp = new BuiltByteParser(resultBytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> result = bbp.parse();
|
||||
|
||||
for(int i = 0; i < result.size(); i++){
|
||||
if(result.get(i).getType() != file.typecode) continue;
|
||||
file f = file.decode((byte[]) result.get(i).get());
|
||||
|
||||
if(f != null)
|
||||
if(f.write())
|
||||
result_filenames += f.filename + "\n";
|
||||
}
|
||||
|
||||
AlertManager.alert("Completed!", result_filenames);
|
||||
|
||||
}catch (Exception e){
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
prevQrIndex = qrIndex;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class AlertManager {
|
||||
public static Context context;
|
||||
|
||||
public static void init(Context c){
|
||||
context = c;
|
||||
}
|
||||
|
||||
public static void alert(String title, String content) {
|
||||
((Activity) context).runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
alert.setMessage(content);
|
||||
alert.setTitle(title);
|
||||
alert.setPositiveButton("OK", null);
|
||||
alert.setCancelable(true);
|
||||
|
||||
alert.create().show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void toast(String content) {
|
||||
((Activity) context).runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
Toast.makeText(context, content, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void error(String content) {
|
||||
((Activity) context).runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
alert.setMessage(content);
|
||||
alert.setTitle("Error!");
|
||||
alert.setPositiveButton("OK", null);
|
||||
alert.setCancelable(true);
|
||||
|
||||
alert.create().show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void error(Exception e) {
|
||||
e.printStackTrace();
|
||||
((Activity) context).runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
alert.setMessage(sw.toString());
|
||||
alert.setTitle(e.getMessage());
|
||||
alert.setPositiveButton("OK", null);
|
||||
alert.setCancelable(true);
|
||||
|
||||
alert.create().show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
public class AutoSaveManager {
|
||||
private static final long AUTO_SAVE_DELAY = 2000; // 2 seconds
|
||||
|
||||
private final Handler handler;
|
||||
private final Runnable autoSaveRunnable;
|
||||
private boolean isAutoSaveScheduled = false;
|
||||
private final AutoSaveFunction autoSaveFunction;
|
||||
public boolean isRunning = false;
|
||||
|
||||
// Functional interface for the auto-save function
|
||||
@FunctionalInterface
|
||||
public interface AutoSaveFunction {
|
||||
void save();
|
||||
}
|
||||
|
||||
public AutoSaveManager(AutoSaveFunction autoSaveFunction) {
|
||||
this.autoSaveFunction = autoSaveFunction;
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
autoSaveRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
performAutoSave();
|
||||
isAutoSaveScheduled = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void start() {
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
isRunning = false;
|
||||
handler.removeCallbacks(autoSaveRunnable);
|
||||
isAutoSaveScheduled = false;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (!isRunning) {
|
||||
return; // Don't schedule auto-saves when not running
|
||||
}
|
||||
|
||||
// Cancel any previously scheduled auto-save
|
||||
handler.removeCallbacks(autoSaveRunnable);
|
||||
|
||||
// Schedule a new auto-save
|
||||
handler.postDelayed(autoSaveRunnable, AUTO_SAVE_DELAY);
|
||||
isAutoSaveScheduled = true;
|
||||
}
|
||||
|
||||
private void performAutoSave() {
|
||||
if (isRunning) {
|
||||
// Call the provided auto-save function
|
||||
autoSaveFunction.save();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
// Remove any pending auto-save tasks when the activity or fragment is destroyed
|
||||
stop();
|
||||
}
|
||||
|
||||
public boolean isAutoSaveScheduled() {
|
||||
return isAutoSaveScheduled;
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class BuiltByteParser {
|
||||
public static final Integer boolType = 0;
|
||||
public static final Integer intType = 1;
|
||||
public static final Integer stringType = 2;
|
||||
public static final Integer intArrayType = 3;
|
||||
public static final Integer stringArrayType = 4;
|
||||
|
||||
public class byteParsingExeption extends Exception {
|
||||
public byteParsingExeption() {}
|
||||
public byteParsingExeption(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static String unBlankStrNull(String str){
|
||||
if(str.equals("ƒ")){
|
||||
return "";
|
||||
}
|
||||
else return str;
|
||||
}
|
||||
|
||||
public abstract class parsedObject {
|
||||
public abstract Integer getType();
|
||||
public abstract Object get();
|
||||
}
|
||||
|
||||
public class boolObject extends parsedObject{
|
||||
boolean val;
|
||||
public Integer getType(){return boolType;}
|
||||
public Object get(){return val;}
|
||||
}
|
||||
|
||||
public class intObject extends parsedObject{
|
||||
int num;
|
||||
public Integer getType(){return intType;}
|
||||
public Object get(){return num;}
|
||||
}
|
||||
public class stringObject extends parsedObject{
|
||||
String str;
|
||||
public Integer getType(){return stringType;}
|
||||
public Object get(){return str;}
|
||||
}
|
||||
|
||||
|
||||
public class intArrayObject extends parsedObject{
|
||||
int[] arr;
|
||||
public Integer getType(){return intArrayType;}
|
||||
public Object get(){return arr;}
|
||||
}
|
||||
public class stringArrayObject extends parsedObject{
|
||||
String[] arr;
|
||||
public Integer getType(){return stringArrayType;}
|
||||
public Object get(){return arr;}
|
||||
}
|
||||
|
||||
|
||||
public class rawObject extends parsedObject {
|
||||
private int type;
|
||||
public rawObject(int type){this.type = type;}
|
||||
byte[] bytes;
|
||||
public Integer getType(){return type;}
|
||||
public Object get(){return bytes;}
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
ArrayList<parsedObject> objects = new ArrayList<>();
|
||||
public BuiltByteParser(byte[] bytes){
|
||||
this.bytes = bytes;
|
||||
}
|
||||
public ArrayList<parsedObject> parse() throws byteParsingExeption {
|
||||
if(bytes.length < 3){throw new byteParsingExeption("Invalid length");}
|
||||
int curIndex = 0;
|
||||
while(true){
|
||||
// Log.i("t", String.valueOf(curIndex));
|
||||
final int length = fileEditor.fromBytes(fileEditor.getByteBlock(bytes, curIndex, curIndex+2), 2);
|
||||
final int type = bytes[curIndex+2] & 0xFF;
|
||||
|
||||
if(length == 0){
|
||||
curIndex += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
final byte[] block;
|
||||
|
||||
try {
|
||||
block = fileEditor.getByteBlock(bytes, curIndex + 3, curIndex + length + 3);
|
||||
} catch(Exception e){
|
||||
throw new byteParsingExeption("Array out of bounds");
|
||||
}
|
||||
|
||||
switch(type){
|
||||
case 0:
|
||||
boolObject bo = new boolObject();
|
||||
bo.val = block[0] == (byte) 1;
|
||||
objects.add(bo);
|
||||
break;
|
||||
case 1:
|
||||
intObject io = new intObject();
|
||||
io.num = fileEditor.fromBytes(block, length);
|
||||
objects.add(io);
|
||||
break;
|
||||
case 2:
|
||||
stringObject so = new stringObject();
|
||||
so.str = unBlankStrNull(new String(block, StandardCharsets.UTF_8));
|
||||
objects.add(so);
|
||||
break;
|
||||
case 3:
|
||||
BuiltByteParser int_bbp = new BuiltByteParser(block);
|
||||
ArrayList<parsedObject> intArrayObjects = int_bbp.parse();
|
||||
|
||||
int[] intArr = new int[intArrayObjects.size()];
|
||||
|
||||
for(int i = 0; i < intArrayObjects.size(); i ++){
|
||||
intArr[i] = (int) intArrayObjects.get(i).get();
|
||||
}
|
||||
|
||||
intArrayObject ia = new intArrayObject();
|
||||
ia.arr = intArr;
|
||||
objects.add(ia);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
BuiltByteParser str_bbp = new BuiltByteParser(block);
|
||||
ArrayList<parsedObject> strArrayObjects = str_bbp.parse();
|
||||
|
||||
String[] StringArr = new String[strArrayObjects.size()];
|
||||
|
||||
for(int i = 0; i < strArrayObjects.size(); i ++){
|
||||
StringArr[i] = (String) strArrayObjects.get(i).get();
|
||||
}
|
||||
|
||||
stringArrayObject sa = new stringArrayObject();
|
||||
sa.arr = StringArr;
|
||||
objects.add(sa);
|
||||
break;
|
||||
default:
|
||||
rawObject ro = new rawObject(type);
|
||||
ro.bytes = block;
|
||||
objects.add(ro);
|
||||
break;
|
||||
}
|
||||
|
||||
curIndex += length + 3;
|
||||
|
||||
if(curIndex == bytes.length){
|
||||
break;
|
||||
}else if(curIndex > bytes.length){
|
||||
throw new byteParsingExeption("Block length problem");
|
||||
}
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ByteBuilder {
|
||||
public static final int bool_id = 0;
|
||||
public static final int int_id = 1;
|
||||
public static final int string_id = 2;
|
||||
public static final int int_arr_id = 3;
|
||||
public static final int string_arr_id = 4;
|
||||
|
||||
ArrayList<byteType> bytesToBuild = new ArrayList<>();
|
||||
|
||||
public class buildingException extends Exception {
|
||||
public buildingException() {}
|
||||
public buildingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class byteType {
|
||||
public abstract byte getType();
|
||||
public abstract int length();
|
||||
public abstract byte[] build();
|
||||
}
|
||||
|
||||
public static String blankStrNull(String str){
|
||||
if(str.isEmpty() || str.isEmpty()){
|
||||
return "ƒ";
|
||||
}
|
||||
else return str;
|
||||
}
|
||||
|
||||
private class boolType extends byteType {
|
||||
public boolean val;
|
||||
public byte getType(){return bool_id;}
|
||||
public int length(){return 1;}
|
||||
public byte[] build(){
|
||||
return new byte[]{(byte) (val ? 1 : 0)};
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuilder addBool(boolean n) throws buildingException {
|
||||
boolType boolType = new boolType();
|
||||
boolType.val = n;
|
||||
|
||||
bytesToBuild.add(boolType);
|
||||
return this;
|
||||
}
|
||||
|
||||
private class intType extends byteType {
|
||||
public int precision;
|
||||
public int num;
|
||||
public byte getType(){return int_id;}
|
||||
public int length(){return precision;}
|
||||
public byte[] build(){
|
||||
return fileEditor.toBytes(num, precision);
|
||||
}
|
||||
}
|
||||
private int getLeastBytePrecision(int num){
|
||||
if(num <= 1){return 1;}
|
||||
return (int) Math.ceil(Math.log(Math.abs(num))/Math.log(8));
|
||||
}
|
||||
public ByteBuilder addInt(int num) throws buildingException {
|
||||
// Get closest number of bytes
|
||||
int precision = getLeastBytePrecision(num);
|
||||
return addInt(num, precision);
|
||||
}
|
||||
public ByteBuilder addInt(int num, int precision) throws buildingException {
|
||||
if(precision <= 0){throw new buildingException("Invalid precision: " + precision);}
|
||||
|
||||
if(precision > 65536){throw new buildingException("Precision too large (greter than 65536)");}
|
||||
if(precision < getLeastBytePrecision(num)){throw new buildingException("Precision too small");}
|
||||
|
||||
if(num > Integer.MAX_VALUE){throw new buildingException("Integer overflow");}
|
||||
if(num < Integer.MIN_VALUE){throw new buildingException("Integer overflow");}
|
||||
|
||||
intType intType = new intType();
|
||||
intType.num = num;
|
||||
intType.precision = precision;
|
||||
|
||||
bytesToBuild.add(intType);
|
||||
return this;
|
||||
}
|
||||
|
||||
private class stringType extends byteType {
|
||||
public byte[] bytes;
|
||||
public byte getType(){return string_id;}
|
||||
public int length(){return bytes.length;}
|
||||
public byte[] build(){
|
||||
return bytes;
|
||||
// return str.getBytes(charset);
|
||||
}
|
||||
}
|
||||
public ByteBuilder addString(String str) throws buildingException {
|
||||
str = blankStrNull(str);
|
||||
if(str.length() > 65536){throw new buildingException("String too long (greater than 65536)");}
|
||||
|
||||
stringType stringType = new stringType();
|
||||
// To get the length correctly, the string bytes need to be precalculated
|
||||
stringType.bytes = str.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
bytesToBuild.add(stringType);
|
||||
return this;
|
||||
}
|
||||
|
||||
private class intArrayType extends byteType {
|
||||
public byte[] bytes;
|
||||
public byte getType(){return int_arr_id;}
|
||||
public int length(){return bytes.length;}
|
||||
public byte[] build(){
|
||||
return bytes;
|
||||
// return str.getBytes(charset);
|
||||
}
|
||||
}
|
||||
public ByteBuilder addIntArray(int[] arr) throws buildingException {
|
||||
intArrayType intArrayType = new intArrayType();
|
||||
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
|
||||
for(int i = 0; i < arr.length; i++){
|
||||
bb.addInt(arr[i]);
|
||||
}
|
||||
|
||||
intArrayType.bytes = bb.build();
|
||||
|
||||
bytesToBuild.add(intArrayType);
|
||||
return this;
|
||||
}
|
||||
|
||||
private class stringArrayType extends byteType {
|
||||
public byte[] bytes;
|
||||
public byte getType(){return string_arr_id;}
|
||||
public int length(){return bytes.length;}
|
||||
public byte[] build(){
|
||||
return bytes;
|
||||
// return str.getBytes(charset);
|
||||
}
|
||||
}
|
||||
public ByteBuilder addStringArray(String[] arr) throws buildingException {
|
||||
stringArrayType stringArrayType = new stringArrayType();
|
||||
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
|
||||
for(int i = 0; i < arr.length; i++){
|
||||
bb.addString(arr[i]);
|
||||
}
|
||||
|
||||
stringArrayType.bytes = bb.build();
|
||||
|
||||
bytesToBuild.add(stringArrayType);
|
||||
return this;
|
||||
}
|
||||
|
||||
private class rawType extends byteType {
|
||||
public int type;
|
||||
public byte[] bytes;
|
||||
public byte getType(){return (byte) type;}
|
||||
public int length(){return bytes.length;}
|
||||
public byte[] build(){
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuilder addRaw(int type, byte[] bytes) throws buildingException {
|
||||
if(bytes.length > 65536){throw new buildingException("Byte array length to long (greater than 65536)");}
|
||||
|
||||
rawType rawType = new rawType();
|
||||
rawType.type = type;
|
||||
rawType.bytes = bytes;
|
||||
bytesToBuild.add(rawType);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] build() throws buildingException {
|
||||
if(bytesToBuild.size() == 0){throw new buildingException("Cannot build null data");}
|
||||
|
||||
int length = bytesToBuild.size() * 3;
|
||||
for(byteType bt : bytesToBuild){
|
||||
length += bt.length();
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[length];
|
||||
int bytesFilled = 0;
|
||||
|
||||
for(byteType bt : bytesToBuild){
|
||||
|
||||
byte[] blockLength = fileEditor.toBytes(bt.length(), 2);
|
||||
|
||||
bytes[bytesFilled] = blockLength[0];
|
||||
bytesFilled += 1;
|
||||
bytes[bytesFilled] = blockLength[1];
|
||||
bytesFilled += 1;
|
||||
bytes[bytesFilled] = bt.getType();
|
||||
bytesFilled += 1;
|
||||
|
||||
// if(bt.length == 0)
|
||||
// continue;
|
||||
|
||||
int i = 1;
|
||||
byte[] newBytes = bt.build();
|
||||
for(byte b : newBytes){
|
||||
// Log.i("i", (bytesFilled+1) + "/" + length + " (" + i + "/" + bt.length() + ")");
|
||||
bytes[bytesFilled] = b;
|
||||
bytesFilled += 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
import com.ridgebotics.ridgescout.scoutingData.fields;
|
||||
import com.ridgebotics.ridgescout.scoutingData.transfer.transferType;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
|
||||
public class DataManager {
|
||||
public static String evcode;
|
||||
public static frcEvent event;
|
||||
public static void reload_event(){
|
||||
evcode = getevcode();
|
||||
event = frcEvent.decode(fileEditor.readFile(evcode + ".eventdata"));
|
||||
}
|
||||
|
||||
public static String getevcode() {
|
||||
return latestSettings.settings.get_evcode();
|
||||
}
|
||||
|
||||
public static inputType[][] match_values;
|
||||
public static inputType[] match_latest_values;
|
||||
public static transferType[][] match_transferValues;
|
||||
public static void reload_match_fields(){
|
||||
match_values = fields.load(fields.matchFieldsFilename);
|
||||
match_latest_values = match_values[match_values.length-1];
|
||||
match_transferValues = transferType.get_transfer_values(match_values);
|
||||
}
|
||||
|
||||
public static inputType[][] pit_values;
|
||||
public static inputType[] pit_latest_values;
|
||||
public static transferType[][] pit_transferValues;
|
||||
public static void reload_pit_fields(){
|
||||
pit_values = fields.load(fields.pitsFieldsFilename);
|
||||
pit_latest_values = pit_values[pit_values.length-1];
|
||||
pit_transferValues = transferType.get_transfer_values(pit_values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class JSONUtil {
|
||||
public static JSONArray sort(JSONArray array, Comparator c){
|
||||
List asList = new ArrayList(array.length());
|
||||
for (int i=0; i<array.length(); i++){
|
||||
asList.add(array.opt(i));
|
||||
}
|
||||
asList.sort(c);
|
||||
JSONArray res = new JSONArray();
|
||||
for (Object o : asList){
|
||||
res.put(o);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.TableLayout;
|
||||
|
||||
public class ReorderableTableLayout extends TableLayout {
|
||||
private boolean reorderingEnabled = false;
|
||||
private int draggedRowIndex = -1;
|
||||
private float lastY;
|
||||
private List<View> rows;
|
||||
private List<Integer> reorderedIndices;
|
||||
private int rowHeight;
|
||||
|
||||
public ReorderableTableLayout(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ReorderableTableLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
rows = new ArrayList<>();
|
||||
reorderedIndices = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (!reorderingEnabled) {
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
lastY = ev.getY();
|
||||
draggedRowIndex = getRowIndexAtY(lastY);
|
||||
if (draggedRowIndex != -1) {
|
||||
View draggedRow = getChildAt(draggedRowIndex);
|
||||
rowHeight = draggedRow.getHeight();
|
||||
saveOriginalOrder();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child) {
|
||||
super.addView(child);
|
||||
reorderedIndices.add(reorderedIndices.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllViews() {
|
||||
super.removeAllViews();
|
||||
reorderedIndices.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (!reorderingEnabled || draggedRowIndex == -1) {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
float currentY = event.getY();
|
||||
int targetIndex = getRowIndexAtY(currentY);
|
||||
View child = getChildAt(targetIndex);
|
||||
if(child != null)
|
||||
getChildAt(targetIndex).callOnClick();
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (targetIndex != -1 && targetIndex != draggedRowIndex) {
|
||||
updateRowOrder(draggedRowIndex, targetIndex);
|
||||
draggedRowIndex = targetIndex;
|
||||
}
|
||||
lastY = currentY;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
draggedRowIndex = -1;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getRowIndexAtY(float y) {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
View child = getChildAt(i);
|
||||
if (y >= child.getTop() && y <= child.getBottom()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void saveOriginalOrder() {
|
||||
rows.clear();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
rows.add(getChildAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRowOrder(int fromIndex, int toIndex) {
|
||||
saveOriginalOrder();
|
||||
if (fromIndex < toIndex) {
|
||||
for (int i = fromIndex; i < toIndex; i++) {
|
||||
Collections.swap(rows, i, i + 1);
|
||||
Collections.swap(reorderedIndices, i, i + 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = fromIndex; i > toIndex; i--) {
|
||||
Collections.swap(rows, i, i - 1);
|
||||
Collections.swap(reorderedIndices, i, i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
removeAllViewsInLayout();
|
||||
for (View view : rows) {
|
||||
addViewInLayout(view, -1, view.getLayoutParams(), true);
|
||||
}
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setReorderingEnabled(boolean enabled) {
|
||||
reorderingEnabled = enabled;
|
||||
}
|
||||
|
||||
public List<Integer> getReorderedIndexes() {
|
||||
return reorderedIndices;
|
||||
}
|
||||
|
||||
public void removeElement(int unshuffledindex){
|
||||
System.out.println(Arrays.toString(new List[]{reorderedIndices}));
|
||||
|
||||
reorderedIndices.remove(unshuffledindex);
|
||||
|
||||
for (int i = 0; i < reorderedIndices.size(); i++) {
|
||||
if(reorderedIndices.get(i) > unshuffledindex)
|
||||
reorderedIndices.set(i, reorderedIndices.get(i) - 1);
|
||||
}
|
||||
|
||||
System.out.println(Arrays.toString(new List[]{reorderedIndices}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
public class RequestTask extends AsyncTask<String, String, String> {
|
||||
|
||||
private Function<String, String> resultFunction = null;
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... uri) {
|
||||
try {
|
||||
URL url = new URL(uri[0]);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
String[] headers = uri[1].split(", ");
|
||||
for(String header : headers){
|
||||
String[] split = header.split(": ");
|
||||
conn.setRequestProperty(split[0], split[1]);
|
||||
}
|
||||
if(conn.getResponseCode() == HttpsURLConnection.HTTP_OK){
|
||||
// ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
return readStream(conn.getInputStream());
|
||||
// Do normal input or output stream reading
|
||||
}
|
||||
else {
|
||||
return null; // See documentation for more info on response handling
|
||||
}
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static String readStream(InputStream in) {
|
||||
BufferedReader reader = null;
|
||||
StringBuilder response = new StringBuilder();
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.toString();
|
||||
}
|
||||
|
||||
public void onResult(Function<String, String> func) {
|
||||
this.resultFunction = func;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
super.onPostExecute(result);
|
||||
if(resultFunction != null){
|
||||
resultFunction.apply(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.tensorflow.lite.support.label.Category;
|
||||
import org.tensorflow.lite.task.text.nlclassifier.NLClassifier;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SentimentAnalysis {
|
||||
private static NLClassifier textClassifier;
|
||||
|
||||
public static void init(Context context){
|
||||
try {
|
||||
textClassifier = NLClassifier.createFromFile(context, "text_classification_v2.tflite");
|
||||
} catch (Exception e) {
|
||||
AlertManager.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface resultCallback {
|
||||
public void onFinish(float data);
|
||||
}
|
||||
|
||||
public static void analyse(String input, resultCallback result){
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<Category> results = textClassifier.classify(input);
|
||||
|
||||
for(int i = 0; i < results.size(); i++){
|
||||
Category cat = results.get(i);
|
||||
switch (cat.getLabel()){
|
||||
case "Positive":
|
||||
result.onFinish(cat.getScore());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static float analyse_sync(String input){
|
||||
List<Category> results = textClassifier.classify(input);
|
||||
|
||||
for(int i = 0; i < results.size(); i++){
|
||||
Category cat = results.get(i);
|
||||
switch (cat.getLabel()){
|
||||
case "Positive":
|
||||
return cat.getScore();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SharePrompt {
|
||||
public static void shareContent(Context context, String fileName, String content, String mimeType) {
|
||||
shareContent(context, fileName, content.getBytes(), mimeType);
|
||||
}
|
||||
|
||||
public static void shareContent(Context context, String fileName, byte[] content, String mimeType) {
|
||||
try {
|
||||
File file = new File(context.getCacheDir(), fileName);
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(content);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
|
||||
import com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public final class fileEditor {
|
||||
private final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
||||
public static final byte internalDataVersion = 0x01;
|
||||
public static final int maxCompressedBlockSize = 4096;
|
||||
|
||||
|
||||
|
||||
public static String binaryVisualize(byte[] bytes){
|
||||
String returnStr = "";
|
||||
for (byte aByte : bytes) {
|
||||
for (int b = 7; b >= 0; b--) {
|
||||
returnStr += String.valueOf((aByte >> b) & 1);
|
||||
}
|
||||
returnStr += " (" + (int) aByte + ")\n";
|
||||
}
|
||||
return returnStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static char byteToChar(int num){
|
||||
return new String(toBytes(num, 1), StandardCharsets.ISO_8859_1).charAt(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static byte[] toBytes(int num, int byteCount){
|
||||
if(num > (Math.pow(2,byteCount*8)-1)){
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
byte[] bytes = new byte[byteCount];
|
||||
for(int i=0;i<byteCount;i++){
|
||||
bytes[i] = (byte)(num >> (i*8));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int fromBytes(byte[] bytes, int byteCount){
|
||||
int returnInt = 0;
|
||||
for(int i=0;i<byteCount;i++){
|
||||
returnInt |= (bytes[i] & 0xFF) << (i*8);
|
||||
}
|
||||
return returnInt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int byteFromChar(char c){
|
||||
byte[] bytes = (String.valueOf(c)).getBytes(Charset.defaultCharset());
|
||||
return Byte.toUnsignedInt(bytes[0]);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] getByteBlock(byte[] bytes, int start, int end){
|
||||
end = Math.min(end, bytes.length);
|
||||
|
||||
byte[] dataBlock = new byte[end-start];
|
||||
|
||||
for(int a=start;a<end;a++){
|
||||
// Log.i("test", start+", "+a+", "+end);
|
||||
dataBlock[a-start] = bytes[a];
|
||||
}
|
||||
|
||||
return dataBlock;
|
||||
}
|
||||
|
||||
public static byte[] compress(byte[] input) {
|
||||
Deflater deflater = new Deflater();
|
||||
deflater.setInput(input);
|
||||
deflater.finish();
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[maxCompressedBlockSize];
|
||||
|
||||
while (!deflater.finished()) {
|
||||
int compressedSize = deflater.deflate(buffer);
|
||||
outputStream.write(buffer, 0, compressedSize);
|
||||
}
|
||||
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] blockCompress(byte[] inputData) {
|
||||
List<byte[]> compiledData = new ArrayList<>();
|
||||
|
||||
for(int i=0;i<Math.ceil((double) inputData.length / fileEditor.maxCompressedBlockSize);i++){
|
||||
final int start = i*fileEditor.maxCompressedBlockSize;
|
||||
int end = ((i+1)*fileEditor.maxCompressedBlockSize);
|
||||
if(end > inputData.length) {
|
||||
end = inputData.length;
|
||||
}
|
||||
|
||||
byte[] dataBlock = fileEditor.getByteBlock(inputData, start, end);
|
||||
|
||||
final byte[] compressedBlock = fileEditor.compress(dataBlock);
|
||||
|
||||
compiledData.add(fileEditor.toBytes(compressedBlock.length, 2));
|
||||
compiledData.add(compressedBlock);
|
||||
}
|
||||
return combineByteArrays(compiledData);
|
||||
}
|
||||
|
||||
public static byte[] blockUncompress(byte[] data) throws DataFormatException {
|
||||
List<byte[]> uncompressedData = new ArrayList<>();
|
||||
int curIndex = 0;
|
||||
while (curIndex < data.length) {
|
||||
|
||||
final int blockLength = fileEditor.fromBytes(fileEditor.getByteBlock(data, curIndex, curIndex + 2), 2);
|
||||
|
||||
uncompressedData.add(
|
||||
decompress(
|
||||
fileEditor.getByteBlock(data, curIndex + 2, curIndex + blockLength + 2)
|
||||
)
|
||||
);
|
||||
|
||||
curIndex += blockLength + 2;
|
||||
}
|
||||
return combineByteArrays(uncompressedData);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] decompress(byte[] input) throws DataFormatException {
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.setInput(input);
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[maxCompressedBlockSize];
|
||||
|
||||
|
||||
while (inflater.getRemaining() > 0) {
|
||||
int decompressedSize = inflater.inflate(buffer);
|
||||
if (decompressedSize == 0) {
|
||||
break;
|
||||
}
|
||||
outputStream.write(buffer, 0, decompressedSize);
|
||||
}
|
||||
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] combineByteArrays(List<byte[]> arrayList) {
|
||||
// Calculate the total length of the combined array
|
||||
int totalLength = arrayList.stream()
|
||||
.mapToInt(array -> array.length)
|
||||
.sum();
|
||||
|
||||
// Create a new byte array with the total length
|
||||
byte[] result = new byte[totalLength];
|
||||
|
||||
// Copy each array into the result array
|
||||
int offset = 0;
|
||||
for (byte[] array : arrayList) {
|
||||
System.arraycopy(array, 0, result, offset, array.length);
|
||||
offset += array.length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean writeFile(String filepath, byte[] data) {
|
||||
try {
|
||||
FileOutputStream output = new FileOutputStream(baseDir + filepath);
|
||||
output.write(data);
|
||||
output.close();
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean createFile(String filepath){
|
||||
if(fileExist(filepath)){
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
File file = new File(baseDir + filepath);
|
||||
return file.createNewFile();
|
||||
}
|
||||
catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean fileExist(String path){
|
||||
File f = new File(baseDir + path);
|
||||
return f.exists() && !f.isDirectory();
|
||||
}
|
||||
|
||||
public static byte[] readFile(String path){
|
||||
return readFileExact(baseDir + path);
|
||||
}
|
||||
public static byte[] readFileExact(String path){
|
||||
File file = new File(path);
|
||||
int size = (int) file.length();
|
||||
byte[] bytes = new byte[size];
|
||||
try {
|
||||
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
|
||||
buf.read(bytes, 0, bytes.length);
|
||||
buf.close();
|
||||
return bytes;
|
||||
} catch (FileNotFoundException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String intSplit(int[] intArr, String splitStr){
|
||||
String returnStr = "";
|
||||
for(int i=0;i<intArr.length;i++){
|
||||
returnStr += String.valueOf(intArr[i]);
|
||||
if(i != intArr.length-1){
|
||||
returnStr += splitStr;
|
||||
}
|
||||
}
|
||||
return returnStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean setEvent(frcEvent event){
|
||||
final String filename = (event.eventCode + ".eventdata");
|
||||
|
||||
if(latestSettings.settings.get_evcode().equals("unset")){
|
||||
latestSettings.settings.set_evcode(event.eventCode);
|
||||
}
|
||||
|
||||
return writeFile(filename, event.encode());
|
||||
}
|
||||
|
||||
public static ArrayList<String> getEventList(){
|
||||
File f = new File(baseDir);
|
||||
File[] files = f.listFiles();
|
||||
ArrayList<String> outFiles = new ArrayList<>();
|
||||
if(files == null){return outFiles;}
|
||||
for (File file : files) {
|
||||
if(!file.isDirectory() && file.getName().endsWith(".eventdata")) {
|
||||
outFiles.add(file.getName().substring(0,file.getName().length()-10));
|
||||
}
|
||||
}
|
||||
Collections.sort(outFiles);
|
||||
return outFiles;
|
||||
}
|
||||
|
||||
|
||||
public static String[] getMatchesByTeamNum(String evcode, int teamNum){
|
||||
File f = new File(baseDir);
|
||||
File[] files = f.listFiles();
|
||||
|
||||
ArrayList<String> outFiles = new ArrayList<>();
|
||||
|
||||
if(files == null){return new String[0];}
|
||||
|
||||
for (File file : files) {
|
||||
String name = file.getName();
|
||||
if(!file.isDirectory() && name.startsWith(evcode+"-") && name.endsWith("-"+teamNum+".matchscoutdata")) {
|
||||
outFiles.add(file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
String[] filenames = outFiles.toArray(new String[0]);
|
||||
|
||||
Arrays.sort(filenames, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return Integer.valueOf(o1.split("-")[1]).compareTo(Integer.valueOf(o2.split("-")[1]));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return filenames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static String[] getEventFiles(String evcode){
|
||||
File f = new File(baseDir);
|
||||
File[] files = f.listFiles();
|
||||
|
||||
if(files == null){return new String[0];}
|
||||
|
||||
ArrayList<String> outFiles = new ArrayList<>();
|
||||
outFiles.add("matches.fields");
|
||||
outFiles.add("pits.fields");
|
||||
// outFiles.add(evcode + ".eventdata");
|
||||
|
||||
for (File file : files) {
|
||||
String name = file.getName();
|
||||
if(!file.isDirectory() && name.startsWith(evcode)) {
|
||||
outFiles.add(file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
String[] filenames = outFiles.toArray(new String[0]);
|
||||
|
||||
Arrays.sort(filenames, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
try {
|
||||
if(!o1.contains("-") || !o2.contains("-"))
|
||||
return 0;
|
||||
return Integer.valueOf(o1.split("-")[1]).compareTo(Integer.valueOf(o2.split("-")[1]));
|
||||
} catch (Exception e){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return filenames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean setTeams(Context context, String key, ArrayList<frcTeam> teams){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user