diff --git a/app/build.gradle b/app/build.gradle index abd3dc8..bb802aa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,8 +27,8 @@ android { applicationId "com.cpjd.roblu" minSdkVersion 19 targetSdkVersion 28 - versionCode 66 - versionName "4.5.8" + versionCode 67 + versionName "4.5.9" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" javaCompileOptions { @@ -80,7 +80,7 @@ android { } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(include: ['*.jar'], dir: 'libs') // since lombok is already used in this library, we don't need to add it again androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) @@ -89,12 +89,12 @@ dependencies { implementation('com.mikepenz:materialdrawer:5.9.0@aar') { transitive = true } - implementation "com.googlecode.json-simple:json-simple:1.1" implementation 'com.dlazaro66.qrcodereaderview:qrcodereaderview:2.0.3' implementation 'com.roughike:bottom-bar:2.1.1' implementation 'com.miguelcatalan:materialsearchview:1.4.0' implementation 'pub.devrel:easypermissions:0.2.1' - implementation 'com.google.guava:guava:24.1-android' // ignore this warning + implementation 'com.google.guava:guava:24.1-android' + // ignore this warning implementation 'com.jrummyapps:colorpicker:2.1.6' implementation 'com.github.infotech-group:CanvasView:release' implementation 'com.android.support:appcompat-v7:28.0.0' @@ -107,7 +107,9 @@ dependencies { implementation('com.mikepenz:aboutlibraries:5.9.5@aar') { transitive = true } implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3' - implementation "org.projectlombok:lombok:1.18.0" + //implementation 'org.projectlombok:lombok:1.18.0' + //implementation 'javax.annotation:jsr250-api:1.0' + //implementation 'com.googlecode.json-simple:json-simple:1.1' annotationProcessor 'org.projectlombok:lombok:1.18.0' - implementation 'javax.annotation:jsr250-api:1.0' + implementation files('libs/TBA-API-V3.jar') } diff --git a/app/libs/TBA-API-V3.jar b/app/libs/TBA-API-V3.jar new file mode 100644 index 0000000..ee83e35 Binary files /dev/null and b/app/libs/TBA-API-V3.jar differ diff --git a/app/libs/TBA-API.jar b/app/libs/TBA-API.jar deleted file mode 100644 index db29a06..0000000 Binary files a/app/libs/TBA-API.jar and /dev/null differ diff --git a/app/src/main/java/com/cpjd/roblu/csv/csvSheets/OurMatches.java b/app/src/main/java/com/cpjd/roblu/csv/csvSheets/OurMatches.java index fa6e72b..3a44b95 100644 --- a/app/src/main/java/com/cpjd/roblu/csv/csvSheets/OurMatches.java +++ b/app/src/main/java/com/cpjd/roblu/csv/csvSheets/OurMatches.java @@ -3,10 +3,8 @@ import android.os.StrictMode; -import com.cpjd.main.Settings; import com.cpjd.main.TBA; -import com.cpjd.models.Event; -import com.cpjd.models.Match; +import com.cpjd.models.standard.Match; import com.cpjd.roblu.models.RCheckout; import com.cpjd.roblu.models.REvent; import com.cpjd.roblu.models.RForm; @@ -58,23 +56,23 @@ public void generateSheet(XSSFSheet sheet, REvent event, RForm form, RTeam[] tea createCell(one, 6, "Team6"); // Determine event year - Settings.disableAll(); - Settings.GET_EVENT_MATCHES = true; + //Settings.disableAll(); + //Settings.GET_EVENT_MATCHES = true; try { - Event tbaEvent = new TBA().getEvent(event.getKey()); - for(Match m : tbaEvent.matches) { - if(m.doesMatchContainTeam(teamNumber) > 0) { + Match[] matches = new TBA().getMatches(event.getKey()); + for(Match m : matches) { + if(doesMatchContainTeam(m, teamNumber)) { Row row = createRow(sheet); setCellStyle(BorderStyle.THIN, IndexedColors.WHITE, IndexedColors.BLACK, true); - createCell(row, 0, String.valueOf(m.match_number)); + createCell(row, 0, String.valueOf(m.getMatchNumber())); setStyle(blue); - createCell(row, 1, m.blueTeams[0].replace("frc", "")); - createCell(row, 2, m.blueTeams[1].replace("frc", "")); - createCell(row, 3, m.blueTeams[2].replace("frc", "")); + createCell(row, 1, m.getBlue().getTeamKeys()[0].replace("frc", "")); + createCell(row, 2, m.getBlue().getTeamKeys()[0].replace("frc", "")); + createCell(row, 3, m.getBlue().getTeamKeys()[0].replace("frc", "")); setStyle(red); - createCell(row, 4, m.redTeams[0].replace("frc", "")); - createCell(row, 5, m.redTeams[1].replace("frc", "")); - createCell(row, 6, m.redTeams[2].replace("frc", "")); + createCell(row, 4, m.getRed().getTeamKeys()[0].replace("frc", "")); + createCell(row, 5, m.getRed().getTeamKeys()[0].replace("frc", "")); + createCell(row, 6, m.getRed().getTeamKeys()[0].replace("frc", "")); } } } catch(Exception e) { @@ -92,4 +90,24 @@ public String getSheetName() { public int getColumnWidth() { return 2000; } + private int getAlliancePosition(Match m, int teamNumber) { + for(int i = 0; i < m.getBlue().getTeamKeys().length; i++) { + if(m.getBlue().getTeamKeys()[i].equals("frc"+teamNumber)) return i + 4; + } + for(int i = 0; i < m.getRed().getTeamKeys().length; i++) { + if(m.getRed().getTeamKeys()[i].equals("frc"+teamNumber)) return i + 1; + } + + return -1; + } + + private boolean isOnWinningAlliance(Match m, int teamNumber) { + boolean redWinner = m.getWinningAlliance().toLowerCase().contains("red"); + return (redWinner && getAlliancePosition(m, teamNumber) <= 3) || (!redWinner && getAlliancePosition(m, teamNumber) >= 4); + } + + private boolean doesMatchContainTeam(Match m, int teamNumber) { + return getAlliancePosition(m, teamNumber) != -1; + } + } diff --git a/app/src/main/java/com/cpjd/roblu/tba/ImportEvent.java b/app/src/main/java/com/cpjd/roblu/tba/ImportEvent.java index 34735ca..76bb6ab 100644 --- a/app/src/main/java/com/cpjd/roblu/tba/ImportEvent.java +++ b/app/src/main/java/com/cpjd/roblu/tba/ImportEvent.java @@ -3,9 +3,11 @@ import android.os.StrictMode; import android.util.Log; -import com.cpjd.main.Settings; import com.cpjd.main.TBA; -import com.cpjd.models.Event; +import com.cpjd.models.standard.Event; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; +import com.cpjd.roblu.utils.Constants; /** * ImportEvent is used when the user has tapped a specific Event and more specific info @@ -34,13 +36,18 @@ public void run() { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build(); StrictMode.setThreadPolicy(policy); + // Set auth token + TBA.setAuthToken(Constants.PUBLIC_TBA_READ_KEY); + // set what should be included in the event download - Settings.defaults(); + //Settings.defaults(); // notify the listener of the downloaded event Event e = new TBA().getEvent(this.key); + Team[] teams = new TBA().getEventTeams(e.getKey()); + Match[] matches = new TBA().getMatches(e.getKey()); - if(e != null) listener.eventDownloaded(e); + if(e != null) listener.eventDownloaded(e, teams, matches); else listener.errorOccurred("No event found with key: "+this.key+"."); try { diff --git a/app/src/main/java/com/cpjd/roblu/tba/SyncTBAEvent.java b/app/src/main/java/com/cpjd/roblu/tba/SyncTBAEvent.java index cd8e608..56f6db1 100644 --- a/app/src/main/java/com/cpjd/roblu/tba/SyncTBAEvent.java +++ b/app/src/main/java/com/cpjd/roblu/tba/SyncTBAEvent.java @@ -1,6 +1,11 @@ package com.cpjd.roblu.tba; -import com.cpjd.models.Event; +import android.os.StrictMode; + +import com.cpjd.main.TBA; +import com.cpjd.models.ScoreBreakdown; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.models.RForm; import com.cpjd.roblu.models.RTab; @@ -9,6 +14,7 @@ import com.cpjd.roblu.models.metrics.RFieldData; import com.cpjd.roblu.models.metrics.RMetric; import com.cpjd.roblu.models.metrics.RTextfield; +import com.cpjd.roblu.utils.Constants; import com.cpjd.roblu.utils.Utils; import java.util.ArrayList; @@ -24,19 +30,22 @@ */ public class SyncTBAEvent extends Thread { - private Event event; + private Team[] eventTeams; + private Match[] matches; private RForm form; private int eventID; private IO io; + private SyncTBAEventListener listener; public interface SyncTBAEventListener { void done(); } - public SyncTBAEvent(Event event, int eventID, IO io, SyncTBAEventListener listener) { - this.event = event; + public SyncTBAEvent(Team[] teams, Match[] matches, int eventID, IO io, SyncTBAEventListener listener) { + this.eventTeams = teams; + this.matches = matches; this.eventID = eventID; this.io = io; this.listener = listener; @@ -44,19 +53,25 @@ public SyncTBAEvent(Event event, int eventID, IO io, SyncTBAEventListener listen @Override public void run() { - // Load all the teams locally + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build(); + StrictMode.setThreadPolicy(policy); + + // Set auth token + TBA.setAuthToken(Constants.PUBLIC_TBA_READ_KEY); + + // Load all the eventTeams locally RTeam[] teams = io.loadTeams(eventID); form = io.loadForm(eventID); - + /* * Start processing! */ - for(int i = 0; i < event.teams.length; i++) { + for(int i = 0; i < eventTeams.length; i++) { // Check if the team already exists boolean found = false; if(teams != null) { for(RTeam team : teams) { - if(team.getName().equals(event.teams[i].nickname) && team.getNumber() == event.teams[i].team_number) { + if(team.getName().equals(eventTeams[i].getNickname()) && team.getNumber() == eventTeams[i].getTeamNumber()) { syncTeam(team); found = true; break; @@ -64,7 +79,7 @@ public void run() { } } if(!found) { - RTeam newTeam = new RTeam(event.teams[i].nickname, (int) event.teams[i].team_number, io.getNewTeamID(eventID)); + RTeam newTeam = new RTeam(eventTeams[i].getNickname(), (int) eventTeams[i].getTeamNumber(), io.getNewTeamID(eventID)); syncTeam(newTeam); } } @@ -75,8 +90,8 @@ public void run() { private void syncTeam(RTeam team) { team.verify(form); - for(int i = 0; i < event.matches.length; i++) { - if(event.matches[i].doesMatchContainTeam(team.getNumber()) == -1) continue; + for(int i = 0; i < matches.length; i++) { + if(!doesMatchContainTeam(matches[i], team.getNumber())) continue; RTab newTab = matchModelToTab(i, team.getNumber()); @@ -111,63 +126,98 @@ private void syncTeam(RTeam team) { private void insertFieldData(int index, RTab tab) { try { - // Check for FieldData metrics if(tab.getMetrics() != null) { for(RMetric metric : tab.getMetrics()) { if(metric instanceof RFieldData) { if(((RFieldData) metric).getData() == null) ((RFieldData) metric).setData(new LinkedHashMap>()); - for(int i = 0; i < event.matches[index].scorableItems.length; i++) { + ScoreBreakdown redScore = matches[index].getRedScoreBreakdown(); + ScoreBreakdown blueScore = matches[index].getBlueScoreBreakdown(); + String[] keyValues = new String[redScore.getValues().size()]; + keyValues = redScore.getValues().keySet().toArray(keyValues); + + for(String keyValue : keyValues) { ArrayList metrics = new ArrayList<>(); try { - metrics.add(new RCounter(0, "", 0, Double.parseDouble(event.matches[index].redValues[i]))); + metrics.add(new RCounter(0, "", 0, Double.parseDouble(String.valueOf(redScore.getValues().get(keyValue))))); } catch(Exception e) { - metrics.add(new RTextfield(0, "", (event.matches[index].redValues[i]))); + metrics.add(new RTextfield(0, "", (String.valueOf(redScore.getValues().get(keyValue))))); } try { - metrics.add(new RCounter(0, "", 0, Double.parseDouble(event.matches[index].blueValues[i]))); + metrics.add(new RCounter(0, "", 0, Double.parseDouble(String.valueOf(blueScore.getValues().get(keyValue))))); } catch(Exception e) { - metrics.add(new RTextfield(0, "", (event.matches[index].blueValues[i]))); + metrics.add(new RTextfield(0, "", (String.valueOf(blueScore.getValues().get(keyValue))))); } - if(event.matches[index].scorableItems[i] != null && metrics.size() > 0) ((RFieldData) metric).getData().put(event.matches[index].scorableItems[i], metrics); + if(keyValues != null && metrics.size() > 0) ((RFieldData) metric).getData().put(keyValue, metrics); + } + + // Sort it + if(((RFieldData) metric).getData() != null) { + ArrayList keys = new ArrayList<>(((RFieldData) metric).getData().keySet()); + Collections.sort(keys); + LinkedHashMap> sorted = new LinkedHashMap<>(); + for(String s : keys) { + sorted.put(s, ((RFieldData) metric).getData().get(s)); + } + ((RFieldData) metric).setData(sorted); } } } } - } catch(Exception e) {} + } catch(Exception e) { + e.printStackTrace(); + } } private RTab matchModelToTab(int index, int teamNumber) { - int result = event.matches[index].doesMatchContainTeam(teamNumber); - if(result > 0) { + if(doesMatchContainTeam(matches[index], teamNumber)) { String name = "Match"; // process the correct match name - switch(event.matches[index].comp_level) { + switch(matches[index].getCompLevel()) { case "qm": - name = "Quals " + event.matches[index].match_number; + name = "Quals " + matches[index].getMatchNumber(); break; case "qf": - name = "Quarters " + event.matches[index].set_number + " Match " + event.matches[index].match_number; + name = "Quarters " + matches[index].getSetNumber() + " Match " + matches[index].getMatchNumber(); break; case "sf": - name = "Semis " + event.matches[index].set_number + " Match " + event.matches[index].match_number; + name = "Semis " + matches[index].getSetNumber() + " Match " + matches[index].getMatchNumber(); break; case "f": - name = "Finals " + event.matches[index].match_number; + name = "Finals " + matches[index].getMatchNumber(); } - boolean isRed = result == com.cpjd.main.Constants.CONTAINS_TEAM_RED; + boolean isRed = getAlliancePosition(matches[index], teamNumber) <= 3; // add the match to the team, make sure to multiple the Event model's matches times by 1000 (seconds to milliseconds, Roblu works with milliseconds!) - RTab tab = new RTab(teamNumber, name, Utils.duplicateRMetricArray(form.getMatch()), isRed, event.matches[index].isOnWinningAlliance(teamNumber), event.matches[index].time * 1000); + RTab tab = new RTab(teamNumber, name, Utils.duplicateRMetricArray(form.getMatch()), isRed, isOnWinningAlliance(matches[index], teamNumber), matches[index].getTime() * 1000); // set the match position, if possible - tab.setAlliancePosition(event.matches[index].getTeamPosition(teamNumber)); + tab.setAlliancePosition(getAlliancePosition(matches[index], teamNumber)); return tab; } return null; } - + + private int getAlliancePosition(Match m, int teamNumber) { + for(int i = 0; i < m.getBlue().getTeamKeys().length; i++) { + if(m.getBlue().getTeamKeys()[i].equals("frc"+teamNumber)) return i + 4; + } + for(int i = 0; i < m.getRed().getTeamKeys().length; i++) { + if(m.getRed().getTeamKeys()[i].equals("frc"+teamNumber)) return i + 1; + } + + return -1; + } + + private boolean isOnWinningAlliance(Match m, int teamNumber) { + boolean redWinner = m.getWinningAlliance().toLowerCase().contains("red"); + return (redWinner && getAlliancePosition(m, teamNumber) <= 3) || (!redWinner && getAlliancePosition(m, teamNumber) >= 4); + } + + private boolean doesMatchContainTeam(Match m, int teamNumber) { + return getAlliancePosition(m, teamNumber) != -1; + } } diff --git a/app/src/main/java/com/cpjd/roblu/tba/TBALoadEventsTask.java b/app/src/main/java/com/cpjd/roblu/tba/TBALoadEventsTask.java index 17ee63c..8ca9f67 100644 --- a/app/src/main/java/com/cpjd/roblu/tba/TBALoadEventsTask.java +++ b/app/src/main/java/com/cpjd/roblu/tba/TBALoadEventsTask.java @@ -3,18 +3,22 @@ import android.os.AsyncTask; import android.os.StrictMode; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.View; import android.widget.ProgressBar; -import com.cpjd.main.Settings; import com.cpjd.main.TBA; -import com.cpjd.models.Event; +import com.cpjd.models.standard.Event; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; import com.cpjd.roblu.ui.tba.TBAEventAdapter; +import com.cpjd.roblu.utils.Constants; import com.cpjd.roblu.utils.Utils; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import lombok.Data; import lombok.EqualsAndHashCode; @@ -64,6 +68,9 @@ public class TBALoadEventsTask extends AsyncTask { */ private WeakReference recyclerViewWeakReference; + // A cloned version of the events array that events can be removed from with no big issue + private ArrayList cloned; + public interface LoadTBAEventsListener { /** * Called when a general error happens while attempting to pull events @@ -74,7 +81,7 @@ public interface LoadTBAEventsListener { * Called when a specific event is downloaded, with sub-teams, sub-matches, and scores, etc. * @param event the downloaded event */ - void eventDownloaded(Event event); + void eventDownloaded(Event event, Team[] teams, Match[] matches); /** * Called when this thread downloads a list of events, this interface method will tell TBAEventSelector to hold onto these * events for us until later @@ -113,11 +120,15 @@ protected Void doInBackground(Void... params) { */ StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build(); StrictMode.setThreadPolicy(policy); + + // Set auth token + TBA.setAuthToken(Constants.PUBLIC_TBA_READ_KEY); + /* * This disables any sub-data returned with the events, we only want the event data! * Downloading sub-teams for each event would take a while. */ - Settings.disableAll(); + //Settings.disableAll(); /* * Now let's use the AMAZING TBA-API features to download the events, you * should check out the TBA-API developer, he's great. @@ -125,68 +136,77 @@ protected Void doInBackground(Void... params) { if(events == null || events.size() == 0) { try { Event[] events; - if(onlyShowMyEvents) events = new TBA().getTeamEvents(teamNumber, year, false); - else events = new TBA().getEvents(year, false); + if(onlyShowMyEvents) events = new TBA().getEvents(teamNumber, year); + else events = new TBA().getEvents(year); /* * Clean up the downloaded data a bit */ for(Event e : events) { - while(e.name.startsWith(" ")) e.name = e.name.substring(1); - e.start_date = Integer.parseInt(e.start_date.split("-")[1])+"/"+Integer.parseInt(e.start_date.split("-")[2])+"/"+e.start_date.split("-")[0]; + while(e.getName().startsWith(" ")) e.setName(e.getName().substring(1)); } this.events = new ArrayList<>(); Collections.addAll(this.events, events); listener.eventListDownloaded(this.events); } catch(Exception e) { - e.printStackTrace(); + Log.d("RBS", "Error: "+e.getMessage()); if(onlyShowMyEvents && teamNumber == 0) listener.errorOccurred("Error occurred downloading events list. Is your team number properly defined in Roblu settings?"); else listener.errorOccurred("An error occurred while accessing TheBlueAlliance.com"); } } + cloned = new ArrayList<>(this.events); + /* * Now, perform searching if necessary */ if(!query.equals("")) { - for(Event e : this.events) { - /* - * Because of the janky API sort method, relevance can NEVER be zero (otherwise the event will get sorted by date), - * so make sure that zero is not possible! - */ - e.relevance = -1; - /* - * It's tempting to use if statements here, don't! They are INDIVIDUAL search criteria scores - */ - if(e.name.toLowerCase().equals(query)) e.relevance += 5; - if(e.name.toLowerCase().contains(query)) e.relevance += 2; - if(Utils.contains(e.name.toLowerCase(), query)) e.relevance += 4; - if(e.start_date.toLowerCase().contains(query)) e.relevance += 2; - if(e.start_date.toLowerCase().equals(query)) e.relevance += 5; - if(Utils.contains(e.start_date.toLowerCase(), query)) e.relevance += 4; - if(e.location.toLowerCase().equals(query)) e.relevance += 5; - if(e.location.toLowerCase().contains(query)) e.relevance += 2; - if(Utils.contains(e.location.toLowerCase(), query)) e.relevance += 4; + // Remove teams with no relevance + for(int i = 0; i < cloned.size(); i++) { + if(calculateRelevance(cloned.get(i)) == -1) { + cloned.remove(i); + i--; + } } - Collections.sort(this.events); - Collections.reverse(this.events); + Collections.sort(cloned, new Comparator() { + @Override + public int compare(Event o1, Event o2) { + return Integer.compare(calculateRelevance(o1), calculateRelevance(o2)); + } + }); + Collections.reverse(cloned); } /* * Sort by date! */ else { - // make sure to reset old relevance (from past searches) - for(Event e : this.events) e.relevance = 0; - - Collections.sort(this.events); + Collections.sort(cloned); } return null; } + private int calculateRelevance(Event e) { + int relevance = -1; + + if(e.getName().toLowerCase().equals(query)) relevance += 5; + if(e.getName().toLowerCase().contains(query)) relevance += 2; + if(Utils.contains(e.getName().toLowerCase(), query)) relevance += 4; + if(e.getStartDate().toLowerCase().contains(query)) relevance += 2; + if(e.getStartDate().toLowerCase().equals(query)) relevance += 5; + if(Utils.contains(e.getName().toLowerCase(), query)) relevance += 4; + if(e.getLocationName() != null) { + if(e.getLocationName().toLowerCase().equals(query)) relevance += 5; + if(e.getLocationName().toLowerCase().contains(query)) relevance += 2; + if(Utils.contains(e.getLocationName().toLowerCase(), query)) relevance += 4; + } + + return relevance; + } + @Override protected void onPostExecute(Void params) { - tbaEventAdapterWeakReference.get().setEvents(this.events, !query.equals("")); + tbaEventAdapterWeakReference.get().setEvents(cloned); progressBarWeakReference.get().setVisibility(View.INVISIBLE); recyclerViewWeakReference.get().setVisibility(View.VISIBLE); } diff --git a/app/src/main/java/com/cpjd/roblu/tba/UnpackTBAEvent.java b/app/src/main/java/com/cpjd/roblu/tba/UnpackTBAEvent.java index e266fd8..742e02b 100644 --- a/app/src/main/java/com/cpjd/roblu/tba/UnpackTBAEvent.java +++ b/app/src/main/java/com/cpjd/roblu/tba/UnpackTBAEvent.java @@ -4,9 +4,11 @@ import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; -import android.util.Log; -import com.cpjd.models.Event; +import com.cpjd.models.ScoreBreakdown; +import com.cpjd.models.standard.Event; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.models.RForm; import com.cpjd.roblu.models.RTab; @@ -36,6 +38,8 @@ public class UnpackTBAEvent extends AsyncTask { private Event event; + private Match[] matches; + private Team[] teams; private int eventID; private WeakReference activityWeakReference; @@ -44,33 +48,36 @@ public class UnpackTBAEvent extends AsyncTask { @Setter private boolean randomize; - public UnpackTBAEvent(Event e, int eventID, Activity activity, ProgressDialog d) { + public UnpackTBAEvent(Event e, Team[] teams, Match[] matches, int eventID, Activity activity, ProgressDialog d) { this.eventID = eventID; this.event = e; + this.teams = teams; + this.matches = matches; this.activityWeakReference = new WeakReference<>(activity); this.progressDialogWeakReference = new WeakReference<>(d); } protected Void doInBackground(Void... params) { + /* * No teams were contained within the event, so exit, nothing here is relevant * to a TBA event that doesn't contain any team models */ - if(event.teams == null || event.teams.length == 0) return null; + if(teams == null || teams.length == 0) return null; /* * Create an array of team models from the ones contained in the event */ ArrayList teams = new ArrayList<>(); - for(int i = 0; i < event.teams.length; i++) { + for(int i = 0; i < this.teams.length; i++) { // i can be used as the ID because we are creating a fresh event, io.getNewTeamID is irrelevant - teams.add(new RTeam(event.teams[i].nickname, (int) event.teams[i].team_number, i)); + teams.add(new RTeam(this.teams[i].getNickname(), (int) this.teams[i].getTeamNumber(), i)); } /* * Sort the matches in the event */ - Collections.sort(Arrays.asList(event.matches)); + Collections.sort(Arrays.asList(this.matches)); /* * Add the matches to the respective team models @@ -78,32 +85,30 @@ protected Void doInBackground(Void... params) { IO io = new IO(activityWeakReference.get()); RForm form = io.loadForm(eventID); - int result; for(RTeam t : teams) { t.verify(form); - for(int j = 0; j < event.matches.length; j++) { - result = event.matches[j].doesMatchContainTeam(t.getNumber()); - if(result > 0) { + for(int j = 0; j < matches.length; j++) { + if(doesMatchContainTeam(matches[j], t.getNumber())) { String name = "Match"; // process the correct match name - switch(event.matches[j].comp_level) { + switch(matches[j].getCompLevel()) { case "qm": - name = "Quals " + event.matches[j].match_number; + name = "Quals " + matches[j].getMatchNumber(); break; case "qf": - name = "Quarters " + event.matches[j].set_number + " Match " + event.matches[j].match_number; + name = "Quarters " + matches[j].getSetNumber() + " Match " + matches[j].getMatchNumber(); break; case "sf": - name = "Semis " + event.matches[j].set_number + " Match " + event.matches[j].match_number; + name = "Semis " + matches[j].getSetNumber() + " Match " + matches[j].getMatchNumber(); break; case "f": - name = "Finals " + event.matches[j].match_number; + name = "Finals " + matches[j].getMatchNumber(); } - boolean isRed = result == com.cpjd.main.Constants.CONTAINS_TEAM_RED; + boolean isRed = getAlliancePosition(matches[j], t.getNumber()) <= 3; // add the match to the team, make sure to multiple the Event model's matches times by 1000 (seconds to milliseconds, Roblu works with milliseconds!) - RTab tab = new RTab(t.getNumber(), name, Utils.duplicateRMetricArray(form.getMatch()), isRed, event.matches[j].isOnWinningAlliance(t.getNumber()), event.matches[j].time * 1000); + RTab tab = new RTab(t.getNumber(), name, Utils.duplicateRMetricArray(form.getMatch()), isRed, isOnWinningAlliance(matches[j], t.getNumber()), matches[j].getTime() * 1000); // set the match position, if possible - tab.setAlliancePosition(event.matches[j].getTeamPosition(t.getNumber())); + tab.setAlliancePosition(getAlliancePosition(matches[j], t.getNumber())); // Check for FieldData metrics if(tab.getMetrics() != null) { @@ -111,23 +116,37 @@ protected Void doInBackground(Void... params) { if(metric instanceof RFieldData) { if(((RFieldData) metric).getData() == null) ((RFieldData) metric).setData(new LinkedHashMap>()); - for(int i = 0; i < event.matches[j].scorableItems.length; i++) { + ScoreBreakdown redScore = matches[j].getRedScoreBreakdown(); + ScoreBreakdown blueScore = matches[j].getBlueScoreBreakdown(); - Log.d("RBS", "Metric name: "+event.matches[j].scorableItems[i]+", "+"Red value: "+event.matches[j].redValues[i]+", Blue value: "+event.matches[j].blueValues[i]); + String[] keyValues = new String[redScore.getValues().size()]; + keyValues = redScore.getValues().keySet().toArray(keyValues); + for(String keyValue : keyValues) { ArrayList metrics = new ArrayList<>(); try { - metrics.add(new RCounter(0, "", 0, Double.parseDouble(event.matches[j].redValues[i]))); + metrics.add(new RCounter(0, "", 0, Double.parseDouble(String.valueOf(redScore.getValues().get(keyValue))))); } catch(Exception e) { - metrics.add(new RTextfield(0, "", (event.matches[j].redValues[i]))); + metrics.add(new RTextfield(0, "", (String.valueOf(redScore.getValues().get(keyValue))))); } try { - metrics.add(new RCounter(0, "", 0, Double.parseDouble(event.matches[j].blueValues[i]))); + metrics.add(new RCounter(0, "", 0, Double.parseDouble(String.valueOf(blueScore.getValues().get(keyValue))))); } catch(Exception e) { - metrics.add(new RTextfield(0, "", (event.matches[j].blueValues[i]))); + metrics.add(new RTextfield(0, "", (String.valueOf(blueScore.getValues().get(keyValue))))); } - if(event.matches[j].scorableItems[i] != null && metrics.size() > 0) ((RFieldData) metric).getData().put(event.matches[j].scorableItems[i], metrics); + if(keyValues != null && metrics.size() > 0) ((RFieldData) metric).getData().put(keyValue, metrics); + } + + // Sort it + if(((RFieldData) metric).getData() != null) { + ArrayList keys = new ArrayList<>(((RFieldData) metric).getData().keySet()); + Collections.sort(keys); + LinkedHashMap> sorted = new LinkedHashMap<>(); + for(String s : keys) { + sorted.put(s, ((RFieldData) metric).getData().get(s)); + } + ((RFieldData) metric).setData(sorted); } } } @@ -160,6 +179,26 @@ private boolean doesExist(RTeam team, String name) { return false; } + private int getAlliancePosition(Match m, int teamNumber) { + for(int i = 0; i < m.getBlue().getTeamKeys().length; i++) { + if(m.getBlue().getTeamKeys()[i].equals("frc"+teamNumber)) return i + 4; + } + for(int i = 0; i < m.getRed().getTeamKeys().length; i++) { + if(m.getRed().getTeamKeys()[i].equals("frc"+teamNumber)) return i + 1; + } + + return -1; + } + + private boolean isOnWinningAlliance(Match m, int teamNumber) { + boolean redWinner = m.getWinningAlliance().toLowerCase().contains("red"); + return (redWinner && getAlliancePosition(m, teamNumber) <= 3) || (!redWinner && getAlliancePosition(m, teamNumber) >= 4); + } + + private boolean doesMatchContainTeam(Match m, int teamNumber) { + return getAlliancePosition(m, teamNumber) != -1; + } + @Override protected void onPostExecute(Void params) { Intent result = new Intent(); diff --git a/app/src/main/java/com/cpjd/roblu/ui/events/EventEditor.java b/app/src/main/java/com/cpjd/roblu/ui/events/EventEditor.java index 89024f8..5ce466c 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/events/EventEditor.java +++ b/app/src/main/java/com/cpjd/roblu/ui/events/EventEditor.java @@ -16,7 +16,9 @@ import android.widget.Switch; import android.widget.TextView; -import com.cpjd.models.Event; +import com.cpjd.models.standard.Event; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; import com.cpjd.roblu.R; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.models.REvent; @@ -117,7 +119,7 @@ protected void onCreate(Bundle savedInstanceState) { * all the data within this Event model should be included when creating the REvent */ Event event = (Event) getIntent().getSerializableExtra("tbaEvent"); - eventName.setText(event.name); + eventName.setText(event.getName()); findViewById(R.id.switch1).setVisibility(View.VISIBLE); } } else { @@ -270,9 +272,12 @@ private void createEvent(RForm form) { if(!editing && getIntent().getSerializableExtra("tbaEvent") != null) { ProgressDialog d = ProgressDialog.show(this, "Hold on tight!", "Generating team profiles from event...", true); d.setCancelable(false); - event.setKey(((Event)getIntent().getSerializableExtra("tbaEvent")).key); + event.setKey(((Event)getIntent().getSerializableExtra("tbaEvent")).getKey()); io.saveEvent(event); - UnpackTBAEvent unpackTBAEvent = new UnpackTBAEvent((Event)getIntent().getSerializableExtra("tbaEvent"), event.getID(), this, d); + UnpackTBAEvent unpackTBAEvent + = new UnpackTBAEvent((Event)getIntent().getSerializableExtra("tbaEvent"), + (Team[])getIntent().getSerializableExtra("tbaTeams"), + (Match[])getIntent().getSerializableExtra("tbaMatches"), event.getID(), this, d); if(((Switch)findViewById(R.id.switch1)).isChecked()) unpackTBAEvent.setRandomize(true); unpackTBAEvent.execute(); } diff --git a/app/src/main/java/com/cpjd/roblu/ui/events/EventSettings.java b/app/src/main/java/com/cpjd/roblu/ui/events/EventSettings.java index 626b7d8..831dc36 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/events/EventSettings.java +++ b/app/src/main/java/com/cpjd/roblu/ui/events/EventSettings.java @@ -29,7 +29,9 @@ import android.widget.Toast; import com.cpjd.http.Request; -import com.cpjd.models.Event; +import com.cpjd.models.standard.Event; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; import com.cpjd.requests.CloudTeamRequest; import com.cpjd.roblu.R; import com.cpjd.roblu.csv.CSVActivity; @@ -300,12 +302,13 @@ public void errorOccurred(String errMsg) { } @Override - public void eventDownloaded(Event e) { + public void eventDownloaded(Event e, Team[] teams, Match[] matches) { // Start the merge! - new SyncTBAEvent(e, event.getID(), new IO(getActivity()), new SyncTBAEvent.SyncTBAEventListener() { + new SyncTBAEvent(teams, matches, event.getID(), new IO(getActivity()), new SyncTBAEvent.SyncTBAEventListener() { @Override public void done() { tbaSyncDialog.dismiss(); + Utils.showSnackbar(getActivity().findViewById(R.id.event_settings), getActivity(), "Event synced with TBA successfully.", false, rui.getPrimaryColor()); } }).start(); } diff --git a/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventAdapter.java b/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventAdapter.java index 445cd13..b85a4fb 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventAdapter.java +++ b/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventAdapter.java @@ -7,7 +7,7 @@ import android.view.ViewGroup; import android.widget.TextView; -import com.cpjd.models.Event; +import com.cpjd.models.standard.Event; import com.cpjd.roblu.R; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.models.RUI; @@ -72,18 +72,9 @@ interface TBAEventSelectListener { /** * Sets the events to the adapter * @param events events to pass control of to this adapter - * @param hideZeroRelevanceEvents if events with 0 relevance should be visible */ - public void setEvents(ArrayList events, boolean hideZeroRelevanceEvents) { - if(hideZeroRelevanceEvents) { - this.events = new ArrayList<>(events); // clones the array - for(int i = 0; i < this.events.size(); i++) { - if(this.events.get(i).relevance == -1) { - this.events.remove(i); - i--; - } - } - } else this.events = events; + public void setEvents(ArrayList events) { + this.events = events; notifyDataSetChanged(); } @@ -138,8 +129,9 @@ class ViewHolder extends RecyclerView.ViewHolder { void bindEvent(Event e) { if(e == null) return; - this.title.setText(e.name); - this.subtitle.setText(e.location+"\n"+e.start_date); + this.title.setText(e.getName()); + String[] tokens = e.getStartDate().split("-"); + this.subtitle.setText(e.getLocationName()+"\n"+tokens[1]+"/"+tokens[2]+"/"+tokens[0]); this.number.setText(""); if(rui != null) { this.title.setTextColor(rui.getText()); diff --git a/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventSelector.java b/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventSelector.java index a447a30..69e28b8 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventSelector.java +++ b/app/src/main/java/com/cpjd/roblu/ui/tba/TBAEventSelector.java @@ -26,7 +26,9 @@ import android.widget.ProgressBar; import android.widget.Spinner; -import com.cpjd.models.Event; +import com.cpjd.models.standard.Event; +import com.cpjd.models.standard.Match; +import com.cpjd.models.standard.Team; import com.cpjd.roblu.R; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.tba.ImportEvent; @@ -236,13 +238,13 @@ public void tbaEventSelected(View v) { Utils.showSnackbar(findViewById(R.id.activity_apievent_select), getApplicationContext(), "Downloading event...", false, new IO(getApplicationContext()).loadSettings().getRui().getPrimaryColor()); - Log.d("RBS", "Importing event with key: "+event.key); + Log.d("RBS", "Importing event with key: "+event.getKey()); /* * Import the event specifically, eventDownloaded(Event event) will receive the result of this * task execution */ - new ImportEvent(this, event.key).start(); + new ImportEvent(this, event.getKey()).start(); } /** @@ -260,13 +262,15 @@ public void errorOccurred(String errMsg) { * @param event the downloaded event */ @Override - public void eventDownloaded(Event event) { - Log.d("RBS", "Event: "+event.name+" was downloaded."); + public void eventDownloaded(Event event, Team[] teams, Match[] matches) { + Log.d("RBS", "Event: "+event.getName()+" was downloaded."); Intent intent = new Intent(this, EventEditor.class); intent.putExtra("editing", false); - intent.putExtra("key", event.key); - intent.putExtra("name", event.name); + intent.putExtra("key", event.getKey()); + intent.putExtra("name", event.getName()); intent.putExtra("tbaEvent", event); + intent.putExtra("tbaTeams", teams); + intent.putExtra("tbaMatches", matches); startActivityForResult(intent, Constants.GENERAL); } /** diff --git a/app/src/main/java/com/cpjd/roblu/ui/team/TBATeamInfoTask.java b/app/src/main/java/com/cpjd/roblu/ui/team/TBATeamInfoTask.java index 97e2175..3c6a036 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/team/TBATeamInfoTask.java +++ b/app/src/main/java/com/cpjd/roblu/ui/team/TBATeamInfoTask.java @@ -5,10 +5,12 @@ import android.util.Log; import com.cpjd.main.TBA; -import com.cpjd.models.Media; -import com.cpjd.models.Team; +import com.cpjd.models.other.Media; +import com.cpjd.models.standard.Team; import com.squareup.picasso.Picasso; +import org.json.JSONObject; + import java.io.ByteArrayOutputStream; /** @@ -46,9 +48,10 @@ public void run() { listener.teamRetrieved(new TBA().getTeam(teamNumber)); try { - Media[] medias = new TBA().getMedia(teamNumber, Integer.parseInt(year)); + Media[] medias = new TBA().getTeamMedia(teamNumber, Integer.parseInt(year)); for(Media media : medias) { - String url = (String)media.details.get("thumbnail_url"); + JSONObject details = new JSONObject(media.getDetails()); + String url = details.getString("thumbnail_url"); if(url == null || url.equals("")) continue; Log.d("RBS", "Attempting to download image at URL: "+url); Bitmap b = Picasso.with(context).load(url).get(); diff --git a/app/src/main/java/com/cpjd/roblu/ui/team/fragments/Overview.java b/app/src/main/java/com/cpjd/roblu/ui/team/fragments/Overview.java index d973a74..c3ce8f5 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/team/fragments/Overview.java +++ b/app/src/main/java/com/cpjd/roblu/ui/team/fragments/Overview.java @@ -12,7 +12,7 @@ import android.view.View; import android.view.ViewGroup; -import com.cpjd.models.Team; +import com.cpjd.models.standard.Team; import com.cpjd.roblu.R; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.models.REvent; @@ -243,15 +243,14 @@ else if(metric instanceof RCounter || metric instanceof RSlider || metric instan */ @Override public void teamRetrieved(Team tbaTeam) { - Log.d("RBS", "Downloaded TBA information for "+ tbaTeam.nickname); - String tbaInfo = "Locality: " + tbaTeam.locality + - "\nRegion: " + tbaTeam.region + - "\nCountry name: " + tbaTeam.country_name + - "\nLocation: " + tbaTeam.location + - "\nRookie year: " + tbaTeam.rookie_year + - "\nMotto: " + tbaTeam.motto; + Log.d("RBS", "Downloaded TBA information for "+ tbaTeam.getNickname()); + String tbaInfo = + "Country name: " + tbaTeam.getCountry() + + "\nLocation: " + tbaTeam.getLocationName() + + "\nRookie year: " + tbaTeam.getRookieYear() + + "\nMotto: " + tbaTeam.getMotto(); TeamViewer.team.setTbaInfo(tbaInfo); - TeamViewer.team.setWebsite(tbaTeam.website); + TeamViewer.team.setWebsite(tbaTeam.getWebsite()); try { new IO(getView().getContext()).saveTeam(getArguments().getInt("eventID"), TeamViewer.team); diff --git a/app/src/main/java/com/cpjd/roblu/ui/teams/TeamsView.java b/app/src/main/java/com/cpjd/roblu/ui/teams/TeamsView.java index ef0e0c4..b7cc88e 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/teams/TeamsView.java +++ b/app/src/main/java/com/cpjd/roblu/ui/teams/TeamsView.java @@ -35,7 +35,6 @@ import android.widget.Spinner; import android.widget.TextView; -import com.cpjd.main.TBA; import com.cpjd.roblu.R; import com.cpjd.roblu.io.IO; import com.cpjd.roblu.models.RCheckout; @@ -198,7 +197,7 @@ protected void onCreate(Bundle savedInstanceState) { finish(); return; } - TBA.setID("Roblu", "Scouting-App", "v3"); //setup TBA api vars + // This is a public account. There isn't anything valuable on here, and this is only a read-only token. So have fun! settings = io.loadSettings(); /* @@ -604,13 +603,14 @@ public void run() { @Override public boolean onLongClick(View v) { - if(v.getId() == R.id.fab) { + if(v.getId() == R.id.fab && eventDrawerManager.getEvent() != null) { final Dialog d = new Dialog(this); d.setTitle("Add metric filter:"); d.setContentView(R.layout.metric_chooser_filter); final Spinner spinner = d.findViewById(R.id.type); String[] values; RForm form = io.loadForm(eventDrawerManager.getEvent().getID()); + if(form == null || form.getMatch() == null || form.getPit() == null) return false; final ArrayList metrics = new ArrayList<>(form.getPit()); metrics.addAll(form.getMatch()); diff --git a/app/src/main/java/com/cpjd/roblu/ui/tutorials/Tutorial.java b/app/src/main/java/com/cpjd/roblu/ui/tutorials/Tutorial.java index 81f685d..12651a8 100644 --- a/app/src/main/java/com/cpjd/roblu/ui/tutorials/Tutorial.java +++ b/app/src/main/java/com/cpjd/roblu/ui/tutorials/Tutorial.java @@ -49,7 +49,8 @@ protected void onCreate(Bundle savedInstanceState) { // List of tutorials tutorials = new ArrayList<>(); - tutorials.add(new RTutorial("Text based", "View the Roblu text based tutorial", "https://docs.google.com/document/d/1DqpgKPdtfZDUc7Zu3MqdJHL59aB-ht8H1ZwllYlzMuc/edit?usp=sharing")); + tutorials.add(new RTutorial("Roblu - Text based", "View the Roblu text based tutorial", "https://docs.google.com/document/d/1DqpgKPdtfZDUc7Zu3MqdJHL59aB-ht8H1ZwllYlzMuc/edit?usp=sharing")); + tutorials.add(new RTutorial("Roblu Scouter - Text based", "View the Roblu Scouter text based tutorial", "https://docs.google.com/document/d/191km1s6HqZF8Ag6bCwn_XWA54MepjL5gU8-N05ean3w/edit?usp=sharing")); tutorials.add(new RTutorial("The basics", "Roblu's mission, description of platforms, terms, etc.", "9j6ysvJJyQg")); tutorials.add(new RTutorial("Events", "Learn how to create, manage, backup, organize, and export events", "6BLlLxltppk")); tutorials.add(new RTutorial("Forms", "Learn how to create, manage, edit, organize, master form", "xLLbPyhW9fg")); @@ -119,18 +120,18 @@ void watchYoutubeVideo(String id){ @Override public void tutorialSelected(View v) { int position = rv.getChildLayoutPosition(v); - if(position == tutorials.size() - 1) { + if(position == tutorials.size() - 1) { // devlogs String url = "https://www.youtube.com/playlist?list=PLjv2hkWcHVGZAlplguiS4rR_45-KLS28a"; Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(url)); startActivity(i); } - else if(position == 0 || position == 7) { + else if(position == 0 || position == 1 || position == 8) { // links or anything non-youtube, add their positions here Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(tutorials.get(position).getYoutubeID())); startActivity(i); } - else { + else { // youtube videos watchYoutubeVideo(tutorials.get(position).getYoutubeID()); } } diff --git a/app/src/main/java/com/cpjd/roblu/utils/Constants.java b/app/src/main/java/com/cpjd/roblu/utils/Constants.java index b7b0f14..cecd68a 100644 --- a/app/src/main/java/com/cpjd/roblu/utils/Constants.java +++ b/app/src/main/java/com/cpjd/roblu/utils/Constants.java @@ -13,9 +13,19 @@ public abstract class Constants { public static final String SERVICE_ID = "com.cpjd.roblu.service"; - public static final String UPDATE_MESSAGE = "-Added multi-filter option (long press search button)\n-IOS edition of Roblu Scouter coming soon!\n-Bug fixes"; + public static final String UPDATE_MESSAGE = "What's new in 4.5.9?\n\n-Updated TBA-API to V3\n-IOS edition of Roblu Scouter coming soon!\n-Bug fixes"; - public static final int VERSION = 13; // used for updating the changelist + /** + * This isn't really that secure, but the point here is, it's a read-only key, it's a throwaway account, + * there's not even any data stored on the account, the account isn't even used. This really helps + * because it means that people don't have to hassle around with api keys. Also, I'll probably get kicked + * off this API and some point, and when that day happens, I'll add in a "sign into TBA" so everyone can + * have their personal read-API and everything can be square with the world, until then, we'll pretend that + * I never noticed. + */ + public static final String PUBLIC_TBA_READ_KEY = SecretConstants.PUBLIC_TBA_READ_KEY; + + public static final int VERSION = 14; // used for updating the changelist /* * v4.0.0 cross activity codes diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6fbbfce..d5a744b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -85,7 +85,7 @@ Roblu requires several permissions to work correctly. Please accept the dialog that appears after clicking next. Roblu is ready to use Head of the scouting division of your team? Coach? Learn how to use Roblu with these official tutorials: - View YouTube tutorials + View tutorials Welcome to Roblu V4. Done