Show download queue size in nav bar
This commit is contained in:
@@ -164,6 +164,10 @@
|
|||||||
"failed_to_retry": "Could not retry failed download."
|
"failed_to_retry": "Could not retry failed download."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"info": {
|
||||||
|
"paused": "Paused — $t(download.queue.info.remaining)",
|
||||||
|
"remaining": "{{count}} remaining"
|
||||||
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"delete_all": "Delete all",
|
"delete_all": "Delete all",
|
||||||
"no_downloads": "No downloads"
|
"no_downloads": "No downloads"
|
||||||
@@ -455,6 +459,7 @@
|
|||||||
"sort": "Sort",
|
"sort": "Sort",
|
||||||
"standard": "Standard",
|
"standard": "Standard",
|
||||||
"started": "Started",
|
"started": "Started",
|
||||||
|
"stopped": "Stopped",
|
||||||
"success": "Success",
|
"success": "Success",
|
||||||
"system": "System",
|
"system": "System",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
|
|||||||
@@ -19,8 +19,11 @@ import GetAppOutlinedIcon from '@mui/icons-material/GetAppOutlined';
|
|||||||
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
import InfoIcon from '@mui/icons-material/Info';
|
import InfoIcon from '@mui/icons-material/Info';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { NavbarItem, NavBarItemMoreGroup } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
import { NavbarItem, NavBarItemMoreGroup } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.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 };
|
type RestrictedNavBarItem<Show extends NavbarItem['show']> = Omit<NavbarItem, 'show'> & { show: Show };
|
||||||
|
|
||||||
@@ -67,6 +70,19 @@ const NAVIGATION_BAR_DESKTOP_ITEMS = [
|
|||||||
IconComponent: GetAppOutlinedIcon,
|
IconComponent: GetAppOutlinedIcon,
|
||||||
show: 'desktop',
|
show: 'desktop',
|
||||||
moreGroup: NavBarItemMoreGroup.HIDDEN_ITEM,
|
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,
|
path: AppRoutes.settings.path,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export interface NavbarItem {
|
|||||||
IconComponent: OverridableComponent<SvgIconTypeMap<{}, 'svg'>>;
|
IconComponent: OverridableComponent<SvgIconTypeMap<{}, 'svg'>>;
|
||||||
show: 'mobile' | 'desktop' | 'both';
|
show: 'mobile' | 'desktop' | 'both';
|
||||||
moreGroup: NavBarItemMoreGroup;
|
moreGroup: NavBarItemMoreGroup;
|
||||||
|
useBadge?: () => { count: number; title: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NavbarContextType = {
|
export type NavbarContextType = {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import { styled, useTheme } from '@mui/material/styles';
|
|||||||
import { useCallback, useMemo, useRef } from 'react';
|
import { useCallback, useMemo, useRef } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import ListItem from '@mui/material/ListItem';
|
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 { CustomTooltip } from '@/modules/core/components/CustomTooltip.tsx';
|
||||||
import { ListItemLink } from '@/modules/core/components/lists/ListItemLink.tsx';
|
import { ListItemLink } from '@/modules/core/components/lists/ListItemLink.tsx';
|
||||||
import { useGetOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
|
import { useGetOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
|
||||||
@@ -37,11 +39,12 @@ const DrawerHeader = styled('div')(({ theme }) => ({
|
|||||||
...theme.mixins.toolbar,
|
...theme.mixins.toolbar,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent }: NavbarItem) => {
|
const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent, useBadge }: NavbarItem) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { isCollapsed } = useNavBarContext();
|
const { isCollapsed } = useNavBarContext();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const badgeInfo = useBadge?.();
|
||||||
|
|
||||||
const isActive = location.pathname.startsWith(path);
|
const isActive = location.pathname.startsWith(path);
|
||||||
const Icon = isActive ? SelectedIconComponent : IconComponent;
|
const Icon = isActive ? SelectedIconComponent : IconComponent;
|
||||||
@@ -56,18 +59,30 @@ const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent }
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItemLink selected={!isCollapsed && isActive} sx={{ p: 0, m: 0 }} to={path}>
|
<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}>
|
<ListItem sx={listItemProps}>
|
||||||
<ListItemIcon sx={listItemIconProps}>
|
<ListItemIcon sx={listItemIconProps}>
|
||||||
<Icon
|
<Badge badgeContent={badgeInfo?.count} color="primary">
|
||||||
sx={{
|
<Icon
|
||||||
color: isActive ? 'primary.dark' : undefined,
|
sx={{
|
||||||
...theme.applyStyles('dark', {
|
color: isActive ? 'primary.dark' : undefined,
|
||||||
color: isActive ? 'primary.light' : undefined,
|
...theme.applyStyles('dark', {
|
||||||
}),
|
color: isActive ? 'primary.light' : undefined,
|
||||||
}}
|
}),
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
<TypographyMaxLines
|
<TypographyMaxLines
|
||||||
@@ -83,7 +98,14 @@ const NavigationBarItem = ({ path, title, IconComponent, SelectedIconComponent }
|
|||||||
{t(title)}
|
{t(title)}
|
||||||
</TypographyMaxLines>
|
</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>
|
</ListItem>
|
||||||
</CustomTooltip>
|
</CustomTooltip>
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ import BottomNavigation from '@mui/material/BottomNavigation';
|
|||||||
import BottomNavigationAction from '@mui/material/BottomNavigationAction';
|
import BottomNavigationAction from '@mui/material/BottomNavigationAction';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Paper from '@mui/material/Paper';
|
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 { 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 { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
|
||||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||||
import { NavbarItem } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
import { NavbarItem } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
@@ -52,7 +53,7 @@ export const MobileBottomBar = ({ navBarItems }: { navBarItems: NavbarItem[] })
|
|||||||
style={{
|
style={{
|
||||||
...(theme.applyStyles('dark', {
|
...(theme.applyStyles('dark', {
|
||||||
'--Paper-overlay': 'unset',
|
'--Paper-overlay': 'unset',
|
||||||
}) as Omit<CSSObject, 'accentColorsd'>),
|
}) as CSSProperties),
|
||||||
}}
|
}}
|
||||||
elevation={3}
|
elevation={3}
|
||||||
>
|
>
|
||||||
@@ -64,12 +65,15 @@ export const MobileBottomBar = ({ navBarItems }: { navBarItems: NavbarItem[] })
|
|||||||
navigate(newValue);
|
navigate(newValue);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{navBarItems.map(({ path, title, IconComponent, SelectedIconComponent }) => (
|
{navBarItems.map(({ path, title, IconComponent, SelectedIconComponent, useBadge }) => (
|
||||||
<BottomNavigationAction
|
<BottomNavigationAction
|
||||||
key={path}
|
|
||||||
value={path}
|
value={path}
|
||||||
label={t(title)}
|
label={t(title)}
|
||||||
icon={selectedNavBarItem === path ? <SelectedIconComponent /> : <IconComponent />}
|
icon={
|
||||||
|
<Badge key={path} badgeContent={useBadge?.().count} color="primary">
|
||||||
|
{selectedNavBarItem === path ? <SelectedIconComponent /> : <IconComponent />}
|
||||||
|
</Badge>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</BottomNavigation>
|
</BottomNavigation>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export const More = () => {
|
|||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<item.IconComponent />
|
<item.IconComponent />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t(item.title)} />
|
<ListItemText primary={t(item.title)} secondary={item.useBadge?.().title} />
|
||||||
</ListItemLink>
|
</ListItemLink>
|
||||||
))}
|
))}
|
||||||
{index !== list.length - 1 && <Divider />}
|
{index !== list.length - 1 && <Divider />}
|
||||||
|
|||||||
Reference in New Issue
Block a user