From dded2773cf6f71da9de43a6b72a0c15679be85f3 Mon Sep 17 00:00:00 2001 From: Astatin3 <77305074+Astatin3@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:49:16 -0600 Subject: [PATCH] Add file bundles. Start work on ftp support. --- README.md | 11 +- app/src/main/AndroidManifest.xml | 9 +- .../scoutingapp2025/MainActivity.java | 23 ++++ .../types/input/dropdownType.java | 2 +- .../types/input/sliderType.java | 3 +- .../types/input/tallyType.java | 5 +- .../scoutingapp2025/types/input/textType.java | 1 + .../ui/transfer/CSVExport.java | 26 +---- .../ui/transfer/FileBundle.java | 107 ++++++++++++++++++ .../ui/transfer/TransferFragment.java | 15 ++- .../ui/transfer/TransferSelectorFragment.java | 8 +- .../scoutingapp2025/utility/SharePrompt.java | 37 ++++++ .../scoutingapp2025/utility/fileEditor.java | 5 +- app/src/main/res/layout/fragment_transfer.xml | 26 ++--- .../res/layout/fragment_transfer_selector.xml | 6 +- 15 files changed, 223 insertions(+), 61 deletions(-) create mode 100644 app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/FileBundle.java create mode 100644 app/src/main/java/com/astatin3/scoutingapp2025/utility/SharePrompt.java diff --git a/README.md b/README.md index 24ce9af..5fc85f4 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,25 @@ Ridgebotics 2025 scouting app in Android - Make the "Report" menu, A tool that lets users select data to display from the the teams and compare menus. - Make practice mode #### Data Analysis: -- Statbotics intigration +- Statbotics intigration??? - AI overview of scouting data for a team??? - Make the "Compare" menu, cross comparing team's stats. #### Functionality: -- Make the system for blank and unselected fields better. - Add more types of data fields. -- Make server software to allow for easy sync over wifi - Test the scouting app - Deploy to F-Droid ## In Progress: #### Scouting: -- When a field is created, make updated scouting data return null values, not the default value -- Fix scouting offset bug #### Data Analysis: #### Functionality: - +- Make server software to allow for easy sync over wifi - FTP ## Done: #### Scouting: - Add an "unselect" option to all of the scouting fields +- When a field is created, make updated scouting data return null values, not the default value +- Fix scouting offset bug #### Data Analysis: - Add "history" view type to the teams view menu. - Sentiment analysis of text input type @@ -39,3 +37,4 @@ Ridgebotics 2025 scouting app in Android - Bluetooth data sync - Formalize error messages & stacktraces - Make pit and match data field builder UIs. I don't want to have to keep editing a variable +- Make the system for blank and unselected fields better. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0756344..3ceff53 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,9 @@ android:name="android.hardware.camera" android:required="true" /> + + + @@ -36,10 +39,14 @@ android:label="@string/app_name"> - + + + + entries = new ArrayList<>(); for (int a = 0; a < data.length; a++) { - if(data[a] == null) continue; + if(data[a].isNull()) continue; entries.add( new Entry(a, diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/sliderType.java b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/sliderType.java index 0016519..85dd479 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/sliderType.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/sliderType.java @@ -186,7 +186,7 @@ public class sliderType extends inputType { int[] values = new int[max-min+1]; for (int i = 0; i < data.length; i++) - if(intType.isNull((int) data[i].get())) + if(!data[i].isNull()) values[(int) data[i].get()-min]++; @@ -262,6 +262,7 @@ public class sliderType extends inputType { List entries = new ArrayList<>(); for (int i = 0; i < data.length; i++){ if(data[i] == null) continue; + if(data[i].isNull()) continue; entries.add(new Entry(i, (float)(int) data[i].get())); } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java index a2643f2..6339b68 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/tallyType.java @@ -98,7 +98,7 @@ public class tallyType extends inputType { public void add_individual_view(LinearLayout parent, dataType data){ - if((int)data.get() == 0) return; + if(data.isNull()) return; TextView tv = new TextView(parent.getContext()); tv.setLayoutParams(new FrameLayout.LayoutParams( @@ -176,7 +176,7 @@ public class tallyType extends inputType { int[] values = new int[max-min+1]; for (int i = 0; i < data.length; i++) - if(intType.isNull((int) data[i].get())) + if(data[i] != null && data[i].isNull()) values[(int) data[i].get()-min]++; @@ -255,6 +255,7 @@ public class tallyType extends inputType { List entries = new ArrayList<>(); for (int i = 0; i < data.length; i++){ if(data[i] == null) continue; + if(data[i].isNull()) continue; entries.add(new Entry(i, (float)(int) data[i].get())); } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java index e932ffc..4b4dd5c 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/types/input/textType.java @@ -183,6 +183,7 @@ public class textType extends inputType { List entries = new ArrayList<>(); for (int i = 0; i < data.length; i++) { if(data[i] == null) continue; + if(data[i].isNull()) continue; entries.add( new Entry(i, diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/CSVExport.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/CSVExport.java index 99208b7..78e3060 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/CSVExport.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/CSVExport.java @@ -4,6 +4,7 @@ import static com.astatin3.scoutingapp2025.utility.DataManager.evcode; import static com.astatin3.scoutingapp2025.utility.DataManager.event; import static com.astatin3.scoutingapp2025.utility.DataManager.match_latest_values; import static com.astatin3.scoutingapp2025.utility.DataManager.pit_latest_values; +import static com.astatin3.scoutingapp2025.utility.SharePrompt.shareContent; import android.content.Context; import android.content.Intent; @@ -122,29 +123,4 @@ public class CSVExport { shareContent(c, evcode+"-pits.csv", data, "text/plain"); } - - - - - - - public static void shareContent(Context context, String fileName, String content, String mimeType) { - try { - File file = new File(context.getCacheDir(), fileName); - FileOutputStream fos = new FileOutputStream(file); - fos.write(content.getBytes()); - fos.close(); - - Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file); - - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType(mimeType); - shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri); - shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - context.startActivity(Intent.createChooser(shareIntent, "Share using")); - } catch (IOException e) { - AlertManager.error(e); - } - } } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/FileBundle.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/FileBundle.java new file mode 100644 index 0000000..76155c2 --- /dev/null +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/FileBundle.java @@ -0,0 +1,107 @@ +package com.astatin3.scoutingapp2025.ui.transfer; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import com.astatin3.scoutingapp2025.MainActivity; +import com.astatin3.scoutingapp2025.types.file; +import com.astatin3.scoutingapp2025.utility.AlertManager; +import com.astatin3.scoutingapp2025.utility.BuiltByteParser; +import com.astatin3.scoutingapp2025.utility.ByteBuilder; +import com.astatin3.scoutingapp2025.utility.DataManager; +import com.astatin3.scoutingapp2025.utility.SharePrompt; +import com.astatin3.scoutingapp2025.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 parsedObjectList = bbp.parse(); + + ArrayList 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); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferFragment.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferFragment.java index f22a947..8f1c371 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferFragment.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferFragment.java @@ -34,12 +34,14 @@ public class TransferFragment extends Fragment { 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); @@ -114,19 +116,21 @@ public class TransferFragment extends Fragment { private void start_upload() { FileSelectorFragment.setOnSelect(data -> { - CodeGeneratorView.setData(data); - BluetoothSenderFragment.set_data(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 onSelectWifi(TransferSelectorFragment self) {} + public void onSelectFileBundle(TransferSelectorFragment self) { + FileBundle.send(data, getContext()); + } }); findNavController(this).navigate(R.id.action_navigation_file_selector_to_navigation_transfer_selector); }); @@ -137,6 +141,7 @@ public class TransferFragment extends Fragment { private void start_download(){ + TransferSelectorFragment.setOnSelect(new TransferSelectorFragment.onSelect() { @Override public void onSelectCodes(TransferSelectorFragment self) { @@ -149,7 +154,9 @@ public class TransferFragment extends Fragment { } @Override - public void onSelectWifi(TransferSelectorFragment self) {} + public void onSelectFileBundle(TransferSelectorFragment self) { + FileBundle.receive(getActivity()); + } }); findNavController(this).navigate(R.id.action_navigation_transfer_to_navigation_transfer_selector); } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferSelectorFragment.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferSelectorFragment.java index ef69111..5c41ad6 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferSelectorFragment.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/TransferSelectorFragment.java @@ -14,7 +14,7 @@ import com.astatin3.scoutingapp2025.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 onSelectWifi(TransferSelectorFragment self) {}}; + 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; @@ -23,7 +23,7 @@ public class TransferSelectorFragment extends Fragment { public interface onSelect { void onSelectCodes(TransferSelectorFragment self); void onSelectBluetooth(TransferSelectorFragment self); - void onSelectWifi(TransferSelectorFragment self); + void onSelectFileBundle(TransferSelectorFragment self); } FragmentTransferSelectorBinding binding; @@ -38,8 +38,8 @@ public class TransferSelectorFragment extends Fragment { onselect.onSelectBluetooth(this); }); - binding.wifiButton.setOnClickListener(view -> { - onselect.onSelectWifi(this); + binding.fileBundleButton.setOnClickListener(view -> { + onselect.onSelectFileBundle(this); }); return binding.getRoot(); diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/utility/SharePrompt.java b/app/src/main/java/com/astatin3/scoutingapp2025/utility/SharePrompt.java new file mode 100644 index 0000000..07d5870 --- /dev/null +++ b/app/src/main/java/com/astatin3/scoutingapp2025/utility/SharePrompt.java @@ -0,0 +1,37 @@ +package com.astatin3.scoutingapp2025.utility; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import androidx.core.content.FileProvider; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +public class SharePrompt { + public static void shareContent(Context context, String fileName, String content, String mimeType) { + shareContent(context, fileName, content.getBytes(), mimeType); + } + + public static void shareContent(Context context, String fileName, byte[] content, String mimeType) { + try { + File file = new File(context.getCacheDir(), fileName); + FileOutputStream fos = new FileOutputStream(file); + fos.write(content); + fos.close(); + + Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file); + + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType(mimeType); + shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + context.startActivity(Intent.createChooser(shareIntent, "Share using")); + } catch (IOException e) { + AlertManager.error(e); + } + } +} diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/utility/fileEditor.java b/app/src/main/java/com/astatin3/scoutingapp2025/utility/fileEditor.java index 7e45b27..c0718ff 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/utility/fileEditor.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/utility/fileEditor.java @@ -228,7 +228,10 @@ public final class fileEditor { } public static byte[] readFile(String path){ - File file = new File(baseDir + path); + return readFileExact(baseDir + path); + } + public static byte[] readFileExact(String path){ + File file = new File(path); int size = (int) file.length(); byte[] bytes = new byte[size]; try { diff --git a/app/src/main/res/layout/fragment_transfer.xml b/app/src/main/res/layout/fragment_transfer.xml index dd984f2..2a78f1b 100644 --- a/app/src/main/res/layout/fragment_transfer.xml +++ b/app/src/main/res/layout/fragment_transfer.xml @@ -33,28 +33,28 @@ android:layout_height="wrap_content" android:text="Upload" android:textSize="34sp" - app:layout_constraintBottom_toTopOf="@+id/downloadButton" + app:layout_constraintBottom_toTopOf="@+id/CSVButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> -