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 ? (