mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 00:59:28 +01:00
gradient working better now/in album view
title bar now also uses gradient color
This commit is contained in:
parent
0a31597111
commit
a151fe299e
@ -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 />
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
65
src/components/common/ImageGradientBackground.tsx
Normal file
65
src/components/common/ImageGradientBackground.tsx
Normal 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;
|
||||||
30
src/components/common/ImageGradientScrollView.tsx
Normal file
30
src/components/common/ImageGradientScrollView.tsx
Normal 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;
|
||||||
Loading…
x
Reference in New Issue
Block a user