-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
97 changed files
with
10,238 additions
and
2,579 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,27 @@ | ||
import { StatusBar } from 'expo-status-bar'; | ||
import { StyleSheet } from 'react-native'; | ||
import React from 'react'; | ||
|
||
import useCachedResources from './hooks/useCachedResources'; | ||
import Navigation from './navigation'; | ||
import { SafeAreaProvider } from 'react-native-safe-area-context'; | ||
import useCachedResources from './hooks/useCachedResources'; | ||
import { PaletteProvider, usePalette } from './hooks/usePalette'; | ||
import RootNavigator from './navigation/RootNavigator'; | ||
|
||
export default function App() { | ||
const isLoadingComplete = useCachedResources(); | ||
const isLoadingComplete = useCachedResources(); | ||
const [palette] = usePalette(); | ||
|
||
if (!isLoadingComplete) { | ||
return null; | ||
} else { | ||
return ( | ||
<SafeAreaProvider> | ||
<Navigation /> | ||
<StatusBar style="light" /> | ||
</SafeAreaProvider> | ||
); | ||
} | ||
if (!isLoadingComplete) { | ||
return null; | ||
} else { | ||
return ( | ||
<PaletteProvider> | ||
<StatusBar | ||
animated={true} | ||
backgroundColor={palette.headerBackground} | ||
style='light' /> | ||
<SafeAreaProvider> | ||
<RootNavigator /> | ||
</SafeAreaProvider > | ||
</PaletteProvider> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<p align="center"> | ||
<a href="https://team5148.org/#/"> | ||
<img alt="Blitz Scouter" src="https://i.imgur.com/eANWZcA.png" /> | ||
</a> | ||
</p> | ||
|
||
<p align="center"> | ||
<a href="https://github.com/NB-Blitz/BlitzScouter/releases"> | ||
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/NB-Blitz/BlitzScouter/total"> | ||
</a> | ||
<a href="https://github.com/NB-Blitz/BlitzScouter/issues"> | ||
<img alt="GitHub issues" src="https://img.shields.io/github/issues/NB-Blitz/BlitzScouter"> | ||
</a> | ||
</p> | ||
|
||
<p align="center"> | ||
<img alt="BlitzScouter Matches" src="https://i.imgur.com/6rzXtkB.jpg" width="30%" height="30%" > | ||
<img alt="BlitzScouter Teams" src="https://i.imgur.com/weB4lfc.jpg" width="30%" height="30%" > | ||
</p> | ||
|
||
# Download | ||
At the moment, BlitzScouter is only supported on **Android** devices. APKs can be downloaded and installed under the [Releases](https://github.com/NB-Blitz/BlitzScouter/releases) tab. | ||
|
||
# Features | ||
- 🎨 Customizable color palette | ||
- 📋 Customizable scouting templates | ||
- 📷 Take and manage robot photos | ||
- 💾 Take event data from [The Blue Alliance](https://www.thebluealliance.com/) offline | ||
- 📁 Share data using json, csv, or QR codes | ||
- 🥊 Quick match summaries for strategy | ||
- 🧑🤝🧑 Sort and analyze teams | ||
|
||
# Building | ||
Requires [Node](https://nodejs.org/en/) | ||
1. Install Expo: | ||
``` | ||
npm install --global expo-cli | ||
``` | ||
2. Run Dev Client: | ||
``` | ||
expo start | ||
``` | ||
3. Scan the QR-Code that appears on screen |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { Linking } from 'react-native'; | ||
import { TBAEvent, TBAMatch, TBAMedia, TBARankings, TBAStatus, TBATeam, TBAZebra } from '../types/TBAModels'; | ||
|
||
const API_KEY = "i90dAcKHXvQ9havypHJKeGY8O1tfymFpaW1Po3RGYpvoMTRVwtiUsUFaLmstCDp3"; | ||
const URL_PREFIX = "https://www.thebluealliance.com/api/v3/"; | ||
const URL_SUFFIX = "?X-TBA-Auth-Key=" + API_KEY; | ||
const TIMEOUT = 8000; // ms | ||
export default class TBA { | ||
|
||
/** | ||
* Fetches all matches at a given event | ||
* @param eventID - ID of the event | ||
* @returns An array of TBAMatch | ||
*/ | ||
static getMatches(eventID: string) { | ||
return TBA._fetch<TBAMatch[]>("event/" + eventID + "/matches/simple"); | ||
} | ||
|
||
/** | ||
* Fetches team stats and rankings at a given event | ||
* @param eventID - ID of the event | ||
* @returns Ranking data | ||
*/ | ||
static getRankings(eventID: string) { | ||
return TBA._fetch<TBARankings>("event/" + eventID + "/rankings"); | ||
} | ||
|
||
/** | ||
* Fetches all events in a current year | ||
* @returns An array of TBAEvent | ||
*/ | ||
static async getEvents(year: number) { | ||
return TBA._fetch<TBAEvent[]>("events/" + year); | ||
} | ||
|
||
/** | ||
* Fetches Zebra Motionworks data for a match | ||
* @param matchID - ID of the match | ||
* @returns | ||
*/ | ||
static async getZebra(matchID: string) { | ||
return TBA._fetch<TBAZebra>("match/" + matchID + "/zebra_motionworks"); | ||
} | ||
|
||
/** | ||
* Fetches all teams at a given event | ||
* @param eventID - ID of the event | ||
* @returns An array of TBATeam | ||
*/ | ||
static async getTeams(eventID: string) { | ||
return TBA._fetch<TBATeam[]>("event/" + eventID + "/teams/simple"); | ||
} | ||
|
||
|
||
/** | ||
* Fetches all media of a given team | ||
* @param teamID - ID of the team | ||
* @returns An array of TBAMedia | ||
*/ | ||
static getTeamMedia(teamID: string, year: number) { | ||
return TBA._fetch<TBAMedia[]>("team/" + teamID + "/media/" + year); | ||
} | ||
|
||
/** | ||
* Fetches the server status of The Blue Alliance | ||
* @returns Status in the form of TBAStatus | ||
*/ | ||
static getServerStatus() { | ||
return TBA._fetch<TBAStatus>("status"); | ||
} | ||
|
||
/** | ||
* Opens a team in a new browser window | ||
* @param teamNumber - Number of the team | ||
*/ | ||
static openTeam(teamNumber: number, year?: number) { | ||
Linking.openURL("https://www.thebluealliance.com/team/" + teamNumber + "/" + (year ? year : "")); | ||
} | ||
|
||
/** | ||
* Opens a match in a new browser window | ||
* @param matchID - ID of the match | ||
*/ | ||
static openMatch(matchID: string) { | ||
Linking.openURL("https://www.thebluealliance.com/match/" + matchID); | ||
} | ||
|
||
/** | ||
* Fetches a url from the TBA API | ||
* @param path - API route | ||
* @returns The parsed response from the API | ||
*/ | ||
static _fetch<Type>(path: string): Promise<Type | undefined> { | ||
/* | ||
https://github.com/whatwg/fetch/issues/180 | ||
TL;DR: fetch doesn't include a request timeout by default. | ||
While this solution does introduce memory leaks, there | ||
is no other option until a better solution is implemented. | ||
*/ | ||
|
||
// Fetch Promise | ||
const URL = URL_PREFIX + path + URL_SUFFIX; | ||
let fetchPromise = new Promise<Type | undefined>((resolve, reject) => { | ||
let headers = new Headers(); | ||
headers.append("pragma", "no-cache"); | ||
headers.append("cache-control", "no-cache"); | ||
|
||
const REQUEST_DATA = { | ||
method: "GET", | ||
headers: headers | ||
}; | ||
|
||
console.log("GET: " + URL); | ||
fetch(URL, REQUEST_DATA).then((result) => { | ||
result.json().then((json) => { | ||
resolve(json); | ||
}).catch(() => { | ||
resolve(undefined); | ||
}); | ||
}).catch(() => { | ||
resolve(undefined); | ||
}); | ||
}); | ||
|
||
// Timeout Promise | ||
let timeoutPromise = new Promise<Type | undefined>((resolve, reject) => { | ||
setTimeout(() => { | ||
resolve(undefined); | ||
}, TIMEOUT); | ||
}) | ||
|
||
return Promise.race<Type | undefined>([fetchPromise, timeoutPromise]); | ||
} | ||
} |
Oops, something went wrong.