Fix bottom scrubber on android

This commit is contained in:
Zoe Roux 2024-01-28 18:39:16 +01:00
parent 085d337fb7
commit 0cc6274894
4 changed files with 63 additions and 51 deletions

View File

@ -27,7 +27,7 @@ import { ContrastArea } from "../themes";
import { percent } from "yoshiki/native"; import { percent } from "yoshiki/native";
import { imageBorderRadius } from "../constants"; import { imageBorderRadius } from "../constants";
export { FastImage } from "./fast-image"; export { Sprite } from "./sprite";
export { BlurhashContainer } from "./blurhash"; export { BlurhashContainer } from "./blurhash";
export { type Props as ImageProps, Image }; export { type Props as ImageProps, Image };

View File

@ -18,10 +18,9 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>. * along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { View } from "react-native"; import { Image, View } from "react-native";
import FImage from "react-native-fast-image";
export const FastImage = ({ export const Sprite = ({
src, src,
alt, alt,
width, width,
@ -45,21 +44,12 @@ export const FastImage = ({
}) => { }) => {
return ( return (
<View style={{ width, height, overflow: "hidden", flexGrow: 0, flexShrink: 0 }}> <View style={{ width, height, overflow: "hidden", flexGrow: 0, flexShrink: 0 }}>
<FImage <Image
source={{ source={{ uri: src }}
uri: src, alt={alt}
priority: FImage.priority.low, width={width * columns}
}} height={height * rows}
accessibilityLabel={alt} style={{ transform: [{ translateX: -x }, { translateY: -y }] }}
resizeMode={FImage.resizeMode.cover}
style={[
{
width: width * columns,
height: height * rows,
transform: `translate(${-x}px, ${-y}px)`,
},
style,
]}
{...props} {...props}
/> />
</View> </View>

View File

@ -20,7 +20,7 @@
import NextImage from "next/image"; import NextImage from "next/image";
export const FastImage = ({ export const Sprite = ({
src, src,
alt, alt,
style, style,
@ -31,8 +31,8 @@ export const FastImage = ({
src: string; src: string;
alt: string; alt: string;
style?: object; style?: object;
width: number | string; width: number;
height: number | string; height: number;
x: number; x: number;
y: number; y: number;
}) => { }) => {
@ -43,7 +43,13 @@ export const FastImage = ({
alt={alt!} alt={alt!}
// Don't use next's server to reprocess images, they are already optimized by kyoo. // Don't use next's server to reprocess images, they are already optimized by kyoo.
unoptimized={true} unoptimized={true}
style={{ objectFit: "none", objectPosition: `${-x}px ${-y}px`, ...style }} style={{
objectFit: "none",
objectPosition: `${-x}px ${-y}px`,
flexGrow: 0,
flexShrink: 0,
...style,
}}
{...props} {...props}
/> />
); );

View File

@ -19,11 +19,11 @@
*/ */
import { useFetch, QueryIdentifier, imageFn, Chapter } from "@kyoo/models"; import { useFetch, QueryIdentifier, imageFn, Chapter } from "@kyoo/models";
import { FastImage, P, imageBorderRadius, ts } from "@kyoo/primitives"; import { Sprite, P, imageBorderRadius, ts } from "@kyoo/primitives";
import { View } from "react-native"; import { View, Platform } from "react-native";
import { percent, useYoshiki, px, Theme } from "yoshiki/native"; import { percent, useYoshiki, px, Theme, useForceRerender } from "yoshiki/native";
import { ErrorView } from "../../fetch"; import { ErrorView } from "../../fetch";
import { useMemo } from "react"; import { useMemo, useState } from "react";
import { useAtomValue } from "jotai"; import { useAtomValue } from "jotai";
import { durationAtom, progressAtom } from "../state"; import { durationAtom, progressAtom } from "../state";
import { toTimerString } from "./left-buttons"; import { toTimerString } from "./left-buttons";
@ -128,7 +128,7 @@ export const ScrubberTooltip = ({
})} })}
> >
{current && ( {current && (
<FastImage <Sprite
src={current.url} src={current.url}
alt={""} alt={""}
width={current.width} width={current.width}
@ -145,10 +145,12 @@ export const ScrubberTooltip = ({
</View> </View>
); );
}; };
let scrubberWidth = 0;
export const BottomScrubber = ({ url }: { url: string }) => { export const BottomScrubber = ({ url }: { url: string }) => {
const { css } = useYoshiki(); const { css } = useYoshiki();
const { info, error, stats } = useScrubber(url); const { info, error, stats } = useScrubber(url);
const rerender = useForceRerender();
const progress = useAtomValue(progressAtom); const progress = useAtomValue(progressAtom);
const duration = useAtomValue(durationAtom) ?? 1; const duration = useAtomValue(durationAtom) ?? 1;
@ -159,30 +161,44 @@ export const BottomScrubber = ({ url }: { url: string }) => {
return ( return (
<View {...css({ overflow: "hidden" })}> <View {...css({ overflow: "hidden" })}>
<View <View
{...css( {...(Platform.OS === "web"
{ flexDirection: "row" }, ? css({ transform: `translateX(50%)` })
{ : {
style: { // react-native does not support translateX by percentage so we simulate it
transform: `translateX(calc(${ style: { transform: [{ translateX: scrubberWidth / 2 }] },
(progress / duration) * -width * info.length - width / 2 onLayout: (e) => {
}px + 50%))`, if (!e.nativeEvent.layout.width) return;
}, scrubberWidth = e.nativeEvent.layout.width;
}, rerender();
)} },
})}
> >
{info.map((thumb) => ( <View
<FastImage {...css(
key={thumb.to} { flexDirection: "row" },
src={thumb.url} {
alt="" style: {
width={thumb.width} transform: `translateX(${
height={thumb.height} (progress / duration) * -width * info.length - width / 2
x={thumb.x} }px)`,
y={thumb.y} },
columns={stats!.columns} },
rows={stats!.rows} )}
/> >
))} {info.map((thumb) => (
<Sprite
key={thumb.to}
src={thumb.url}
alt=""
width={thumb.width}
height={thumb.height}
x={thumb.x}
y={thumb.y}
columns={stats!.columns}
rows={stats!.rows}
/>
))}
</View>
</View> </View>
<View <View
{...css({ {...css({