gradient working better now/in album view

title bar now also uses gradient color
This commit is contained in:
austinried 2021-07-03 22:59:38 +09:00
parent 0a31597111
commit a151fe299e
4 changed files with 103 additions and 65 deletions

View File

@ -1,13 +1,11 @@
import { useAtomValue } from 'jotai/utils'; import { useAtomValue } from 'jotai/utils';
import React, { useEffect, useState } from 'react'; import React from 'react';
import { StyleSheet, Text, View, StatusBar, useWindowDimensions } from 'react-native'; import { StatusBar, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import { currentQueueNameAtom, currentTrackAtom } from '../state/trackplayer'; import { currentQueueNameAtom, currentTrackAtom } from '../state/trackplayer';
import colors from '../styles/colors';
import text from '../styles/text'; import text from '../styles/text';
import CoverArt from './common/CoverArt'; import CoverArt from './common/CoverArt';
import GradientBackground from './common/GradientBackground'; import ImageGradientBackground from './common/ImageGradientBackground';
import ImageColors from 'react-native-image-colors';
const NowPlayingHeader = () => { const NowPlayingHeader = () => {
const queueName = useAtomValue(currentQueueNameAtom); const queueName = useAtomValue(currentQueueNameAtom);
@ -106,61 +104,8 @@ const infoStyles = StyleSheet.create({
}, },
}); });
interface AndroidImageColors {
dominant?: string;
average?: string;
vibrant?: string;
darkVibrant?: string;
lightVibrant?: string;
darkMuted?: string;
lightMuted?: string;
muted?: string;
platform: 'android';
}
interface IOSImageColors {
background: string;
primary: string;
secondary: string;
detail: string;
quality: Config['quality'];
platform: 'ios';
}
interface Config {
fallback?: string;
pixelSpacing?: number;
quality?: 'lowest' | 'low' | 'high' | 'highest';
cache?: boolean;
key?: string;
}
declare type ImageColorsResult = AndroidImageColors | IOSImageColors;
const NowPlayingLayout = () => { const NowPlayingLayout = () => {
const track = useAtomValue(currentTrackAtom); const track = useAtomValue(currentTrackAtom);
const [imageColors, setImageColors] = useState<ImageColorsResult | undefined>(undefined);
const ica = imageColors as AndroidImageColors;
useEffect(() => {
async function getColors() {
if (track?.artwork === undefined) {
return;
}
const cachedResult = ImageColors.cache.getItem(track.artwork as string);
if (cachedResult) {
setImageColors(cachedResult);
return;
}
const result = await ImageColors.getColors(track.artwork as string, {
cache: true,
});
setImageColors(result);
}
getColors();
}, [track]);
return ( return (
<View <View
@ -168,10 +113,7 @@ const NowPlayingLayout = () => {
flex: 1, flex: 1,
paddingTop: StatusBar.currentHeight, paddingTop: StatusBar.currentHeight,
}}> }}>
<GradientBackground <ImageGradientBackground imageUri={track?.artwork as string} />
colors={[ica ? (ica.muted as string) : colors.gradient.high, colors.gradient.low]}
locations={[0.1, 1.0]}
/>
<NowPlayingHeader /> <NowPlayingHeader />
<SongCoverArt /> <SongCoverArt />
<SongInfo /> <SongInfo />

View File

@ -18,7 +18,7 @@ import text from '../../styles/text';
import AlbumArt from './AlbumArt'; import AlbumArt from './AlbumArt';
import Button from './Button'; import Button from './Button';
import GradientBackground from './GradientBackground'; import GradientBackground from './GradientBackground';
import GradientScrollView from './GradientScrollView'; import ImageGradientScrollView from './ImageGradientScrollView';
const SongItem: React.FC<{ const SongItem: React.FC<{
id: string; id: string;
@ -102,7 +102,8 @@ const AlbumDetails: React.FC<{
} }
return ( return (
<GradientScrollView <ImageGradientScrollView
imageUri={album.coverArtUri}
style={{ style={{
flex: 1, flex: 1,
}} }}
@ -166,7 +167,7 @@ const AlbumDetails: React.FC<{
/> />
))} ))}
</View> </View>
</GradientScrollView> </ImageGradientScrollView>
); );
}; };

View File

@ -0,0 +1,65 @@
import { useNavigation } from '@react-navigation/native';
import React, { useEffect, useState } from 'react';
import { ViewStyle } from 'react-native';
import ImageColors from 'react-native-image-colors';
import { AndroidImageColors } from 'react-native-image-colors/lib/typescript/types';
import colors from '../../styles/colors';
import GradientBackground from './GradientBackground';
const ImageGradientBackground: React.FC<{
height?: number | string;
width?: number | string;
position?: 'relative' | 'absolute';
style?: ViewStyle;
imageUri?: string;
}> = ({ height, width, position, style, imageUri, children }) => {
const [highColor, setHighColor] = useState<string>(colors.gradient.high);
const navigation = useNavigation();
useEffect(() => {
async function getColors() {
if (imageUri === undefined) {
return;
}
let res: AndroidImageColors;
const cachedResult = ImageColors.cache.getItem(imageUri);
if (cachedResult) {
res = cachedResult as AndroidImageColors;
} else {
res = (await ImageColors.getColors(imageUri, {
cache: true,
})) as AndroidImageColors;
}
if (res.muted && res.muted !== '#000000') {
setHighColor(res.muted);
} else if (res.darkMuted && res.darkMuted !== '#000000') {
setHighColor(res.darkMuted);
}
}
getColors();
}, [imageUri]);
useEffect(() => {
navigation.setOptions({
headerStyle: {
backgroundColor: highColor,
},
});
}, [navigation, highColor]);
return (
<GradientBackground
height={height}
width={width}
position={position}
style={style}
colors={[highColor, colors.gradient.low]}
locations={[0.1, 1.0]}>
{children}
</GradientBackground>
);
};
export default ImageGradientBackground;

View File

@ -0,0 +1,30 @@
import React, { useState } from 'react';
import { LayoutRectangle, ScrollView, ScrollViewProps } from 'react-native';
import colors from '../../styles/colors';
import ImageGradientBackground from './ImageGradientBackground';
const ImageGradientScrollView: React.FC<ScrollViewProps & { imageUri?: string }> = props => {
const [layout, setLayout] = useState<LayoutRectangle | undefined>(undefined);
props.style = props.style || {};
if (typeof props.style === 'object' && props.style !== null) {
props.style = {
...props.style,
backgroundColor: colors.gradient.low,
};
}
return (
<ScrollView
overScrollMode="never"
{...props}
onLayout={event => {
setLayout(event.nativeEvent.layout);
}}>
<ImageGradientBackground height={layout?.height} imageUri={props.imageUri} />
{props.children}
</ScrollView>
);
};
export default ImageGradientScrollView;