diff --git a/front/packages/models/src/accounts.tsx b/front/packages/models/src/accounts.tsx index aa4555a8..f2071a21 100644 --- a/front/packages/models/src/accounts.tsx +++ b/front/packages/models/src/accounts.tsx @@ -157,7 +157,7 @@ export const AccountProvider = ({ if (user.id !== selectedRef.current.id) return; const nUser = { ...selectedRef.current, ...user }; updateAccount(nUser.id, nUser); - }, [user]); + }, [user, userIsSuccess, userIsPlaceholder]); const queryClient = useQueryClient(); const oldSelected = useRef<{ id: string; token: string } | null>( diff --git a/front/packages/models/src/resources/watch-info.ts b/front/packages/models/src/resources/watch-info.ts index 82e624bd..a0a10d86 100644 --- a/front/packages/models/src/resources/watch-info.ts +++ b/front/packages/models/src/resources/watch-info.ts @@ -18,21 +18,10 @@ * along with Kyoo. If not, see . */ -import i18next from "i18next"; import { z } from "zod"; import { imageFn } from "../traits"; import { QualityP } from "./quality"; -const getDisplayName = (sub: Track) => { - const languageNames = new Intl.DisplayNames([i18next.language ?? "en"], { type: "language" }); - const lng = sub.language ? languageNames.of(sub.language) : undefined; - - if (lng && sub.title && sub.title !== lng) return `${lng} - ${sub.title}`; - if (lng) return lng; - if (sub.title) return sub.title; - return `Unknown (${sub.index})`; -}; - /** * A Video track */ @@ -97,10 +86,7 @@ export const TrackP = z.object({ }); export type Track = z.infer; -export const AudioP = TrackP.transform((x) => ({ - ...x, - displayName: getDisplayName(x), -})); +export const AudioP = TrackP; export type Audio = z.infer; export const SubtitleP = TrackP.extend({ @@ -108,10 +94,7 @@ export const SubtitleP = TrackP.extend({ * The url of this track (only if this is a subtitle).. */ link: z.string().transform(imageFn).nullable(), -}).transform((x) => ({ - ...x, - displayName: getDisplayName(x), -})); +}); export type Subtitle = z.infer; export const ChapterP = z.object({ diff --git a/front/packages/primitives/src/themes/theme.tsx b/front/packages/primitives/src/themes/theme.tsx index dfe6447b..7f1a37e5 100644 --- a/front/packages/primitives/src/themes/theme.tsx +++ b/front/packages/primitives/src/themes/theme.tsx @@ -27,7 +27,9 @@ import { useTheme, useYoshiki } from "yoshiki/native"; import "yoshiki/native"; import { catppuccin } from "./catppuccin"; -type FontList = Partial, string>>; +type FontList = Partial< + Record, string> +>; type Mode = { mode: "light" | "dark" | "auto"; diff --git a/front/packages/ui/src/components/context-menus.tsx b/front/packages/ui/src/components/context-menus.tsx index af9e6673..ea2904b6 100644 --- a/front/packages/ui/src/components/context-menus.tsx +++ b/front/packages/ui/src/components/context-menus.tsx @@ -95,7 +95,7 @@ export const EpisodesContext = ({ {Object.values(WatchStatusV).map((x) => ( }`)} onSelect={() => mutation.mutate(x)} selected={x === status} /> diff --git a/front/packages/ui/src/components/media-info.tsx b/front/packages/ui/src/components/media-info.tsx index ae7d9099..77b2dc65 100644 --- a/front/packages/ui/src/components/media-info.tsx +++ b/front/packages/ui/src/components/media-info.tsx @@ -31,16 +31,19 @@ import { useTranslation } from "react-i18next"; import { View } from "react-native"; import { useYoshiki } from "yoshiki/native"; import { Fetch } from "../fetch"; +import { useDisplayName } from "../utils"; const MediaInfoTable = ({ mediaInfo: { path, video, container, audios, subtitles, duration, size }, }: { mediaInfo: Partial; }) => { + const getDisplayName = useDisplayName(); const { t } = useTranslation(); const { css } = useYoshiki(); + const formatBitrate = (b: number) => `${(b / 1000000).toFixed(2)} Mbps`; - const formatTrackTable = (trackTable: (Audio | Subtitle)[], s: string) => { + const formatTrackTable = (trackTable: (Audio | Subtitle)[], type: "subtitles" | "audio") => { if (trackTable.length === 0) { return undefined; } @@ -48,15 +51,16 @@ const MediaInfoTable = ({ return trackTable.reduce( (collected, audioTrack, index) => { // If there is only one track, we do not need to show an index - collected[singleTrack ? t(s) : `${t(s)} ${index + 1}`] = [ - audioTrack.displayName, - // Only show it if there is more than one track - audioTrack.isDefault && !singleTrack ? t("mediainfo.default") : undefined, - audioTrack.isForced ? t("mediainfo.forced") : undefined, - audioTrack.codec, - ] - .filter((x) => x !== undefined) - .join(" - "); + collected[singleTrack ? t(`mediainfo.${type}`) : `${t(`mediainfo.${type}`)} ${index + 1}`] = + [ + getDisplayName(audioTrack), + // Only show it if there is more than one track + audioTrack.isDefault && !singleTrack ? t("mediainfo.default") : undefined, + audioTrack.isForced ? t("mediainfo.forced") : undefined, + audioTrack.codec, + ] + .filter((x) => x !== undefined) + .join(" - "); return collected; }, {} as Record, @@ -81,10 +85,10 @@ const MediaInfoTable = ({ }, audios === undefined ? { [t("mediainfo.audio")]: undefined } - : formatTrackTable(audios, "mediainfo.audio"), + : formatTrackTable(audios, "audio"), subtitles === undefined ? { [t("mediainfo.subtitles")]: undefined } - : formatTrackTable(subtitles, "mediainfo.subtitles"), + : formatTrackTable(subtitles, "subtitles"), ] as const ).filter((x) => x !== undefined) as Record[]; return ( diff --git a/front/packages/ui/src/player/components/hover.tsx b/front/packages/ui/src/player/components/hover.tsx index db0f8b45..b4170e6f 100644 --- a/front/packages/ui/src/player/components/hover.tsx +++ b/front/packages/ui/src/player/components/hover.tsx @@ -295,6 +295,7 @@ export const HoverTouch = ({ children, ...props }: { children: ReactNode }) => { playerWidth.current = e.nativeEvent.layout.width; }} {...css( + // @ts-expect-error Web only property (cursor: unset) { flexDirection: "row", justifyContent: "center", @@ -304,7 +305,6 @@ export const HoverTouch = ({ children, ...props }: { children: ReactNode }) => { left: 0, right: 0, bottom: 0, - // @ts-expect-error Web only property cursor: hover ? "unset" : "none", }, props, diff --git a/front/packages/ui/src/player/components/right-buttons.tsx b/front/packages/ui/src/player/components/right-buttons.tsx index 28ecb01f..cb790538 100644 --- a/front/packages/ui/src/player/components/right-buttons.tsx +++ b/front/packages/ui/src/player/components/right-buttons.tsx @@ -31,6 +31,7 @@ import { Platform, View } from "react-native"; import { type Stylable, useYoshiki } from "yoshiki/native"; import { fullscreenAtom, subtitleAtom } from "../state"; import { AudiosMenu, QualitiesMenu } from "../video"; +import { useDisplayName } from "../../utils"; export const RightButtons = ({ audios, @@ -48,6 +49,7 @@ export const RightButtons = ({ } & Stylable) => { const { css } = useYoshiki(); const { t } = useTranslation(); + const getDisplayName = useDisplayName(); const [isFullscreen, setFullscreen] = useAtom(fullscreenAtom); const [selectedSubtitle, setSubtitle] = useAtom(subtitleAtom); @@ -72,7 +74,7 @@ export const RightButtons = ({ {subtitles.map((x) => ( setSubtitle(x)} diff --git a/front/packages/ui/src/utils.ts b/front/packages/ui/src/utils.ts new file mode 100644 index 00000000..26ea0b75 --- /dev/null +++ b/front/packages/ui/src/utils.ts @@ -0,0 +1,16 @@ +import type { Track } from "@kyoo/models"; +import { useTranslation } from "react-i18next"; + +export const useDisplayName = () => { + const { i18n } = useTranslation(); + + return (sub: Track) => { + const languageNames = new Intl.DisplayNames([i18n.language ?? "en"], { type: "language" }); + const lng = sub.language ? languageNames.of(sub.language) : undefined; + + if (lng && sub.title && sub.title !== lng) return `${lng} - ${sub.title}`; + if (lng) return lng; + if (sub.title) return sub.title; + return `Unknown (${sub.index})`; + }; +};