mirror of
https://github.com/leinelissen/jellyfin-audio-player.git
synced 2026-09-03 05:10:01 +03:00
* Upgraded search page - Removed artificial combinding of Fuse and normal fetch results. - Jellyfin API results are now properly integrated into Fuse. - Fuse results are now given better ranking weights. - Added support for artist searching. - Added support for playlist searching. - Added support for instant mixes when a track is selected from search. - Made artist page to look and feel like the albums. - Added support for artist overview display. Fixed searching * Removed separate album retrieving from search * Utilized fix version of react-native-reanimated to solve build issues Code cleanup Fixed package-lock * Fixed linting * Removed debug code and fixed linting errors * [Search Upgrade] Made tracks to instant play from search - InstantMix is no longer treated as a regular playlist. - When a music track is selected from the search results - it will play a mix based on the song. - Refactored Artist page to have full-width artist image and gradient on the overview text. - Made overview fetching to be part of the original artist result to skip additional requests. - Made navigating back to work for all supported items in the search results. * Fixed variable names * feat: filters on search page and saved search queries * fix: artists view * fix: dont dispatch instantmix call * fix: update search parameters to include AlbumArtist * fix: dont query for artists in api yet * fix: remove any * fix: add missing translations for "artist" in multiple languages * fix: lint --------- Co-authored-by: Nikolay Babanov <nikolay.babanov@chaos.com> Co-authored-by: Lei Nelissen <lei@codified.nl>
190 lines
6.6 KiB
TypeScript
190 lines
6.6 KiB
TypeScript
import { BlurView, BlurViewProps } from '@react-native-community/blur';
|
|
import React, { PropsWithChildren } from 'react';
|
|
import { useContext } from 'react';
|
|
import { ColorSchemeName, Platform, StyleSheet, View, useColorScheme } from 'react-native';
|
|
import { useTypedSelector } from '@/store';
|
|
import { ColorScheme } from '@/store/settings/types';
|
|
import { useAccessibilitySetting } from 'react-native-accessibility-settings';
|
|
|
|
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
|
|
|
|
/**
|
|
* Function for generating both the dark and light stylesheets, so that they
|
|
* don't have to be generate on every individual component render
|
|
*/
|
|
function generateStyles(scheme: ColorSchemeName, highContrast: boolean) {
|
|
return StyleSheet.create({
|
|
text: {
|
|
color: scheme === 'dark' ? '#fff' : '#000',
|
|
fontSize: 14,
|
|
fontFamily: 'Inter',
|
|
},
|
|
textSmall: {
|
|
color: scheme === 'dark' ? '#fff' : '#000',
|
|
fontSize: 12,
|
|
lineHeight: 20,
|
|
opacity: 0.5,
|
|
},
|
|
textHalfOpacity: {
|
|
color: highContrast
|
|
? (scheme === 'dark' ? '#ffffffbb' : '#000000bb')
|
|
: (scheme === 'dark' ? '#ffffff88' : '#00000088'),
|
|
fontSize: 14,
|
|
},
|
|
textQuarterOpacity: {
|
|
color: highContrast
|
|
? (scheme === 'dark' ? '#ffffff88' : '#00000088')
|
|
: (scheme === 'dark' ? '#ffffff44' : '#00000044'),
|
|
fontSize: 14,
|
|
},
|
|
view: {
|
|
backgroundColor: scheme === 'dark' ? '#111' : '#fff',
|
|
},
|
|
border: {
|
|
borderColor: scheme === 'dark' ? '#262626' : '#ddd',
|
|
},
|
|
activeBackground: {
|
|
backgroundColor: highContrast
|
|
? `#8b513c${scheme === 'dark' ? '26' : '10'}`
|
|
: `#FF3C00${scheme === 'dark' ? '26' : '16'}`,
|
|
},
|
|
imageBackground: {
|
|
backgroundColor: scheme === 'dark' ? '#191919' : '#eee',
|
|
borderWidth: 0.5,
|
|
borderColor: scheme === 'dark' ? '#262626' : '#ddd',
|
|
},
|
|
modal: {
|
|
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
|
|
},
|
|
modalInner: {
|
|
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
|
|
},
|
|
button: {
|
|
backgroundColor: highContrast
|
|
? (scheme === 'dark' ? '#ffffff0f' : '#0000000f')
|
|
: (scheme === 'dark' ? '#ffffff09' : '#00000009'),
|
|
},
|
|
input: {
|
|
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
|
|
color: scheme === 'dark' ? '#fff' : '#000',
|
|
},
|
|
trackBackground: {
|
|
backgroundColor: scheme === 'dark' ? '#161616' : '#fff',
|
|
},
|
|
stackHeader: {
|
|
color: scheme === 'dark' ? 'white' : 'black'
|
|
},
|
|
icon: {
|
|
color: scheme === 'dark' ? '#ffffff4d' : '#0000004d',
|
|
},
|
|
divider: {
|
|
backgroundColor: scheme === 'dark' ? '#333' : '#eee',
|
|
},
|
|
filter: {
|
|
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
|
|
},
|
|
themeColor: {
|
|
color: highContrast
|
|
? scheme === 'dark' ? '#FF7A1C' : '#c93400'
|
|
: '#FF3C00',
|
|
},
|
|
themeColorHalfOpacity: {
|
|
color: highContrast
|
|
? scheme === 'dark' ? '#FF7A1Cbb' : '#c93400bb'
|
|
: '#FF3C0088',
|
|
},
|
|
themeColorQuarterOpacity: {
|
|
color: highContrast
|
|
? scheme === 'dark' ? '#FF7A1C88' : '#c9340088'
|
|
: '#FF3C0044',
|
|
},
|
|
themeBackground: {
|
|
backgroundColor: highContrast
|
|
? scheme === 'dark' ? '#FF7A1C' : '#c93400'
|
|
: '#FF3C00',
|
|
}
|
|
});
|
|
}
|
|
|
|
// Prerender both stylesheets
|
|
export const themes: Record<'dark' | 'light' | 'dark-highcontrast' | 'light-highcontrast', ReturnType<typeof generateStyles>> = {
|
|
'dark': generateStyles('dark', false),
|
|
'light': generateStyles('light', false),
|
|
'dark-highcontrast': generateStyles('dark', true),
|
|
'light-highcontrast': generateStyles('light', true),
|
|
};
|
|
|
|
// Create context for supplying the theming information
|
|
export const ColorSchemeContext = React.createContext(themes.dark);
|
|
|
|
/**
|
|
* This hook returns the proper color scheme, taking into account potential user overrides.
|
|
*/
|
|
export function useUserOrSystemScheme() {
|
|
const systemScheme = useColorScheme();
|
|
const userScheme = useTypedSelector((state) => state.settings.colorScheme);
|
|
return userScheme === ColorScheme.System ? systemScheme : userScheme;
|
|
}
|
|
|
|
/**
|
|
* This provider contains the logic for settings the right theme on the ColorSchemeContext.
|
|
*/
|
|
export function ColorSchemeProvider({ children }: PropsWithChildren<{}>) {
|
|
const highContrast = useAccessibilitySetting('darkerSystemColors');
|
|
const scheme = useUserOrSystemScheme();
|
|
const theme = highContrast
|
|
? themes[`${scheme || 'light'}-highcontrast`]
|
|
: themes[scheme || 'light'];
|
|
|
|
return (
|
|
<ColorSchemeContext.Provider value={theme}>
|
|
{children}
|
|
</ColorSchemeContext.Provider>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retrieves the default styles object in hook form
|
|
*/
|
|
export default function useDefaultStyles() {
|
|
return useContext(ColorSchemeContext);
|
|
}
|
|
|
|
interface DefaultStylesProviderProps {
|
|
children: (defaultStyles: ReturnType<typeof useDefaultStyles>) => React.JSX.Element;
|
|
}
|
|
|
|
/**
|
|
* A render props component to supply the defaultStyles object.
|
|
*/
|
|
export function DefaultStylesProvider(props: DefaultStylesProviderProps) {
|
|
const defaultStyles = useDefaultStyles();
|
|
|
|
return props.children(defaultStyles);
|
|
}
|
|
|
|
export function ColoredBlurView({ children, style, ...props }: PropsWithChildren<BlurViewProps>) {
|
|
const systemScheme = useColorScheme();
|
|
const userScheme = useTypedSelector((state) => state.settings.colorScheme);
|
|
const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme;
|
|
|
|
return Platform.OS === 'ios' ? (
|
|
<View style={[style, { overflow: 'hidden' }]}>
|
|
<BlurView
|
|
style={[ StyleSheet.absoluteFill, { overflow: 'hidden'} ]}
|
|
{...props}
|
|
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
|
|
? scheme === 'dark' ? 'materialDark' : 'materialLight'
|
|
: scheme === 'dark' ? 'extraDark' : 'xlight'
|
|
}
|
|
/>
|
|
{children}
|
|
</View>
|
|
) : (
|
|
<View {...props} style={[ style, {
|
|
backgroundColor: scheme === 'light' ? '#f6f6f6fb' : '#333333fb',
|
|
} ]}>
|
|
{children}
|
|
</View>
|
|
);
|
|
} |