Skip to content

Commit

Permalink
Merge pull request #33 from HighlanderRobotics/ci
Browse files Browse the repository at this point in the history
Add linting, formatting, and enforce in CI
  • Loading branch information
MangoSwirl authored Aug 7, 2024
2 parents 99033b4 + 62cd6f8 commit b5abb28
Show file tree
Hide file tree
Showing 79 changed files with 8,485 additions and 4,790 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Runs lint and checks prettier formatting

name: CI

on:
push:
branches:
- main
pull_request:

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 22
- run: npm ci
- run: npm run lint

prettier:
name: Prettier
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 22
- run: npm ci
- run: npm run format:check

tsc:
name: TypeScript
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 22
- run: npm ci
- run: npm run ts:check
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true
}
4 changes: 1 addition & 3 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
"resizeMode": "contain",
"backgroundColor": "#1f1f1f"
},
"assetBundlePatterns": [
"**/*"
],
"assetBundlePatterns": ["**/*"],
"ios": {
"icon": "./assets/icon.png",
"supportsTablet": true,
Expand Down
232 changes: 125 additions & 107 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,36 @@ import { NativeModules, View } from "react-native";
import { colors } from "../lib/colors";

import {
useFonts,
Heebo_400Regular,
Heebo_500Medium,
Heebo_600SemiBold,
Heebo_700Bold,
useFonts,
Heebo_400Regular,
Heebo_500Medium,
Heebo_600SemiBold,
Heebo_700Bold,
} from "@expo-google-fonts/heebo";

import { useCallback, useEffect, useState } from "react";
import { LoadServicesContext, ServiceValues, ServicesContext, services, servicesLoadingAtom } from "../lib/services";
import {
LoadServicesContext,
ServiceValues,
ServicesContext,
services,
servicesLoadingAtom,
} from "../lib/services";
import { LocalCache } from "../lib/localCache";

import TimeAgo from "javascript-time-ago";
import en from 'javascript-time-ago/locale/en.json'
import en from "javascript-time-ago/locale/en.json";
import { atom, useSetAtom } from "jotai";
import { ScouterSchedule, scouterScheduleAtom } from "../lib/storage/scouterSchedules";
import AsyncStorage from "@react-native-async-storage/async-storage";
import {
ScouterSchedule,
scouterScheduleAtom,
} from "../lib/storage/scouterSchedules";

const {UIManager} = NativeModules;
const { UIManager } = NativeModules;

UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}

TimeAgo.addDefaultLocale(en);

Expand All @@ -32,107 +41,116 @@ SplashScreen.preventAutoHideAsync();
export const startMatchEnabledAtom = atom(false);

export default function Layout() {
const setServicesLoading = useSetAtom(servicesLoadingAtom);

const setStartMatchEnabled = useSetAtom(startMatchEnabledAtom);
const setServicesLoading = useSetAtom(servicesLoadingAtom);

useEffect(() => {
const timeout = setTimeout(() => {
setStartMatchEnabled(true);
}, 2000);
const setStartMatchEnabled = useSetAtom(startMatchEnabledAtom);

return () => {
clearTimeout(timeout);
}
});

const [fontsLoaded, fontError] = useFonts({
Heebo_400Regular,
Heebo_500Medium,
Heebo_600SemiBold,
Heebo_700Bold,
MaterialSymbols_500Rounded: require("../assets/fonts/Material-Symbols-Rounded.ttf"),
MaterialSymbols_500Rounded40px: require("../assets/fonts/Material-Symbols-Rounded-40px.ttf"),
MaterialSymbols_500Rounded48px: require("../assets/fonts/Material-Symbols-Rounded-48px.ttf"),
});

const setScouterSchedule = useSetAtom(scouterScheduleAtom);

const onLayoutRootView = useCallback(async () => {
if (fontsLoaded || fontError) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded, fontError]);

const [serviceValues, setServiceValues] = useState<ServiceValues>({
teamScouters: null,
tournaments: null,
scouterSchedule: null,
});

const loadServices = async () => {
setServicesLoading(true);
await Promise.allSettled(services.map(async service => {
try {
console.log(`Loading service ${service.id}`);

const localValue = await service.getLocal();

if (localValue && !serviceValues[service.id]) {
setServiceValues((values) => ({
...values,
[service.id]: localValue,
}));
}

const value = await service.get();

setServiceValues((values) => ({
...values,
[service.id]: value,
}));

if (service.id === "scouterSchedule") {
setScouterSchedule(async () => value as LocalCache<ScouterSchedule>);
console.log(`Loaded scouter schedule ${value.data.hash}`);
}
console.log(`Loaded service ${service.id}`);
} catch (e) {
console.error(`Failed to load service ${service.id}`);
console.error(e);
}
}));
setServicesLoading(false);
};
useEffect(() => {
const timeout = setTimeout(() => {
setStartMatchEnabled(true);
}, 2000);

useEffect(() => {
loadServices();
return () => {
clearTimeout(timeout);
};
});

const interval = setInterval(loadServices, 2 * 60 * 1000);
const [fontsLoaded, fontError] = useFonts({
Heebo_400Regular,
Heebo_500Medium,
Heebo_600SemiBold,
Heebo_700Bold,
MaterialSymbols_500Rounded: require("../assets/fonts/Material-Symbols-Rounded.ttf"),
MaterialSymbols_500Rounded40px: require("../assets/fonts/Material-Symbols-Rounded-40px.ttf"),
MaterialSymbols_500Rounded48px: require("../assets/fonts/Material-Symbols-Rounded-48px.ttf"),
});

return () => clearInterval(interval);
}, []);
const setScouterSchedule = useSetAtom(scouterScheduleAtom);

if (!fontsLoaded && !fontError) {
return null;
const onLayoutRootView = useCallback(async () => {
if (fontsLoaded || fontError) {
await SplashScreen.hideAsync();
}

return (
<ServicesContext.Provider value={serviceValues}>
<LoadServicesContext.Provider
value={async () => {
await loadServices();
}}
>
<View style={{ backgroundColor: colors.background.default, flex: 1 }} onLayout={onLayoutRootView}>
<Stack screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor: colors.background.default,
}
}} />
</View>
</LoadServicesContext.Provider>
</ServicesContext.Provider>
}, [fontsLoaded, fontError]);

