Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor fix suggestions #29

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TabBarIcon } from '@/components';
import { GlobalStateProvider } from '@/hooks/providers/GlobalStateProvider';
import { useFavoriteStoreStatus } from '@/hooks/useFavorite';
import Locales from '@/locales';
import { Themes } from '@/styles';
import { useFonts } from 'expo-font';
Expand Down Expand Up @@ -34,13 +35,15 @@ export default function RootLayout() {
Roboto: require('../assets/fonts/Roboto-Regular.ttf'),
});

const { hydrated: favoriteStoreReady } = useFavoriteStoreStatus();

const { t } = useTranslation();

useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
if (loaded && favoriteStoreReady) {
SplashScreen.hideAsync().catch();
}
}, [loaded]);
}, [loaded, favoriteStoreReady]);

if (!loaded) {
return null;
Expand Down
8 changes: 6 additions & 2 deletions app/credits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { useTranslation } from 'react-i18next';
import { ImageBackground, View } from 'react-native';
import { ScrollView } from 'react-native';
import { Text, useTheme } from 'react-native-paper';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export default function Credits() {
const theme = useTheme();
const { t } = useTranslation();

const safeArea = useSafeAreaInsets();

return (
<ScrollView
style={{
Expand All @@ -15,7 +19,7 @@ export default function Credits() {
}}
contentContainerStyle={{
gap: 16,
paddingBottom: 16,
paddingBottom: safeArea.bottom,
}}
>
<View>
Expand Down Expand Up @@ -66,11 +70,11 @@ export default function Credits() {
<View style={{ gap: 16, paddingHorizontal: 16 }}>
<Text variant='bodyLarge'>Luukas Pörtfors</Text>
<Text variant='bodyLarge'>Otto Laakkonen</Text>
<Text variant='bodyLarge'>Eero Salla</Text>
<Text variant='bodyLarge'>Onni Linnala</Text>
<Text variant='bodyLarge'>Anto Keinänen</Text>
<Text variant='bodyLarge'>Samu Kupiainen</Text>
<Text variant='bodyLarge'>Miika Tuominen</Text>
<Text variant='bodyLarge'>Eero Salla</Text>
</View>
<Text
variant='bodyLarge'
Expand Down
95 changes: 64 additions & 31 deletions components/timetable/Event.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useFavorite } from '@/hooks/useFavorite';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Image, View } from 'react-native';
import { View } from 'react-native';
import { IconButton, Surface, Text } from 'react-native-paper';

interface EventProps {
Expand All @@ -26,10 +28,15 @@ const getEventTimeString = (start: Date, end: Date) => {
};

const Event = ({ id, title, location, start, end, color, thumbnail }: EventProps) => {
const timeString = getEventTimeString(start, end);
const { favorite, toggle: toggleFavorite } = useFavorite(id);
const timeString = useMemo(() => getEventTimeString(start, end), [start, end]);
const { isFavorite, setIsFavorite } = useFavorite(id);
const { t, i18n } = useTranslation();
dayjs.locale(i18n.language);

const [isAfterEnd, isBeforeStart] = useMemo(() => {
dayjs.locale(i18n.language);

return [dayjs().isAfter(end), dayjs().isBefore(start)];
}, [end, i18n.language, start]);

return (
<Surface
Expand All @@ -44,7 +51,7 @@ const Event = ({ id, title, location, start, end, color, thumbnail }: EventProps
}}
elevation={0}
>
{dayjs().isAfter(end) &&
{isAfterEnd &&
process.env.EXPO_PUBLIC_ENVIRONMENT !== 'development' &&
process.env.EXPO_PUBLIC_ENVIRONMENT !== 'preview' && (
<View
Expand All @@ -61,7 +68,8 @@ const Event = ({ id, title, location, start, end, color, thumbnail }: EventProps
{thumbnail && (
<Image
source={{ uri: thumbnail }}
resizeMode='cover'
contentFit='cover'
cachePolicy='memory-disk'
style={{
position: 'absolute',
top: 0,
Expand All @@ -86,35 +94,60 @@ const Event = ({ id, title, location, start, end, color, thumbnail }: EventProps
backgroundColor: 'rgba(0, 0, 0, 0.75)',
}}
/>
<Surface elevation={0} style={{ padding: 16, width: '100%', alignItems: 'center' }}>
<Text variant='titleMedium' style={{ textAlign: 'center' }}>
{title}
</Text>
{location && (

<Surface
elevation={0}
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
}}
>
<Surface
elevation={0}
style={{
padding: 16,
flex: 1,
alignItems: 'center',
paddingRight: 40,
marginRight: -40,
paddingLeft: 16 + 40,
display: 'flex',
}}
>
<Text
variant='labelLarge'
style={{ textAlign: 'center' }}
>{`${t('location')}: ${location}`}</Text>
)}
<Text variant='labelLarge' style={{ textAlign: 'center' }}>
{`${t('time')}: ${timeString}`}
</Text>
</Surface>
{dayjs().isBefore(start) ||
((process.env.EXPO_PUBLIC_ENVIRONMENT === 'development' ||
process.env.EXPO_PUBLIC_ENVIRONMENT === 'preview') && (
<IconButton
onPress={() => toggleFavorite()}
icon={favorite ? 'heart' : 'heart-outline'}
variant='titleMedium'
style={{
position: 'absolute',
top: 0,
right: 0,
textAlign: 'center',
}}
/>
))}
>
{title}
</Text>
{location && (
<Text
variant='labelLarge'
style={{ textAlign: 'center' }}
>{`${t('location')}: ${location}`}</Text>
)}
<Text variant='labelLarge' style={{ textAlign: 'center' }}>
{`${t('time')}: ${timeString}`}
</Text>
</Surface>
{isBeforeStart ||
((process.env.EXPO_PUBLIC_ENVIRONMENT === 'development' ||
process.env.EXPO_PUBLIC_ENVIRONMENT === 'preview') && (
<IconButton
onPress={() => setIsFavorite(!isFavorite)}
icon={isFavorite ? 'heart' : 'heart-outline'}
style={{
height: 40,
width: 40,
}}
/>
))}
</Surface>
</Surface>
);
};

export default Event;
export default React.memo(Event);
4 changes: 3 additions & 1 deletion elements/about/AboutWebview.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import WhitelistedWebview from '@/components/WhitelistedWebview';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ActivityIndicator } from 'react-native-paper';
import { ActivityIndicator, useTheme } from 'react-native-paper';

const AboutWebview = () => {
const [loading, setLoading] = useState(true);
const { i18n } = useTranslation();
const theme = useTheme();

const uri = `https://assembly.org/${i18n.language}/about`;
const whitelist = [
Expand All @@ -32,6 +33,7 @@ const AboutWebview = () => {
whitelistedUrls={whitelist}
style={{
display: loading ? 'none' : 'flex',
backgroundColor: theme.colors.background,
}}
onLoad={() => setLoading(false)}
source={{ uri }}
Expand Down
65 changes: 46 additions & 19 deletions elements/timetable/EventsBox.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,58 @@
import { AssemblyEvent } from '@/api/eventService';
import Event from '@/components/timetable/Event';
import { ScrollView } from 'react-native';
import React, { useEffect } from 'react';
import { VirtualizedList } from 'react-native';
import { ActivityIndicator } from 'react-native-paper';

interface EventsBoxProps {
events: AssemblyEvent[];
}

const EventsBox = ({ events }: EventsBoxProps) => {
const [loadedEvents, setLoadedEvents] = React.useState<AssemblyEvent[]>([]);

const isLoading = loadedEvents !== events;

useEffect(() => {
const timeout = setTimeout(() => {
setLoadedEvents(events);
}, 250);

return () => clearTimeout(timeout);
}, [events]);

return (
<ScrollView
style={{ paddingHorizontal: 30, paddingBottom: 8 }}
contentContainerStyle={{ gap: 8 }}
>
{events.map((event) => (
<Event
key={event.id}
id={event.id}
title={event.title}
location={event.location}
start={event.start}
end={event.end}
color={event.color}
thumbnail={event.thumbnail}
/>
))}
</ScrollView>
<>
{isLoading ? <ActivityIndicator style={{ margin: 16 }} /> : null}
<VirtualizedList<AssemblyEvent>
removeClippedSubviews={true}
pointerEvents={isLoading ? 'none' : 'auto'}
style={{
paddingHorizontal: 30,
paddingBottom: 8,
opacity: isLoading ? 0 : 1,
}}
renderItem={({ item: event }) => (
<Event
key={event.id}
id={event.id}
title={event.title}
location={event.location}
start={event.start}
end={event.end}
color={event.color}
thumbnail={event.thumbnail}
/>
)}
contentContainerStyle={{ gap: 8 }}
keyExtractor={(event) => event.id.toString()}
getItem={(data, index) => data[index]}
getItemCount={(_) => loadedEvents.length}
data={loadedEvents}
initialNumToRender={8}
/>
</>
);
};

export default EventsBox;
export default React.memo(EventsBox);
20 changes: 13 additions & 7 deletions elements/timetable/Timetable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,19 @@ const Timetable = () => {
<ActivityIndicator animating />
) : (
<>
<DateSelector
date={events[eventDayIndex][0].start}
next={next}
previous={previous}
nextVisible={eventDayIndex < events.length - 1}
previousVisible={eventDayIndex > 0}
/>
<View
style={{
zIndex: 2,
}}
>
<DateSelector
date={events[eventDayIndex][0].start}
next={next}
previous={previous}
nextVisible={eventDayIndex < events.length - 1}
previousVisible={eventDayIndex > 0}
/>
</View>
<View style={{ flex: 1 }}>
<EventsBox events={events[eventDayIndex] ?? []} />
</View>
Expand Down
Loading
Loading