UI changes and Android compatibility

This commit is contained in:
2026-03-05 13:14:26 +01:00
parent fe07112b1f
commit 0d944a6e46
10 changed files with 104 additions and 96 deletions

View File

@@ -3,6 +3,7 @@ import { StyleSheet, Text, View, Pressable } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createContext, useState, useContext } from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import MediaPlayer from "./src/components/MediaPlayer";
@@ -26,9 +27,7 @@ export function UsePlayer() {
}
function PlayerProvider({ children }) {
const [currentTrack, setCurrentTrack] = useState({
title: "Swans - A Piece Of The Sky",
});
const [currentTrack, setCurrentTrack] = useState();
const [isPlaying, setIsPlaying] = useState(false);
@@ -61,7 +60,7 @@ function RootLayout() {
const { currentTrack } = UsePlayer();
return (
<View style={styles.container}>
<SafeAreaProvider style={styles.container}>
<StatusBar style="auto" />
<AppNavigator />
@@ -69,7 +68,7 @@ function RootLayout() {
<View style={styles.mediaPlayerWrapper} pointerEvents="box-none">
<MediaPlayer title={currentTrack?.title ?? "No track"} />
</View>
</View>
</SafeAreaProvider>
);
}

View File

@@ -1,33 +1,38 @@
import { useState } from "react";
import { TouchableOpacity, Text, StyleSheet } from "react-native";
import { View } from "react-native-web";
import { View, Text, StyleSheet } from "react-native";
import { Button, Slider } from "rn-inkpad";
import { LinearGradient } from "expo-linear-gradient";
export default function MediaPlayer({ title, onPress }) {
export default function MediaPlayer() {
const [isPlaying, setIsPlaying] = useState(false);
const [progress, setProgress] = useState(35);
return (
<LinearGradient
colors={[
"rgba(25,25,25,0.95)", // top
"rgba(15,15,15,0.98)", // middle-top
"rgba(5,5,5,1)", // middle-bottom
"rgba(5,5,5,1)", // bottom
"rgba(25,25,25,0.95)",
"rgba(15,15,15,0.98)",
"rgba(5,5,5,1)",
"rgba(5,5,5,1)",
]}
locations={[0, 0.55, 1]}
locations={[0, 0.55, 0.85, 1]}
start={{ x: 0.5, y: 0 }}
end={{ x: 0.5, y: 1 }}
style={styles.box}
>
<Text style={styles.name_album_and_artist}>{title}</Text>
<Text style={styles.name_album_and_artist}>
PlaceholderArtist - PlaceholderTrack
</Text>
<View style={styles.playback_row}>
<Text style={styles.time}>1:20</Text>
<View style={styles.slider_wrapper}>
<Slider
value={35}
value={progress}
min={0}
max={100}
onChange={setProgress}
onValueChange={setProgress}
trackStyles={{
height: 5,
borderRadius: 5,
@@ -39,7 +44,6 @@ export default function MediaPlayer({ title, onPress }) {
}}
/>
</View>
<Text style={styles.time}>4:08</Text>
</View>
@@ -57,12 +61,14 @@ export default function MediaPlayer({ title, onPress }) {
const styles = StyleSheet.create({
box: {
borderRadius: 15,
padding: 20,
paddingHorizontal: 16,
paddingTop: 12,
paddingBottom: 10,
alignSelf: "stretch",
marginHorizontal: 5,
height: "20%",
minHeight: 120,
justifyContent: "space-between",
alignItems: "center",
opacity: 0.98,
},
name_album_and_artist: {
color: "#ffffff",
@@ -70,11 +76,10 @@ const styles = StyleSheet.create({
fontWeight: "bold",
},
playback_row: {
flex: 1,
flexDirection: "row",
width: "100%",
alignItems: "center",
marginTop: 15,
marginTop: 10,
},
slider_wrapper: {
flex: 1,
@@ -84,4 +89,4 @@ const styles = StyleSheet.create({
color: "#ffffff",
fontWeight: "bold",
},
});
});

View File

@@ -1,5 +1,6 @@
import React from 'react';
import { Pressable, View, Text, StyleSheet, Image } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { durationFormatter } from './DurationFormatter';
export default function TrackRow({
@@ -16,20 +17,22 @@ export default function TrackRow({
{cover ? <Image source={cover} style={styles.trackCover} resizeMode="cover" /> : null}
<View style={styles.trackTextBlock}>
<Text style={styles.trackTitle} numberOfLines={1}>
{title}
</Text>
<Text style={styles.trackArtist} numberOfLines={1}>
{artist}
</Text>
<Text style={styles.trackTitle} numberOfLines={1}>{title}</Text>
<Text style={styles.trackArtist} numberOfLines={1}>{artist}</Text>
</View>
{duration ? <Text style={styles.trackDuration}>{durationFormatter(duration)}</Text> : "0"}
{duration ? (
<Text style={styles.trackDuration}>{durationFormatter(duration)}</Text>
) : (
<Text style={styles.trackDuration}>0:00</Text>
)}
<Pressable onPress={onToggleLike} hitSlop={10}>
<Text style={[styles.heart, liked && styles.heartLiked]}>
{liked ? '♥' : '♡'}
</Text>
<Pressable onPress={onToggleLike} hitSlop={10} style={styles.heartBtn}>
<Ionicons
name={liked ? "heart" : "heart-outline"}
size={22}
color={liked ? "#ff4d6d" : "#fff"}
/>
</Pressable>
</Pressable>
);
@@ -67,14 +70,9 @@ const styles = StyleSheet.create({
fontSize: 15,
paddingHorizontal: 18,
},
heart: {
fontSize: 22,
color: '#fff',
paddingHorizontal: 10,
},
heartLiked: {
fontSize: 22,
color: '#ff4d6d',
paddingHorizontal: 10,
heartBtn: {
width: 32,
alignItems: 'center',
justifyContent: 'center',
},
});

View File

@@ -1,5 +1,6 @@
import React, { useMemo } from 'react';
import { View, Text, StyleSheet, FlatList, Pressable, Image } from 'react-native';
import { SafeAreaView } from "react-native-safe-area-context";
import TrackRow from '../components/TrackRow';
import { useLibrary } from '../contexts/LibraryContext';
import { durationFormatter } from '../components/DurationFormatter';
@@ -8,14 +9,13 @@ export default function AlbumScreen({ route, navigation }) {
const { album: routeAlbum } = route.params;
const { albums, toggleLike } = useLibrary();
// Always use latest album from context (so likes stay in sync)
const album = useMemo(
() => albums.find((a) => a.id === routeAlbum.id) ?? routeAlbum,
[albums, routeAlbum]
);
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backText}> Back</Text>
</Pressable>
@@ -46,7 +46,7 @@ export default function AlbumScreen({ route, navigation }) {
)}
contentContainerStyle={styles.trackList}
/>
</View>
</SafeAreaView>
);
}
@@ -54,48 +54,11 @@ const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
paddingTop: 28,
paddingHorizontal: 16,
paddingBottom: 24,
},
header: {
alignItems: 'center',
},
cover: {
width: 180,
height: 180,
borderRadius: 8,
marginBottom: 12,
},
title: {
color: '#fff',
fontSize: 32,
fontWeight: '700',
textAlign: 'center',
marginBottom: 1,
},
artist: {
color: '#fff',
fontSize: 26,
fontWeight: '500',
textAlign: 'center',
marginTop: 1,
},
meta: {
color: '#fff',
fontSize: 14,
fontWeight: '500',
textAlign: 'center',
marginTop: 8,
marginBottom: 24,
},
trackList: {
width: '100%',
paddingHorizontal: 16,
paddingBottom: 180,
},
backBtn: {
marginBottom: 10,
marginBottom: 8,
alignSelf: 'flex-start',
},
backText: {
@@ -103,4 +66,41 @@ const styles = StyleSheet.create({
fontSize: 16,
fontWeight: '600',
},
header: {
alignItems: 'center',
marginBottom: 10,
},
cover: {
width: 140,
height: 140,
borderRadius: 8,
marginBottom: 8,
},
title: {
color: '#fff',
fontSize: 24,
fontWeight: '700',
textAlign: 'center',
marginBottom: 0,
},
artist: {
color: '#fff',
fontSize: 18,
fontWeight: '500',
textAlign: 'center',
marginTop: 1,
},
meta: {
color: '#cfcfcf',
fontSize: 12,
fontWeight: '500',
textAlign: 'center',
marginTop: 6,
marginBottom: 10,
},
trackList: {
width: '100%',
paddingHorizontal: 4,
paddingBottom: 180,
},
});

View File

@@ -11,6 +11,7 @@ import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import TrackRow from "../components/TrackRow";
import { useLibrary } from "../contexts/LibraryContext";
import { SafeAreaView } from "react-native-safe-area-context";
export default function HomeScreen() {
const navigation = useNavigation();
@@ -19,7 +20,7 @@ export default function HomeScreen() {
const homeLikedTracks = useMemo(() => likedTracks.slice(0, 5), [likedTracks]);
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<View style={styles.headerRow}>
<Text style={styles.homeTitle}>Home</Text>
<View style={styles.headerActions}>
@@ -77,7 +78,7 @@ export default function HomeScreen() {
)}
showsVerticalScrollIndicator={false}
/>
</View>
</SafeAreaView>
);
}

View File

@@ -9,6 +9,7 @@ import {
} from "react-native";
import TrackRow from "../components/TrackRow";
import { useLibrary } from "../contexts/LibraryContext";
import { SafeAreaView } from "react-native-safe-area-context";
export default function LikedTracksScreen({ navigation }) {
const [query, setQuery] = useState("");
@@ -48,7 +49,7 @@ export default function LikedTracksScreen({ navigation }) {
}, [likedTracks, query, sortBy, sortDir]);
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backText}> Back</Text>
</Pressable>
@@ -123,7 +124,7 @@ export default function LikedTracksScreen({ navigation }) {
keyboardShouldPersistTaps="handled"
contentContainerStyle={{ paddingBottom: 180 }}
/>
</View>
</SafeAreaView>
);
}

View File

@@ -1,5 +1,6 @@
import React, { useState } from "react";
import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function LoginScreen({ navigation }) {
const [email, setEmail] = useState("");
@@ -18,7 +19,7 @@ export default function LoginScreen({ navigation }) {
};
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backText}> Back</Text>
</Pressable>
@@ -55,7 +56,7 @@ export default function LoginScreen({ navigation }) {
<Pressable style={styles.SignupBtn} onPress={OnSignUp}>
<Text style={styles.SignupBtnText}>Sign Up</Text>
</Pressable>
</View>
</SafeAreaView>
);
}

View File

@@ -1,5 +1,6 @@
import React, { useState } from "react";
import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function PasswordResetScreen({ navigation }) {
const [email, setEmail] = useState("");
@@ -9,7 +10,7 @@ export default function PasswordResetScreen({ navigation }) {
};
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backText}> Back</Text>
</Pressable>
@@ -29,7 +30,7 @@ export default function PasswordResetScreen({ navigation }) {
<Pressable style={styles.primaryBtn} onPress={onResetButtonPress}>
<Text style={styles.primaryBtnText}>Send email</Text>
</Pressable>
</View>
</SafeAreaView>
);
}

View File

@@ -1,12 +1,13 @@
import React, { useState } from "react";
import { View, Text, StyleSheet, Pressable, Switch } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function SettingsScreen({ navigation }) {
const [notificationsEnabled, setNotificationsEnabled] = useState(true);
const [highQuality, setHighQuality] = useState(false);
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backText}> Back</Text>
</Pressable>
@@ -32,7 +33,7 @@ export default function SettingsScreen({ navigation }) {
>
<Text style={styles.logoutBtnText}>Log out</Text>
</Pressable>
</View>
</SafeAreaView>
);
}

View File

@@ -1,5 +1,6 @@
import React, { useState } from "react";
import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function SignUpScreen({ navigation }) {
const [email, setEmail] = useState("");
@@ -10,7 +11,7 @@ export default function SignUpScreen({ navigation }) {
};
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backText}> Back</Text>
</Pressable>
@@ -48,7 +49,7 @@ export default function SignUpScreen({ navigation }) {
<Pressable style={styles.primaryBtn} onPress={onSignUp}>
<Text style={styles.primaryBtnText}>Sign Up</Text>
</Pressable>
</View>
</SafeAreaView>
);
}