const [serviceValues, setServiceValues] = useState<ServiceValues>({
teamScouters: null,
tournaments: null,
scouterSchedule: null,
});

const loadServices = async () => {
setServicesLoading(true);
await Promise.allSettled(
services.map(async (service) => {
try {
console.log(`Loading service ${service.id}`);

const localValue = await service.getLocal();

if (localValue && !serviceValues[service.id]) {
setServiceValues((values) => ({
...values,
[service.id]: localValue,
}));
}

const value = await service.get();

setServiceValues((values) => ({
...values,
[service.id]: value,
}));

if (service.id === "scouterSchedule") {
setScouterSchedule(
async () => value as LocalCache<ScouterSchedule>,
);
console.log(`Loaded scouter schedule ${value.data.hash}`);
}
console.log(`Loaded service ${service.id}`);
} catch (e) {
console.error(`Failed to load service ${service.id}`);
console.error(e);
}
}),
);
setServicesLoading(false);
};

useEffect(() => {
loadServices();

const interval = setInterval(loadServices, 2 * 60 * 1000);

return () => clearInterval(interval);
}, []);

if (!fontsLoaded && !fontError) {
return null;
}

return (
<ServicesContext.Provider value={serviceValues}>
<LoadServicesContext.Provider
value={async () => {
await loadServices();
}}
>
<View
style={{ backgroundColor: colors.background.default, flex: 1 }}
onLayout={onLayoutRootView}
>
<Stack
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor: colors.background.default,
},
}}
/>
</View>
</LoadServicesContext.Provider>
</ServicesContext.Provider>
);
}
63 changes: 35 additions & 28 deletions app/game/index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
import { Suspense, useCallback } from 'react';
import { Game } from '../../lib/collection/ui/Game';
import { ActivityIndicator, Platform } from 'react-native';
import * as NavigationBar from 'expo-navigation-bar';
import { Stack, useFocusEffect } from 'expo-router';
import { Suspense, useCallback } from "react";
import { Game } from "../../lib/collection/ui/Game";
import { ActivityIndicator, Platform } from "react-native";
import * as NavigationBar from "expo-navigation-bar";
import { Stack, useFocusEffect } from "expo-router";

export default function GamePage() {
useFocusEffect(useCallback(() => {
useFocusEffect(
useCallback(() => {
(async () => {
if (Platform.OS === "android") {
await NavigationBar.setVisibilityAsync("hidden");
}
})();

return () => {
(async () => {
if (Platform.OS === "android") {
await NavigationBar.setVisibilityAsync("hidden");
}
if (Platform.OS === "android") {
await NavigationBar.setVisibilityAsync("visible");
}
})();
};
}, []),
);

return () => {
(async () => {
if (Platform.OS === "android") {
await NavigationBar.setVisibilityAsync("visible");
}
})();
};
}, []));

return (
<>
<Stack.Screen options={{ orientation: 'landscape', animationDuration: 0, animationTypeForReplace: "push", animation: "flip" }} />
<Suspense fallback={<ActivityIndicator />}>
<Game />
</Suspense>
</>
)
return (
<>
<Stack.Screen
options={{
orientation: "landscape",
animationDuration: 0,
animationTypeForReplace: "push",
animation: "flip",
}}
/>
<Suspense fallback={<ActivityIndicator />}>
<Game />
</Suspense>
</>
);
}


Loading

0 comments on commit b5abb28

Please sign in to comment.