diff --git a/Notes.md b/Notes.md index dcf27253..0d05071f 100644 --- a/Notes.md +++ b/Notes.md @@ -1,3 +1,24 @@ +# Version 1.0.9 Notes + +## What's new? + +- Personal Bests are now sorted by games. + +## Fixes + +- Fixed: Cannot remove games from `MyGames`. +- Fixed: MyGames not reloading when adding/removing games. +- Fixed: Notifications not loading due to API-Key missing. + +## Known issues + +- App not reloading when logging out. +- Runs with multiple runners not displaying properly. +- Japanese users not displaying. +- OS forced darkmode breaks `UserHeader.js` colors. + +--- + # Version 1.0.8 Notes ## What's new? diff --git a/Source/App.js b/Source/App.js index d9dea189..e3ee1a3c 100644 --- a/Source/App.js +++ b/Source/App.js @@ -12,6 +12,7 @@ import { createStore, applyMiddleware, combineReducers } from "redux"; import thunk from "redux-thunk"; import themeReducer from "./app/redux/themeReducer"; +import { useSelector } from "react-redux"; const store = createStore( combineReducers({ themeReducer }), applyMiddleware(thunk) diff --git a/Source/app.json b/Source/app.json index 8760f47d..ac74fa9b 100644 --- a/Source/app.json +++ b/Source/app.json @@ -3,7 +3,7 @@ "name": "SpeedrunHub", "slug": "speedruncomapp", "platforms": ["ios", "android", "web"], - "version": "1.0.8", + "version": "1.0.9", "orientation": "portrait", "icon": "./app/assets/trophy.png", "splash": { @@ -22,7 +22,7 @@ "githubUrl": "https://github.com/Asiern/SpeedrunHub", "android": { "package": "com.asiern.speedrun", - "versionCode": 8 + "versionCode": 9 } } } diff --git a/Source/app/components/MyGames.js b/Source/app/components/MyGames.js index 3e5df935..84147072 100644 --- a/Source/app/components/MyGames.js +++ b/Source/app/components/MyGames.js @@ -1,8 +1,10 @@ import React from "react"; -import { StyleSheet, View } from "react-native"; +import { StyleSheet, View,Dimestions, Dimensions } from "react-native"; import { FlatList } from "react-native-gesture-handler"; import GameCard from "./GameCard"; - +import NotificationCard from "../components/NotificationCard" +import colors from "../config/colors" +const {width} = Dimensions.get("screen") export default function MyGames(props) { return ( @@ -10,6 +12,16 @@ export default function MyGames(props) { data={props.data} numColumns={3} keyExtractor={(item) => item.id} + ListEmptyComponent={ + + } renderItem={({ item }) => ( { const [data, setData] = useState(null); const [loading, setloading] = useState(true); const [error, seterror] = useState(false); - const key = props.APIKey; useEffect(() => { let mounted = true; @@ -27,11 +25,10 @@ const NotificationBar = (props) => { xhr.open("GET", url); xhr.setRequestHeader("Host", "www.speedrun.com"); xhr.setRequestHeader("Accept", "application/json"); - xhr.setRequestHeader("X-API-Key", key); + xhr.setRequestHeader("X-API-Key", props.APIKey); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && mounted) { response = JSON.parse(xhr.responseText); - setData(response.data); setloading(false); } @@ -44,7 +41,7 @@ const NotificationBar = (props) => { return function cleanup() { mounted = false; }; - }, [data]); + }, [data, loading]); if (loading) { return ; } else if (error) { @@ -57,7 +54,7 @@ const NotificationBar = (props) => { Notifications - {key == null ? ( + {props.APIKey == null ? ( { color={colors.darkgrey} /> ) : ( - + )} ); diff --git a/Source/app/components/PB.js b/Source/app/components/PB.js index d5f41cdd..0af423a4 100644 --- a/Source/app/components/PB.js +++ b/Source/app/components/PB.js @@ -1,95 +1,45 @@ -import React, { PureComponent } from "react"; +import React, { useEffect, useState } from "react"; import { StyleSheet, - View, - Image, Text, TouchableOpacity, + View, Linking, } from "react-native"; import colors from "../config/colors"; -export default class PB extends PureComponent { - constructor(props) { - super(props); - this.state = { - categoryid: this.props.categoryid, - category: this.props.category, - place: this.props.place, - time: this.props.time, - runner: this.props.runner, - runnerid: this.props.runnerid, - cover: - "https://www.speedrun.com/themes/" + - this.props.abbreviation + - "/cover-64.png", - game: this.props.game, - abbreviation: this.props.abbreviation, - weblink: this.props.weblink, - loading: true, - }; - } - loadInBrowser = (link) => { + +const PB = (props) => { + function loadInBrowser(link) { Linking.openURL(link).catch((err) => console.error("Couldn't load page", err) ); - }; - componentDidMount() { - try { - this.timeConverter(); - this.FetchUser(this.state.runnerid); - } catch (error) { - console.log(error); - } - } - timeConverter() { - var result = this.state.time.toLowerCase(); - result = result.substr(2, result.lenght); - this.setState({ time: result }); } - async FetchUser(runnerid) { - const url = "https://www.speedrun.com/api/v1/users/" + runnerid; - const response = await fetch(url); - const data = await response.json(); - this.setState({ loading: false, runner: data.data.names.international }); + function timeConverter(time) { + var result = time.toLowerCase(); + return result.substr(2, result.lenght); } - render() { - return ( - this.loadInBrowser(this.state.weblink)} - > - - - - - {this.state.category} - - - {this.state.place} - + return ( + loadInBrowser(props.weblink)} + style={styles.container} + > + + {props.place} + + + {props.category} + + + {timeConverter(props.time)} + + + ); +}; - - {this.state.time} - - - ); - } -} const styles = StyleSheet.create({ - shadow: { - shadowColor: "gold", - shadowOffset: { width: 5, height: 5 }, - shadowOpacity: 0.9, - - // add shadows for Android only - // No options for shadow color, shadow offset, shadow opacity like iOS - elevation: 1, - }, container: { - paddingVertical: 20, + marginHorizontal: 10, + paddingVertical: 15, flexDirection: "row", flex: 1, alignItems: "center", @@ -102,29 +52,20 @@ const styles = StyleSheet.create({ shadowOpacity: 0.9, elevation: 1, }, - game: { + place: { flex: 3, - //backgroundColor: "dodgerblue", alignItems: "center", }, category: { - flex: 5, - //backgroundColor: "gold" - alignItems: "center", - }, - place: { - flex: 3, - //backgroundColor: "tomato", + flex: 6, alignItems: "center", }, runner: { - flex: 5, - //backgroundColor: "green", + flex: 8, alignItems: "center", }, time: { flex: 8, - //backgroundColor: "orange", alignItems: "center", }, text: { @@ -138,9 +79,6 @@ const styles = StyleSheet.create({ fontSize: 15, color: colors.primary, }, - cover: { - height: 60, - width: 45, - }, }); -module.export = PB; + +export default PB; diff --git a/Source/app/components/ProfileHeader.js b/Source/app/components/ProfileHeader.js new file mode 100644 index 00000000..74db26a1 --- /dev/null +++ b/Source/app/components/ProfileHeader.js @@ -0,0 +1,113 @@ +import React from "react"; +import { Text, View, StyleSheet, Image } from "react-native"; + +import { StackActions } from "@react-navigation/native"; + +const goBack = StackActions.pop(); + +import Constants from "expo-constants"; +import Feather from "@expo/vector-icons/Feather"; +import colors from "../config/colors"; + +const ProfileHeader = (props) => { + return ( + + + + props.navigation.dispatch(goBack)} + name="arrow-left" + color={colors.white} + size={35} + style={{ paddingLeft: 20 }} + /> + + + + + + + + + {props.username} + + + {props.country} + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: colors.primary, + borderBottomLeftRadius: 40, + borderBottomRightRadius: 40, + }, + topbar: { + flex: 1, + flexDirection: "row", + marginTop: Constants.statusBarHeight, + paddingTop: 10, + paddingBottom: 10, + }, + topbarleft: { + flex: 1, + }, + topbarcenter: { + flex: 1, + justifyContent: "center", + }, + topbarright: { + flex: 1, + }, + profile: { + flex: 1, + paddingBottom: 30, + justifyContent: "center", + alignItems: "center", + alignContent: "center", + }, + imagecontainer: { + flex: 1, + alignContent: "center", + justifyContent: "flex-end", + alignItems: "center", + }, + Image: { + height: 100, + width: 100, + borderWidth: 1, + borderRadius: 50, + }, + userinfo: { + flex: 1, + alignItems: "center", + justifyContent: "center", + padding: 20, + }, + h1: { + color: colors.white, + fontSize: 25, + fontWeight: "bold", + alignSelf: "center", + }, + h2: { + color: colors.white, + fontSize: 15, + fontWeight: "bold", + alignSelf: "center", + }, +}); +export default ProfileHeader; diff --git a/Source/app/components/SectionHeader.js b/Source/app/components/SectionHeader.js new file mode 100644 index 00000000..aadadaf3 --- /dev/null +++ b/Source/app/components/SectionHeader.js @@ -0,0 +1,65 @@ +import React from "react"; +import { + Text, + View, + StyleSheet, + ImageBackground, + Dimensions, +} from "react-native"; + +import colors from "../config/colors"; + +const { width } = Dimensions.get("screen"); +const SectionHeader = (props) => { + return ( + + + {props.name} + + + ); +}; +const styles = StyleSheet.create({ + container: { + width: width - 20, + height: 100, + alignContent: "center", + justifyContent: "center", + shadowColor: "black", + backgroundColor: colors.black, + borderRadius: 10, + shadowOffset: { width: 5, height: 5 }, + shadowOpacity: 1, + elevation: 5, + alignSelf: "center", + marginTop: 30, + }, + image: { + flex: 1, + resizeMode: "cover", + flexDirection: "row", + opacity: 1, + textAlign: "center", + justifyContent: "center", + }, + text: { + color: colors.white, + fontSize: 20, + fontWeight: "bold", + alignSelf: "center", + textShadowColor: "#2e2e2e", + textShadowOffset: { width: 1, height: 2 }, + textShadowRadius: 5, + marginHorizontal: 20, + }, +}); +export default SectionHeader; diff --git a/Source/app/components/SettingsSection.js b/Source/app/components/SettingsSection.js new file mode 100644 index 00000000..75cb891e --- /dev/null +++ b/Source/app/components/SettingsSection.js @@ -0,0 +1,51 @@ +import React from "react"; +import { Text, View, TouchableOpacity, StyleSheet } from "react-native"; +import colors from "../config/colors"; +import Feather from "@expo/vector-icons/Feather"; + +const SettingsSection = (props) => { + return ( + props.navigation.navigate(props.navigateTO)} + > + + + + + + + {props.title} + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + padding: 20, + flexDirection: "row", + backgroundColor: colors.white, + }, + textcontainer: { + flex: 3, + justifyContent: "center", + }, + text: { + fontSize: 17, + fontWeight: "bold", + }, + icon: { + flex: 1, + alignContent: "center", + alignItems: "center", + justifyContent: "center", + }, +}); +export default SettingsSection; diff --git a/Source/app/config/Themes.js b/Source/app/config/Themes.js index 96c314fc..2cf427ae 100644 --- a/Source/app/config/Themes.js +++ b/Source/app/config/Themes.js @@ -1,15 +1,27 @@ +export const theme = { + mode: "light", + PRIMARY_BACKGROUND: "#fff", + SECONDARY_BACKGROUND: "#ededed", + PRIMARY_TEXT: "#242c37", + PRIMARY_ACCENT: "#e57373", + INACTIVE: "#242c37", + STATUS_BAR_STYILE: "dark-content", +}; export const lightTheme = { mode: "light", - PRIMARY_BACKGROUND: "#FFF", + PRIMARY_BACKGROUND: "#fff", + SECONDARY_BACKGROUND: "#ededed", PRIMARY_TEXT: "#242c37", - PRIMARY_ACCENT: "#4FC3F7", + PRIMARY_ACCENT: "#e57373", + INACTIVE: "#242c37", STATUS_BAR_STYILE: "dark-content", }; export const darkTheme = { mode: "dark", PRIMARY_BACKGROUND: "#000", - SECONDARY_BACKGROUND: "#242c37", - PRIMARY_TEXT: "#81C784", + SECONDARY_BACKGROUND: "#000", + PRIMARY_TEXT: "#fff", PRIMARY_ACCENT: "#81C784", + INACTIVE: "#ededed", STATUS_BAR_STYILE: "light-content", }; diff --git a/Source/app/config/colors.js b/Source/app/config/colors.js index b75fd10e..2b7ab7cc 100644 --- a/Source/app/config/colors.js +++ b/Source/app/config/colors.js @@ -1,5 +1,5 @@ export default { - primary: "#81C784", + primary: "#FF8A65", primary3: "#FBC2EB", primary2: "#ff758c", primaryG: "#ff7eb3", diff --git a/Source/app/redux/themeReducer.js b/Source/app/redux/themeReducer.js index b3c0833f..98e64f6a 100644 --- a/Source/app/redux/themeReducer.js +++ b/Source/app/redux/themeReducer.js @@ -1,5 +1,7 @@ import { lightTheme } from "../config/Themes"; +import { darkTheme } from "../config/Themes"; +import AsyncStorage from "@react-native-community/async-storage"; import { SWITCH_THEME } from "./themeActions"; const initialState = { diff --git a/Source/app/screens/GameInfo.js b/Source/app/screens/GameInfo.js index 3506d5a1..f5fb528f 100644 --- a/Source/app/screens/GameInfo.js +++ b/Source/app/screens/GameInfo.js @@ -45,16 +45,15 @@ class GameInfo extends React.Component { _toggleFavourites = async () => { const games = await AsyncStorage.getItem("@MyGames"); var gameList = JSON.parse(games); + //Create game obj + var game = { + id: this.state.id, + abbreviation: this.state.abbreviation, + }; if (gameList == null) { gameList = []; } - if (!this.state.favourite) { - console.log("enter if toggle"); - //Create game obj - var game = { - id: this.state.id, - abbreviation: this.state.abbreviation, - }; + if (!this.state.favourite) { //add game to list gameList.push(game); //Game added to list @@ -62,6 +61,11 @@ class GameInfo extends React.Component { this.setState({ favourite: true }); } else { //Game got removed from list + for (let GAME of gameList) { + if (game.id == GAME.id) { + gameList.splice(gameList.indexOf(GAME), 1); + } + } await AsyncStorage.setItem("@MyGames", JSON.stringify(gameList)); this.setState({ favourite: false }); } @@ -268,14 +272,14 @@ class GameInfo extends React.Component { {this.state.favourite == true ? (