diff --git a/res/more_vertical.png b/res/more_vertical.png new file mode 100644 index 0000000..96faff0 Binary files /dev/null and b/res/more_vertical.png differ diff --git a/res/record.png b/res/record.png new file mode 100644 index 0000000..5e85c13 Binary files /dev/null and b/res/record.png differ diff --git a/res/star-fill.png b/res/star-fill.png new file mode 100644 index 0000000..ea34c70 Binary files /dev/null and b/res/star-fill.png differ diff --git a/res/star.png b/res/star.png new file mode 100644 index 0000000..e8d9c61 Binary files /dev/null and b/res/star.png differ diff --git a/src/components/common/AlbumCover.tsx b/src/components/common/AlbumCover.tsx new file mode 100644 index 0000000..f5dfe5e --- /dev/null +++ b/src/components/common/AlbumCover.tsx @@ -0,0 +1,65 @@ +import React, { useState } from 'react'; +import { ActivityIndicator, View } from 'react-native'; +import FastImage from 'react-native-fast-image'; +import LinearGradient from 'react-native-linear-gradient'; +import colors from '../../styles/colors'; + +const AlbumCover: React.FC<{ + height: number, + width: number, + coverArtUri?: string +}> = ({ height, width, coverArtUri }) => { + const [placeholderVisible, setPlaceholderVisible] = useState(false); + const [loading, setLoading] = useState(true); + + const indicatorSize = height > 130 ? 'large' : 'small'; + const halfIndicatorHeight = indicatorSize === 'large' ? 18 : 10; + + const Placeholder: React.FC<{ visible: boolean }> = ({ visible }) => ( + + + + ); + + const CoverArt = () => ( + + + + setPlaceholderVisible(true)} + onLoadEnd={() => setLoading(false)} + /> + + ); + + return ( + + {!coverArtUri ? : } + + ); +} + +export default React.memo(AlbumCover); diff --git a/src/components/common/AlbumView.tsx b/src/components/common/AlbumView.tsx index 0f32c44..3191732 100644 --- a/src/components/common/AlbumView.tsx +++ b/src/components/common/AlbumView.tsx @@ -1,40 +1,172 @@ import { useNavigation } from '@react-navigation/native'; import { useAtomValue } from 'jotai/utils'; import React, { useEffect } from 'react'; -import { View, Text } from 'react-native'; +import { ScrollView, Text, useWindowDimensions, View, Image, Pressable, GestureResponderEvent } from 'react-native'; import { albumAtomFamily } from '../../state/music'; +import colors from '../../styles/colors'; +import text from '../../styles/text'; +import AlbumCover from './AlbumCover'; import TopTabContainer from './TopTabContainer'; +function secondsToTime(s: number): string { + const seconds = s % 60; + const minutes = Math.floor(s / 60) % 60; + const hours = Math.floor(s / 60 / 60); + + let time = `${minutes.toString().padStart(1, '0')}:${seconds.toString().padStart(2, '0')}`; + if (hours > 0) { + time = `${hours}:${time}`; + } + return time; +} + +const Button: React.FC<{ + title: string; + onPress: (event: GestureResponderEvent) => void; +}> = ({ title, onPress }) => { + return ( + + {title} + + ); +} + const AlbumDetails: React.FC<{ id: string, }> = ({ id }) => { - const navigation = useNavigation(); const album = useAtomValue(albumAtomFamily(id)); + const layout = useWindowDimensions(); - useEffect(() => { - if (!album) { - return; - } - navigation.setOptions({ title: album.name }); - }); + const coverSize = layout.width - layout.width / 2; return ( - <> - Name: {album?.name} - Artist: {album?.artist} - + + + + {album?.name} + + {album?.artist}{album?.year ? ` • ${album.year}` : ''} + + +