filter, haptik, background

This commit is contained in:
DevOFVictory
2025-10-28 22:42:19 +01:00
parent 6b39579c75
commit 21cd6c3241
8 changed files with 145 additions and 84 deletions

View File

@@ -2,6 +2,7 @@ import styles from "@/app/tabStyles/indexStyles";
import ShowCard from "@/components/ui/ShowCard"; import ShowCard from "@/components/ui/ShowCard";
import { useShowContext } from "@/contexts/ShowContext"; import { useShowContext } from "@/contexts/ShowContext";
import { useStreamingServiceContext } from "@/contexts/StreamingServiceContext"; import { useStreamingServiceContext } from "@/contexts/StreamingServiceContext";
import * as Haptics from 'expo-haptics';
import { router } from "expo-router"; import { router } from "expo-router";
import React from "react"; import React from "react";
import { import {
@@ -22,12 +23,19 @@ export default function HomeScreen() {
const [filteredShows, setFilteredShows] = React.useState(shows); const [filteredShows, setFilteredShows] = React.useState(shows);
const [activeFilter, setActiveFilter] = React.useState<string>("all"); const [activeFilter, setActiveFilter] = React.useState<string>("all");
const haptikFeedback = () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
React.useEffect(() => { React.useEffect(() => {
setFilteredShows(shows); setFilteredShows(shows);
}, [shows]); }, [shows]);
const handleFilter = (type: string) => { const handleFilter = (type: string) => {
haptikFeedback();
setActiveFilter(type); setActiveFilter(type);
if (type === "all") { if (type === "all") {
setFilteredShows(shows); setFilteredShows(shows);
return; return;
@@ -39,12 +47,26 @@ export default function HomeScreen() {
return; 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); setFilteredShows(filtered);
}; };
const uniqueStreamingServices = React.useMemo(() => { 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); return Array.from(uniqueServices);
}, [shows]); }, [shows]);
@@ -95,36 +117,47 @@ export default function HomeScreen() {
{activeFilter !== "all" && ( {activeFilter !== "all" && (
<TouchableOpacity <TouchableOpacity
style={{ style={{
padding: 2, padding: 5,
height: 50, height: 60,
width: 50, width: 60,
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
backgroundColor: "hsl(221, 39%, 80%)", backgroundColor: "hsla(0, 0%, 29%, 1.00)",
borderRadius: 50, borderRadius: 50,
}} }}
onPress={() => handleFilter("all")} onPress={() => handleFilter("all")}
> >
<Text>ALLE</Text> <Text style={{fontWeight: 'bold', color: 'white'}}>ALLE</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
{activeFilter !== "live" && ( {activeFilter !== "live" && (
<TouchableOpacity <TouchableOpacity
style={{ style={{
padding: 2, padding: 5,
height: 50, height: 60,
width: 50, width: 60,
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
backgroundColor: "hsl(221, 39%, 80%)", backgroundColor: "hsla(0, 0%, 29%, 1.00)",
borderRadius: 50, borderRadius: 50,
}} }}
onPress={() => handleFilter("live")} 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> </TouchableOpacity>
)} )}
<View style={{
height: 60,
width: 2,
backgroundColor: "hsla(0, 0%, 37%, 1.00)",
marginHorizontal: 5,
borderRadius: 5,
}} />
{uniqueStreamingServices.map((serviceName) => { {uniqueStreamingServices.map((serviceName) => {
const streamingService = const streamingService =
streamingServices[ streamingServices[
@@ -134,9 +167,11 @@ export default function HomeScreen() {
<TouchableOpacity <TouchableOpacity
key={serviceName} key={serviceName}
style={{ style={{
padding: 2, padding: 5,
backgroundColor: "hsl(221, 39%, 80%)", backgroundColor: "hsla(0, 0%, 29%, 1.00)",
borderRadius: 50, borderRadius: 50,
borderWidth: serviceName.includes(activeFilter) ? 2 : 0,
borderColor: "hsla(0, 100%, 50%, 1.00)",
}} }}
onPress={() => handleFilter(serviceName)} onPress={() => handleFilter(serviceName)}
> >
@@ -154,12 +189,9 @@ export default function HomeScreen() {
})} })}
</ScrollView> </ScrollView>
</View> </View>
<View style={{ flex: 1, paddingHorizontal: 10 }}>
{filteredShows.map((show) => { {filteredShows.map((show) => {
const showLiveBadge = show.running; const showLiveBadge = show.running;
const streamingService =
streamingServices[
`assets.images.streamingServices.${show.streamingService.toLowerCase()}`
];
return ( return (
<ShowCard <ShowCard
@@ -182,7 +214,7 @@ export default function HomeScreen() {
}) })
} }
imageUri={show.bannerUri} imageUri={show.bannerUri}
streamingServiceUri={streamingService} streamingServicesUris={show.streamingService.split(', ').map(s => streamingServices[`assets.images.streamingServices.${s.toLowerCase()}`])}
genres={show.genres} genres={show.genres}
{...(showLiveBadge {...(showLiveBadge
? { ? {
@@ -193,6 +225,7 @@ export default function HomeScreen() {
/> />
); );
})} })}
</View>
</ScrollView> </ScrollView>
</View> </View>
</GestureHandlerRootView> </GestureHandlerRootView>

View File

@@ -180,6 +180,7 @@ export default function ParticipantScreen() {
<ScrollView <ScrollView
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 20, paddingTop: 10}} contentContainerStyle={{ paddingBottom: 20, paddingTop: 10}}
> >
<Text style={styles.participantName}>{name}</Text> <Text style={styles.participantName}>{name}</Text>
<TouchableOpacity <TouchableOpacity
@@ -214,7 +215,7 @@ export default function ParticipantScreen() {
paddingLeft: 30, paddingLeft: 30,
}} }}
> >
{appearances.map(({ show, seasons }) => { {appearances.toReversed().map(({ show, seasons }) => {
const partners = Array.from( const partners = Array.from(
new Map( new Map(
seasons seasons

View File

@@ -1,9 +1,11 @@
import { getShowById, Show } from "@/apis/showApi";
import ParticipantDetails from "@/components/ParticipantDeatails"; import ParticipantDetails from "@/components/ParticipantDeatails";
import ShowInfo from "@/components/ui/ShowInfo"; import ShowInfo from "@/components/ui/ShowInfo";
import StackHeader from "@/components/ui/StackHeader"; import StackHeader from "@/components/ui/StackHeader";
import { useSeasonContext } from "@/contexts/SeasonContext"; import { useSeasonContext } from "@/contexts/SeasonContext";
import * as Haptics from 'expo-haptics';
import { router, useLocalSearchParams } from "expo-router"; import { router, useLocalSearchParams } from "expo-router";
import React from "react"; import React, { useState } from "react";
import { import {
Dimensions, Dimensions,
Image, Image,
@@ -16,14 +18,18 @@ import styles from "./stackStyles/showDetailStyles";
export default function ShowDetails() { export default function ShowDetails() {
const { const {
bannerUri, // bannerUri,
description, // description,
concept, // concept,
genres, // genres,
streamingService, // streamingService,
id, id,
endDate, // endDate,
} = useLocalSearchParams(); } = useLocalSearchParams();
const [show, setShow] = useState<Show | null>(null);
const [loading, setLoading] = useState(true);
const [selectedParticipants, setSelectedParticipants] = const [selectedParticipants, setSelectedParticipants] =
React.useState<boolean>(true); React.useState<boolean>(true);
const [selectedSeason, setSelectedSeason] = React.useState<number>(1); const [selectedSeason, setSelectedSeason] = React.useState<number>(1);
@@ -48,6 +54,18 @@ export default function ShowDetails() {
React.useEffect(() => { React.useEffect(() => {
if (!showId) return; if (!showId) return;
const fetchShow = async () => {
try {
const data = await getShowById(showId);
setShow(data);
} finally {
setLoading(false);
}
};
fetchShow();
let active = true; let active = true;
(async () => { (async () => {
const count = await fetchSeasonCount(showId); const count = await fetchSeasonCount(showId);
@@ -128,15 +146,15 @@ export default function ShowDetails() {
<ShowInfo <ShowInfo
seasons={seasonCount} seasons={seasonCount}
participants={participants.length} participants={participants.length}
streamingService={streamingService as string} streamingService={show?.streamingService as string}
startDate={startDate as string} startDate={startDate as string}
endDate={endDate as string | null} endDate={show?.endDate as string | null}
/> />
<View style={styles.showBannerLogoContainer}> <View style={styles.showBannerLogoContainer}>
<Image <Image
source={{ source={{
uri: bannerUri as string, uri: show?.bannerUri as string,
}} }}
style={styles.showBannerLogo} style={styles.showBannerLogo}
resizeMode="cover" resizeMode="cover"
@@ -194,6 +212,7 @@ export default function ShowDetails() {
]} ]}
onPress={() => { onPress={() => {
setSelectedSeason(season); setSelectedSeason(season);
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}} }}
> >
<Text style={styles.seasonLabel}>{season}</Text> <Text style={styles.seasonLabel}>{season}</Text>
@@ -241,10 +260,10 @@ export default function ShowDetails() {
</> </>
) : ( ) : (
<ParticipantDetails <ParticipantDetails
description={description as string} description={show?.description as string}
concept={concept as string} concept={show?.concept as string}
genres={genres as string} genres={show?.genres as string[]}
streamingService={streamingService as string} streamingService={show?.streamingService as string}
/> />
)} )}
</ScrollView> </ScrollView>

View File

@@ -50,7 +50,7 @@ const styles = StyleSheet.create({
performedShowsSection: { performedShowsSection: {
width: "100%", width: "100%",
height: "100%", height: "100%",
backgroundColor: "hsl(221, 39%, 0%)", backgroundColor: 'hsl(221, 39%, 16%)',
marginTop: 20, marginTop: 20,
}, },
performedShowsTitle: { performedShowsTitle: {
@@ -175,7 +175,7 @@ const styles = StyleSheet.create({
width: 50, width: 50,
height: 50, height: 50,
borderRadius: 20, borderRadius: 20,
backgroundColor: "hsl(221, 39%, 18%)", backgroundColor: "hsl(221, 39%, 12%)",
marginLeft: 15, marginLeft: 15,
marginTop: 15, marginTop: 15,
marginBottom: 5, marginBottom: 5,

View File

@@ -1,9 +1,9 @@
import { View, Text, StyleSheet } from "react-native"; import { StyleSheet, Text, View } from "react-native";
type ParticipantDetailsProps = { type ParticipantDetailsProps = {
description: string; description: string;
concept: string; concept: string;
genres: string; genres: string[];
streamingService: string; streamingService: string;
}; };
@@ -20,7 +20,7 @@ const ParticipantDetails = ({
<Text style={styles.detailTitle}>Konzept:</Text> <Text style={styles.detailTitle}>Konzept:</Text>
<Text style={styles.detailLabel}>{concept}</Text> <Text style={styles.detailLabel}>{concept}</Text>
<Text style={styles.detailTitle}>Genres:</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.detailTitle}>Produktion:</Text>
<Text style={styles.detailLabel}>{streamingService}</Text> <Text style={styles.detailLabel}>{streamingService}</Text>
</View> </View>

View File

@@ -3,7 +3,7 @@ import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native";
type ShowCardProps = { type ShowCardProps = {
imageUri: string; imageUri: string;
streamingServiceUri: string; streamingServicesUris: string[];
liveBadgeText?: string; liveBadgeText?: string;
liveBadgeContainerStyle?: object; liveBadgeContainerStyle?: object;
genres: string[]; genres: string[];
@@ -13,7 +13,7 @@ type ShowCardProps = {
const ShowCard = ({ const ShowCard = ({
imageUri, imageUri,
streamingServiceUri, streamingServicesUris,
liveBadgeText, liveBadgeText,
liveBadgeContainerStyle, liveBadgeContainerStyle,
genres, genres,
@@ -32,14 +32,20 @@ const ShowCard = ({
}} }}
style={[StyleSheet.absoluteFillObject, { borderRadius: 35 }]} style={[StyleSheet.absoluteFillObject, { borderRadius: 35 }]}
/> />
<View style={styles.streamingServiceIcon}>
<View style={{ flexDirection: 'row', width: '100%', justifyContent: 'flex-end', padding: 10, gap: 5}}>
{streamingServicesUris.length > 0 && streamingServicesUris.map((service) => (
<Image <Image
key={service}
source={{ source={{
uri: streamingServiceUri, uri: service,
}} }}
style={[StyleSheet.absoluteFillObject, { borderRadius: 15 }]} style={{ height: 45, width: 45, resizeMode: 'contain', borderRadius: 100}}
/> />
))}
</View> </View>
{liveBadgeText && ( {liveBadgeText && (
<View style={liveBadgeContainerStyle}> <View style={liveBadgeContainerStyle}>
<Text style={styles.liveBadgeText}>{liveBadgeText}</Text> <Text style={styles.liveBadgeText}>{liveBadgeText}</Text>
@@ -70,8 +76,8 @@ const ShowCard = ({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
showContainer: { showContainer: {
width: "90%", width: "100%",
height: 200, height: 220,
backgroundColor: "transparent", backgroundColor: "transparent",
alignSelf: "center", alignSelf: "center",
borderRadius: 35, borderRadius: 35,

View File

@@ -20,9 +20,9 @@ export default function StackHeader() {
<Feather name="arrow-left" size={26} color="white" /> <Feather name="arrow-left" size={26} color="white" />
</TouchableOpacity> </TouchableOpacity>
<Image style={styles.logo} source={{ uri: logoUriString }} /> <Image style={styles.logo} source={{ uri: logoUriString }} />
<TouchableOpacity> {/* <TouchableOpacity>
<Feather name="share" size={26} color="white" /> <Feather name="share" size={26} color="white" />
</TouchableOpacity> </TouchableOpacity> */}
</View> </View>
); );
} }

View File

@@ -2,6 +2,8 @@
"name": "fltr-app", "name": "fltr-app",
"main": "expo-router/entry", "main": "expo-router/entry",
"version": "1.0.0", "version": "1.0.0",
"displayName": "FLTR",
"description": "Reality TV",
"scripts": { "scripts": {
"start": "expo start", "start": "expo start",
"reset-project": "node ./scripts/reset-project.js", "reset-project": "node ./scripts/reset-project.js",