Show download queue size in nav bar
This commit is contained in:
@@ -19,8 +19,11 @@ import GetAppOutlinedIcon from '@mui/icons-material/GetAppOutlined';
|
||||
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import InfoIcon from '@mui/icons-material/Info';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { NavbarItem, NavBarItemMoreGroup } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { DownloaderState } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
type RestrictedNavBarItem<Show extends NavbarItem['show']> = Omit<NavbarItem, 'show'> & { show: Show };
|
||||
|
||||
@@ -67,6 +70,19 @@ const NAVIGATION_BAR_DESKTOP_ITEMS = [
|
||||
IconComponent: GetAppOutlinedIcon,
|
||||
show: 'desktop',
|
||||
moreGroup: NavBarItemMoreGroup.HIDDEN_ITEM,
|
||||
useBadge: () => {
|
||||
const { t } = useTranslation();
|
||||
const { data } = requestManager.useGetDownloadStatus();
|
||||
const downloadStatus = data?.downloadStatus;
|
||||
|
||||
const isPaused = downloadStatus?.state === DownloaderState.Stopped;
|
||||
const count = downloadStatus?.queue.length ?? 0;
|
||||
|
||||
return {
|
||||
count,
|
||||
title: t(isPaused ? 'download.queue.info.paused' : 'download.queue.info.remaining', { count }),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
path: AppRoutes.settings.path,
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface NavbarItem {
|
||||
IconComponent: OverridableComponent<SvgIconTypeMap<{}, 'svg'>>;
|
||||
show: 'mobile' | 'desktop' | 'both';
|
||||
moreGroup: NavBarItemMoreGroup;
|
||||
useBadge?: () => { count: number; title: string };
|
||||
}
|
||||
|
||||
export type NavbarContextType = {
|
||||
|
||||
@@ -20,6 +20,8 @@ import { styled, useTheme } from '@mui/material/styles';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import Badge from '@mui/material/Badge';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { CustomTooltip } from '@/modules/core/components/CustomTooltip.tsx';
|
||||
import { ListItemLink } from '@/modules/core/components/lists/ListItemLink.tsx';
|
||||
import { useGetOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
|
||||
@@ -37,11 +39,12 @@ const DrawerHeader = styled('div')(({ theme }) => ({
|
||||
...theme.mixins.toolbar,
|
||||
}));
|
||||
|
||||
const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent }: NavbarItem) => {
|
||||
const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent, useBadge }: NavbarItem) => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const { isCollapsed } = useNavBarContext();
|
||||
const theme = useTheme();
|
||||
const badgeInfo = useBadge?.();
|
||||
|
||||
const isActive = location.pathname.startsWith(path);
|
||||
const Icon = isActive ? SelectedIconComponent : IconComponent;
|
||||
@@ -56,18 +59,30 @@ const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent }
|
||||
|
||||
return (
|
||||
<ListItemLink selected={!isCollapsed && isActive} sx={{ p: 0, m: 0 }} to={path}>
|
||||
<CustomTooltip title={t(title)} placement="right">
|
||||
<CustomTooltip
|
||||
title={
|
||||
<>
|
||||
{t(title)}
|
||||
<br />
|
||||
{badgeInfo?.title}
|
||||
</>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<ListItem sx={listItemProps}>
|
||||
<ListItemIcon sx={listItemIconProps}>
|
||||
<Icon
|
||||
sx={{
|
||||
color: isActive ? 'primary.dark' : undefined,
|
||||
...theme.applyStyles('dark', {
|
||||
color: isActive ? 'primary.light' : undefined,
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
<Badge badgeContent={badgeInfo?.count} color="primary">
|
||||
<Icon
|
||||
sx={{
|
||||
color: isActive ? 'primary.dark' : undefined,
|
||||
...theme.applyStyles('dark', {
|
||||
color: isActive ? 'primary.light' : undefined,
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
|
||||
<ListItemText
|
||||
primary={
|
||||
<TypographyMaxLines
|
||||
@@ -83,7 +98,14 @@ const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent }
|
||||
{t(title)}
|
||||
</TypographyMaxLines>
|
||||
}
|
||||
sx={{ maxWidth: '100%', m: 0 }}
|
||||
secondary={
|
||||
!isCollapsed && (
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{badgeInfo?.title}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
sx={{ maxWidth: '100%', m: 0, display: 'flex', flexDirection: 'column' }}
|
||||
/>
|
||||
</ListItem>
|
||||
</CustomTooltip>
|
||||
|
||||
@@ -10,9 +10,10 @@ import BottomNavigation from '@mui/material/BottomNavigation';
|
||||
import BottomNavigationAction from '@mui/material/BottomNavigationAction';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { CSSProperties, useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { CSSObject, useTheme } from '@mui/material/styles';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import Badge from '@mui/material/Badge';
|
||||
import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
|
||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { NavbarItem } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||
@@ -52,7 +53,7 @@ export const MobileBottomBar = ({ navBarItems }: { navBarItems: NavbarItem[] })
|
||||
style={{
|
||||
...(theme.applyStyles('dark', {
|
||||
'--Paper-overlay': 'unset',
|
||||
}) as Omit<CSSObject, 'accentColorsd'>),
|
||||
}) as CSSProperties),
|
||||
}}
|
||||
elevation={3}
|
||||
>
|
||||
@@ -64,12 +65,15 @@ export const MobileBottomBar = ({ navBarItems }: { navBarItems: NavbarItem[] })
|
||||
navigate(newValue);
|
||||
}}
|
||||
>
|
||||
{navBarItems.map(({ path, title, IconComponent, SelectedIconComponent }) => (
|
||||
{navBarItems.map(({ path, title, IconComponent, SelectedIconComponent, useBadge }) => (
|
||||
<BottomNavigationAction
|
||||
key={path}
|
||||
value={path}
|
||||
label={t(title)}
|
||||
icon={selectedNavBarItem === path ? <SelectedIconComponent /> : <IconComponent />}
|
||||
icon={
|
||||
<Badge key={path} badgeContent={useBadge?.().count} color="primary">
|
||||
{selectedNavBarItem === path ? <SelectedIconComponent /> : <IconComponent />}
|
||||
</Badge>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BottomNavigation>
|
||||
|
||||
@@ -68,7 +68,7 @@ export const More = () => {
|
||||
<ListItemIcon>
|
||||
<item.IconComponent />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t(item.title)} />
|
||||
<ListItemText primary={t(item.title)} secondary={item.useBadge?.().title} />
|
||||
</ListItemLink>
|
||||
))}
|
||||
{index !== list.length - 1 && <Divider />}
|
||||
|
||||
Reference in New Issue
Block a user