Added basic login, signup, settings and password reset pages
This commit is contained in:
@@ -2,13 +2,21 @@ import { StatusBar } from "expo-status-bar";
|
|||||||
import { StyleSheet, Text, View, Pressable } from "react-native";
|
import { StyleSheet, Text, View, Pressable } from "react-native";
|
||||||
import { NavigationContainer } from "@react-navigation/native";
|
import { NavigationContainer } from "@react-navigation/native";
|
||||||
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||||
import MediaPlayer from "./src/components/MediaPlayer";
|
|
||||||
import HomeScreen from "./src/screens/HomeScreen";
|
|
||||||
import { createContext, useState, useContext } from "react";
|
import { createContext, useState, useContext } from "react";
|
||||||
|
|
||||||
|
import MediaPlayer from "./src/components/MediaPlayer";
|
||||||
|
|
||||||
|
import HomeScreen from "./src/screens/HomeScreen";
|
||||||
import LikedTracksScreen from "./src/screens/LikedTracksScreen";
|
import LikedTracksScreen from "./src/screens/LikedTracksScreen";
|
||||||
import AlbumScreen from "./src/screens/AlbumScreen";
|
import AlbumScreen from "./src/screens/AlbumScreen";
|
||||||
|
import LoginScreen from "./src/screens/LoginScreen";
|
||||||
|
import PasswordResetScreen from "./src/screens/PasswordResetScreen";
|
||||||
|
import SettingsScreen from "./src/screens/SettingsScreen";
|
||||||
|
import SignUpScreen from "./src/screens/SignUpScreen";
|
||||||
|
|
||||||
import { LibraryProvider } from "./src/contexts/LibraryContext";
|
import { LibraryProvider } from "./src/contexts/LibraryContext";
|
||||||
|
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator();
|
const Stack = createNativeStackNavigator();
|
||||||
|
|
||||||
const playerContext = createContext(null);
|
const playerContext = createContext(null);
|
||||||
@@ -40,6 +48,10 @@ function AppNavigator() {
|
|||||||
<Stack.Screen name="Home" component={HomeScreen} />
|
<Stack.Screen name="Home" component={HomeScreen} />
|
||||||
<Stack.Screen name="LikedTracks" component={LikedTracksScreen} />
|
<Stack.Screen name="LikedTracks" component={LikedTracksScreen} />
|
||||||
<Stack.Screen name="Album" component={AlbumScreen} />
|
<Stack.Screen name="Album" component={AlbumScreen} />
|
||||||
|
<Stack.Screen name="SignUp" component={SignUpScreen} />
|
||||||
|
<Stack.Screen name="Login" component={LoginScreen} />
|
||||||
|
<Stack.Screen name="PasswordReset" component={PasswordResetScreen} />
|
||||||
|
<Stack.Screen name="Settings" component={SettingsScreen} />
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ export default function HomeScreen() {
|
|||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { albums, likedTracks, toggleLike } = useLibrary();
|
const { albums, likedTracks, toggleLike } = useLibrary();
|
||||||
|
|
||||||
// Same behavior as before: show all albums in "Liked albums" section
|
|
||||||
const likedAlbums = albums;
|
|
||||||
|
|
||||||
// Optional: limit shown liked tracks on Home
|
|
||||||
const homeLikedTracks = useMemo(() => likedTracks.slice(0, 5), [likedTracks]);
|
const homeLikedTracks = useMemo(() => likedTracks.slice(0, 5), [likedTracks]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -29,17 +25,13 @@ export default function HomeScreen() {
|
|||||||
<View style={styles.headerActions}>
|
<View style={styles.headerActions}>
|
||||||
<Pressable
|
<Pressable
|
||||||
style={styles.iconBtn}
|
style={styles.iconBtn}
|
||||||
onPress={() => {
|
onPress={() => navigation.navigate("Login")}
|
||||||
console.log("Login pressed");
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Ionicons name="person-outline" size={24} color="#fff" />
|
<Ionicons name="person-outline" size={24} color="#fff" />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Pressable
|
<Pressable
|
||||||
style={styles.iconBtn}
|
style={styles.iconBtn}
|
||||||
onPress={() => {
|
onPress={() => navigation.navigate("Settings")}
|
||||||
console.log("Settings pressed");
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Ionicons name="settings-outline" size={24} color="#fff" />
|
<Ionicons name="settings-outline" size={24} color="#fff" />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
@@ -67,10 +59,10 @@ export default function HomeScreen() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<Text style={[styles.sectionTitle, { marginTop: 24 }]}>Liked albums</Text>
|
<Text style={[styles.sectionTitle, { marginTop: 24 }]}>Albums</Text>
|
||||||
|
|
||||||
<FlatList
|
<FlatList
|
||||||
data={likedAlbums}
|
data={albums}
|
||||||
keyExtractor={(item) => item.id}
|
keyExtractor={(item) => item.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
columnWrapperStyle={styles.albumRow}
|
columnWrapperStyle={styles.albumRow}
|
||||||
|
|||||||
132
jukebox/src/screens/LoginScreen.js
Normal file
132
jukebox/src/screens/LoginScreen.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
|
||||||
|
|
||||||
|
export default function LoginScreen({ navigation }) {
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
const onLogin = () => {
|
||||||
|
console.log("Login button pressed");
|
||||||
|
};
|
||||||
|
|
||||||
|
const OnPasswordReset = () => {
|
||||||
|
navigation.navigate("PasswordReset");
|
||||||
|
};
|
||||||
|
|
||||||
|
const OnSignUp = () => {
|
||||||
|
navigation.navigate("SignUp");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
|
||||||
|
<Text style={styles.backText}>← Back</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Text style={styles.title}>Login</Text>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={email}
|
||||||
|
onChangeText={setEmail}
|
||||||
|
placeholder="Email"
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
style={styles.input}
|
||||||
|
autoCapitalize="none"
|
||||||
|
keyboardType="email-address"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={password}
|
||||||
|
onChangeText={setPassword}
|
||||||
|
placeholder="Password"
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
style={styles.input}
|
||||||
|
secureTextEntry
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Pressable style={styles.loginBtn} onPress={onLogin}>
|
||||||
|
<Text style={styles.loginBtnText}>Log In</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable style={styles.passwordResetBtn} onPress={OnPasswordReset}>
|
||||||
|
<Text style={styles.passwordResetBtnText}>Reset password</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable style={styles.SignupBtn} onPress={OnSignUp}>
|
||||||
|
<Text style={styles.SignupBtnText}>Sign Up</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#000",
|
||||||
|
paddingTop: 24,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
backBtn: {
|
||||||
|
marginBottom: 10,
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
},
|
||||||
|
backText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: "700",
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
backgroundColor: "#1f2937",
|
||||||
|
color: "#fff",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 12,
|
||||||
|
fontSize: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
loginBtn: {
|
||||||
|
backgroundColor: "#dbdbdb",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
loginBtnText: {
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: "700",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
passwordResetBtn: {
|
||||||
|
backgroundColor: "#e36d6d",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
passwordResetBtnText: {
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: "700",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
|
||||||
|
SignupBtn: {
|
||||||
|
backgroundColor: "#dbdbdb",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
SignupBtnText: {
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: "700",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
80
jukebox/src/screens/PasswordResetScreen.js
Normal file
80
jukebox/src/screens/PasswordResetScreen.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
|
||||||
|
|
||||||
|
export default function PasswordResetScreen({ navigation }) {
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
|
||||||
|
const onResetButtonPress = () => {
|
||||||
|
console.log("Send email button pressed");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
|
||||||
|
<Text style={styles.backText}>← Back</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Text style={styles.title}>Reset password</Text>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={email}
|
||||||
|
onChangeText={setEmail}
|
||||||
|
placeholder="Email"
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
style={styles.input}
|
||||||
|
autoCapitalize="none"
|
||||||
|
keyboardType="email-address"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Pressable style={styles.primaryBtn} onPress={onResetButtonPress}>
|
||||||
|
<Text style={styles.primaryBtnText}>Send email</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#000",
|
||||||
|
paddingTop: 24,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
backBtn: {
|
||||||
|
marginBottom: 10,
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
},
|
||||||
|
backText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: "700",
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
backgroundColor: "#1f2937",
|
||||||
|
color: "#fff",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 12,
|
||||||
|
fontSize: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
primaryBtn: {
|
||||||
|
backgroundColor: "#dbdbdb",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
primaryBtnText: {
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: "700",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
87
jukebox/src/screens/SettingsScreen.js
Normal file
87
jukebox/src/screens/SettingsScreen.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { View, Text, StyleSheet, Pressable, Switch } from "react-native";
|
||||||
|
|
||||||
|
export default function SettingsScreen({ navigation }) {
|
||||||
|
const [notificationsEnabled, setNotificationsEnabled] = useState(true);
|
||||||
|
const [highQuality, setHighQuality] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
|
||||||
|
<Text style={styles.backText}>← Back</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Text style={styles.title}>Settings</Text>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={styles.rowText}>Enable notifications</Text>
|
||||||
|
<Switch
|
||||||
|
value={notificationsEnabled}
|
||||||
|
onValueChange={setNotificationsEnabled}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={styles.rowText}>High quality streaming</Text>
|
||||||
|
<Switch value={highQuality} onValueChange={setHighQuality} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Pressable
|
||||||
|
style={[styles.logoutBtn]}
|
||||||
|
onPress={() => console.log("Logged out")}
|
||||||
|
>
|
||||||
|
<Text style={styles.logoutBtnText}>Log out</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#000",
|
||||||
|
paddingTop: 24,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
backBtn: {
|
||||||
|
marginBottom: 10,
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
},
|
||||||
|
backText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: "700",
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
backgroundColor: "#111827",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 14,
|
||||||
|
marginBottom: 10,
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
rowText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
logoutBtn: {
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 16,
|
||||||
|
backgroundColor: "#e36d6d",
|
||||||
|
},
|
||||||
|
logoutBtnText: {
|
||||||
|
color: "#000000",
|
||||||
|
fontWeight: "700",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
99
jukebox/src/screens/SignUpScreen.js
Normal file
99
jukebox/src/screens/SignUpScreen.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
|
||||||
|
|
||||||
|
export default function SignUpScreen({ navigation }) {
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
const onSignUp = () => {
|
||||||
|
console.log("Sign up button pressed");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Pressable onPress={() => navigation.goBack()} style={styles.backBtn}>
|
||||||
|
<Text style={styles.backText}>← Back</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Text style={styles.title}>Sign up</Text>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={email}
|
||||||
|
onChangeText={setEmail}
|
||||||
|
placeholder="Email"
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
style={styles.input}
|
||||||
|
autoCapitalize="none"
|
||||||
|
keyboardType="email-address"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={password}
|
||||||
|
onChangeText={setPassword}
|
||||||
|
placeholder="Password"
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
style={styles.input}
|
||||||
|
secureTextEntry
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={password}
|
||||||
|
onChangeText={setPassword}
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
style={styles.input}
|
||||||
|
secureTextEntry
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Pressable style={styles.primaryBtn} onPress={onSignUp}>
|
||||||
|
<Text style={styles.primaryBtnText}>Sign Up</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#000",
|
||||||
|
paddingTop: 24,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
backBtn: {
|
||||||
|
marginBottom: 10,
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
},
|
||||||
|
backText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: "700",
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
backgroundColor: "#1f2937",
|
||||||
|
color: "#fff",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 12,
|
||||||
|
fontSize: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
primaryBtn: {
|
||||||
|
backgroundColor: "#dbdbdb",
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
primaryBtnText: {
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: "700",
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user