filter, haptik, background
This commit is contained in:
@@ -2,6 +2,7 @@ import styles from "@/app/tabStyles/indexStyles";
|
||||
import ShowCard from "@/components/ui/ShowCard";
|
||||
import { useShowContext } from "@/contexts/ShowContext";
|
||||
import { useStreamingServiceContext } from "@/contexts/StreamingServiceContext";
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { router } from "expo-router";
|
||||
import React from "react";
|
||||
import {
|
||||
@@ -22,12 +23,19 @@ export default function HomeScreen() {
|
||||
const [filteredShows, setFilteredShows] = React.useState(shows);
|
||||
const [activeFilter, setActiveFilter] = React.useState<string>("all");
|
||||
|
||||
const haptikFeedback = () => {
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
setFilteredShows(shows);
|
||||
}, [shows]);
|
||||
|
||||
const handleFilter = (type: string) => {
|
||||
haptikFeedback();
|
||||
setActiveFilter(type);
|
||||
|
||||
|
||||
if (type === "all") {
|
||||
setFilteredShows(shows);
|
||||
return;
|
||||
@@ -39,12 +47,26 @@ export default function HomeScreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
const filtered = shows.filter((show) => show.streamingService === type);
|
||||
if (type === activeFilter) {
|
||||
setFilteredShows(shows);
|
||||
setActiveFilter('all');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const filtered = shows.filter((show) =>
|
||||
show.streamingService.split(',').map(s => s.trim()).includes(type)
|
||||
);
|
||||
setFilteredShows(filtered);
|
||||
};
|
||||
|
||||
const uniqueStreamingServices = React.useMemo(() => {
|
||||
const uniqueServices = new Set(shows.map((show) => show.streamingService));
|
||||
const uniqueServices = new Set<string>();
|
||||
shows.forEach((show) => {
|
||||
const services = show.streamingService.split(', ').map(s => s.trim());
|
||||
services.forEach(service => uniqueServices.add(service));
|
||||
});
|
||||
return Array.from(uniqueServices);
|
||||
}, [shows]);
|
||||
|
||||
@@ -95,48 +117,61 @@ export default function HomeScreen() {
|
||||
{activeFilter !== "all" && (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
padding: 2,
|
||||
height: 50,
|
||||
width: 50,
|
||||
padding: 5,
|
||||
height: 60,
|
||||
width: 60,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "hsl(221, 39%, 80%)",
|
||||
backgroundColor: "hsla(0, 0%, 29%, 1.00)",
|
||||
borderRadius: 50,
|
||||
}}
|
||||
onPress={() => handleFilter("all")}
|
||||
>
|
||||
<Text>ALLE</Text>
|
||||
<Text style={{fontWeight: 'bold', color: 'white'}}>ALLE</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{activeFilter !== "live" && (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
padding: 2,
|
||||
height: 50,
|
||||
width: 50,
|
||||
padding: 5,
|
||||
height: 60,
|
||||
width: 60,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "hsl(221, 39%, 80%)",
|
||||
backgroundColor: "hsla(0, 0%, 29%, 1.00)",
|
||||
borderRadius: 50,
|
||||
}}
|
||||
onPress={() => handleFilter("live")}
|
||||
>
|
||||
<Text>LIVE</Text>
|
||||
<View style={{backgroundColor: "red", paddingHorizontal: 5, paddingVertical: 2, borderRadius: 5}}>
|
||||
<Text style={{fontWeight: 'bold', color: 'white'}}>LIVE</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
<View style={{
|
||||
height: 60,
|
||||
width: 2,
|
||||
backgroundColor: "hsla(0, 0%, 37%, 1.00)",
|
||||
marginHorizontal: 5,
|
||||
borderRadius: 5,
|
||||
|
||||
}} />
|
||||
|
||||
{uniqueStreamingServices.map((serviceName) => {
|
||||
const streamingService =
|
||||
streamingServices[
|
||||
`assets.images.streamingServices.${serviceName.toLowerCase()}`
|
||||
`assets.images.streamingServices.${serviceName.toLowerCase()}`
|
||||
];
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={serviceName}
|
||||
style={{
|
||||
padding: 2,
|
||||
backgroundColor: "hsl(221, 39%, 80%)",
|
||||
padding: 5,
|
||||
backgroundColor: "hsla(0, 0%, 29%, 1.00)",
|
||||
borderRadius: 50,
|
||||
borderWidth: serviceName.includes(activeFilter) ? 2 : 0,
|
||||
borderColor: "hsla(0, 100%, 50%, 1.00)",
|
||||
}}
|
||||
onPress={() => handleFilter(serviceName)}
|
||||
>
|
||||
@@ -154,45 +189,43 @@ export default function HomeScreen() {
|
||||
})}
|
||||
</ScrollView>
|
||||
</View>
|
||||
{filteredShows.map((show) => {
|
||||
const showLiveBadge = show.running;
|
||||
const streamingService =
|
||||
streamingServices[
|
||||
`assets.images.streamingServices.${show.streamingService.toLowerCase()}`
|
||||
];
|
||||
<View style={{ flex: 1, paddingHorizontal: 10 }}>
|
||||
{filteredShows.map((show) => {
|
||||
const showLiveBadge = show.running;
|
||||
|
||||
return (
|
||||
<ShowCard
|
||||
key={show.id}
|
||||
title={show.title}
|
||||
onPress={() =>
|
||||
router.push({
|
||||
pathname: "/showDetails",
|
||||
params: {
|
||||
id: String(show.id),
|
||||
title: show.title,
|
||||
bannerUri: show.bannerUri,
|
||||
description: show.description,
|
||||
concept: show.concept,
|
||||
genres: show.genres,
|
||||
streamingService: show.streamingService,
|
||||
logoUri: show.logoUrl,
|
||||
running: String(show.running),
|
||||
},
|
||||
})
|
||||
}
|
||||
imageUri={show.bannerUri}
|
||||
streamingServiceUri={streamingService}
|
||||
genres={show.genres}
|
||||
{...(showLiveBadge
|
||||
? {
|
||||
return (
|
||||
<ShowCard
|
||||
key={show.id}
|
||||
title={show.title}
|
||||
onPress={() =>
|
||||
router.push({
|
||||
pathname: "/showDetails",
|
||||
params: {
|
||||
id: String(show.id),
|
||||
title: show.title,
|
||||
bannerUri: show.bannerUri,
|
||||
description: show.description,
|
||||
concept: show.concept,
|
||||
genres: show.genres,
|
||||
streamingService: show.streamingService,
|
||||
logoUri: show.logoUrl,
|
||||
running: String(show.running),
|
||||
},
|
||||
})
|
||||
}
|
||||
imageUri={show.bannerUri}
|
||||
streamingServicesUris={show.streamingService.split(', ').map(s => streamingServices[`assets.images.streamingServices.${s.toLowerCase()}`])}
|
||||
genres={show.genres}
|
||||
{...(showLiveBadge
|
||||
? {
|
||||
liveBadgeText: "LIVE",
|
||||
liveBadgeContainerStyle: styles.liveBadgeContainer,
|
||||
}
|
||||
: {})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
: {})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</GestureHandlerRootView>
|
||||
|
||||
@@ -179,7 +179,8 @@ export default function ParticipantScreen() {
|
||||
<GestureHandlerRootView style={styles.mainContainer}>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={{ paddingBottom: 20, paddingTop: 10 }}
|
||||
contentContainerStyle={{ paddingBottom: 20, paddingTop: 10}}
|
||||
|
||||
>
|
||||
<Text style={styles.participantName}>{name}</Text>
|
||||
<TouchableOpacity
|
||||
@@ -214,7 +215,7 @@ export default function ParticipantScreen() {
|
||||
paddingLeft: 30,
|
||||
}}
|
||||
>
|
||||
{appearances.map(({ show, seasons }) => {
|
||||
{appearances.toReversed().map(({ show, seasons }) => {
|
||||
const partners = Array.from(
|
||||
new Map(
|
||||
seasons
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { getShowById, Show } from "@/apis/showApi";
|
||||
import ParticipantDetails from "@/components/ParticipantDeatails";
|
||||
import ShowInfo from "@/components/ui/ShowInfo";
|
||||
import StackHeader from "@/components/ui/StackHeader";
|
||||
import { useSeasonContext } from "@/contexts/SeasonContext";
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Dimensions,
|
||||
Image,
|
||||
@@ -16,14 +18,18 @@ import styles from "./stackStyles/showDetailStyles";
|
||||
|
||||
export default function ShowDetails() {
|
||||
const {
|
||||
bannerUri,
|
||||
description,
|
||||
concept,
|
||||
genres,
|
||||
streamingService,
|
||||
// bannerUri,
|
||||
// description,
|
||||
// concept,
|
||||
// genres,
|
||||
// streamingService,
|
||||
id,
|
||||
endDate,
|
||||
// endDate,
|
||||
} = useLocalSearchParams();
|
||||
|
||||
const [show, setShow] = useState<Show | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [selectedParticipants, setSelectedParticipants] =
|
||||
React.useState<boolean>(true);
|
||||
const [selectedSeason, setSelectedSeason] = React.useState<number>(1);
|
||||
@@ -48,6 +54,18 @@ export default function ShowDetails() {
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!showId) return;
|
||||
|
||||
const fetchShow = async () => {
|
||||
try {
|
||||
const data = await getShowById(showId);
|
||||
setShow(data);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchShow();
|
||||
|
||||
let active = true;
|
||||
(async () => {
|
||||
const count = await fetchSeasonCount(showId);
|
||||
@@ -128,15 +146,15 @@ export default function ShowDetails() {
|
||||
<ShowInfo
|
||||
seasons={seasonCount}
|
||||
participants={participants.length}
|
||||
streamingService={streamingService as string}
|
||||
streamingService={show?.streamingService as string}
|
||||
startDate={startDate as string}
|
||||
endDate={endDate as string | null}
|
||||
endDate={show?.endDate as string | null}
|
||||
/>
|
||||
|
||||
<View style={styles.showBannerLogoContainer}>
|
||||
<Image
|
||||
source={{
|
||||
uri: bannerUri as string,
|
||||
uri: show?.bannerUri as string,
|
||||
}}
|
||||
style={styles.showBannerLogo}
|
||||
resizeMode="cover"
|
||||
@@ -194,6 +212,7 @@ export default function ShowDetails() {
|
||||
]}
|
||||
onPress={() => {
|
||||
setSelectedSeason(season);
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
}}
|
||||
>
|
||||
<Text style={styles.seasonLabel}>{season}</Text>
|
||||
@@ -241,10 +260,10 @@ export default function ShowDetails() {
|
||||
</>
|
||||
) : (
|
||||
<ParticipantDetails
|
||||
description={description as string}
|
||||
concept={concept as string}
|
||||
genres={genres as string}
|
||||
streamingService={streamingService as string}
|
||||
description={show?.description as string}
|
||||
concept={show?.concept as string}
|
||||
genres={show?.genres as string[]}
|
||||
streamingService={show?.streamingService as string}
|
||||
/>
|
||||
)}
|
||||
</ScrollView>
|
||||
|
||||
@@ -50,7 +50,7 @@ const styles = StyleSheet.create({
|
||||
performedShowsSection: {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "hsl(221, 39%, 0%)",
|
||||
backgroundColor: 'hsl(221, 39%, 16%)',
|
||||
marginTop: 20,
|
||||
},
|
||||
performedShowsTitle: {
|
||||
@@ -175,7 +175,7 @@ const styles = StyleSheet.create({
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "hsl(221, 39%, 18%)",
|
||||
backgroundColor: "hsl(221, 39%, 12%)",
|
||||
marginLeft: 15,
|
||||
marginTop: 15,
|
||||
marginBottom: 5,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
|
||||
type ParticipantDetailsProps = {
|
||||
description: string;
|
||||
concept: string;
|
||||
genres: string;
|
||||
genres: string[];
|
||||
streamingService: string;
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ const ParticipantDetails = ({
|
||||
<Text style={styles.detailTitle}>Konzept:</Text>
|
||||
<Text style={styles.detailLabel}>{concept}</Text>
|
||||
<Text style={styles.detailTitle}>Genres:</Text>
|
||||
<Text style={styles.detailLabel}>{genres}</Text>
|
||||
<Text style={styles.detailLabel}>{genres.join(', ')}</Text>
|
||||
<Text style={styles.detailTitle}>Produktion:</Text>
|
||||
<Text style={styles.detailLabel}>{streamingService}</Text>
|
||||
</View>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
||||
|
||||
type ShowCardProps = {
|
||||
imageUri: string;
|
||||
streamingServiceUri: string;
|
||||
streamingServicesUris: string[];
|
||||
liveBadgeText?: string;
|
||||
liveBadgeContainerStyle?: object;
|
||||
genres: string[];
|
||||
@@ -13,7 +13,7 @@ type ShowCardProps = {
|
||||
|
||||
const ShowCard = ({
|
||||
imageUri,
|
||||
streamingServiceUri,
|
||||
streamingServicesUris,
|
||||
liveBadgeText,
|
||||
liveBadgeContainerStyle,
|
||||
genres,
|
||||
@@ -32,14 +32,20 @@ const ShowCard = ({
|
||||
}}
|
||||
style={[StyleSheet.absoluteFillObject, { borderRadius: 35 }]}
|
||||
/>
|
||||
<View style={styles.streamingServiceIcon}>
|
||||
<Image
|
||||
source={{
|
||||
uri: streamingServiceUri,
|
||||
}}
|
||||
style={[StyleSheet.absoluteFillObject, { borderRadius: 15 }]}
|
||||
/>
|
||||
|
||||
<View style={{ flexDirection: 'row', width: '100%', justifyContent: 'flex-end', padding: 10, gap: 5}}>
|
||||
{streamingServicesUris.length > 0 && streamingServicesUris.map((service) => (
|
||||
<Image
|
||||
key={service}
|
||||
source={{
|
||||
uri: service,
|
||||
}}
|
||||
style={{ height: 45, width: 45, resizeMode: 'contain', borderRadius: 100}}
|
||||
/>
|
||||
|
||||
))}
|
||||
</View>
|
||||
|
||||
{liveBadgeText && (
|
||||
<View style={liveBadgeContainerStyle}>
|
||||
<Text style={styles.liveBadgeText}>{liveBadgeText}</Text>
|
||||
@@ -70,8 +76,8 @@ const ShowCard = ({
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
showContainer: {
|
||||
width: "90%",
|
||||
height: 200,
|
||||
width: "100%",
|
||||
height: 220,
|
||||
backgroundColor: "transparent",
|
||||
alignSelf: "center",
|
||||
borderRadius: 35,
|
||||
|
||||
@@ -20,9 +20,9 @@ export default function StackHeader() {
|
||||
<Feather name="arrow-left" size={26} color="white" />
|
||||
</TouchableOpacity>
|
||||
<Image style={styles.logo} source={{ uri: logoUriString }} />
|
||||
<TouchableOpacity>
|
||||
{/* <TouchableOpacity>
|
||||
<Feather name="share" size={26} color="white" />
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity> */}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
"name": "fltr-app",
|
||||
"main": "expo-router/entry",
|
||||
"version": "1.0.0",
|
||||
"displayName": "FLTR",
|
||||
"description": "Reality TV",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"reset-project": "node ./scripts/reset-project.js",
|
||||
|
||||
Reference in New Issue
Block a user