Attempt to get F-Droid working

This commit is contained in:
Astatin3
2024-09-15 22:47:45 -06:00
parent 138158e2ee
commit 3f88c9a05e
74 changed files with 372 additions and 366 deletions
@@ -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);
}
}
@@ -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();
}
}
@@ -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();
}
}
}
@@ -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();
}
}
@@ -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();
}
}
}
@@ -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();
}
}
@@ -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;
}
}