fix(mobile): Edge bez agresywnego kadrowania na foldzie i przy poziomych klipach
Zgloszenie Jana (fold): rozlozony ekran jest prawie kwadratowy, a klip byl skalowany do wypelnienia i zostawal z niego srodek. Teraz liczymy, ile by sie ucielo: do 30 % zostaje wypelnienie (pionowy klip na zwyklym telefonie traci ok. 20 % szerokosci i to jest OK), powyzej cale wideo i czarne pasy. Podpis i kolumna przyciskow stoja przy krawedziach ekranu, wiec przy pasach same wchodza na pasy zamiast na wideo. Poster pod wideo dostaje to samo kadrowanie, zeby nie mrugalo przy starcie. Zysk takze na zwyklym telefonie: ok. 19 % klipow RedGifs jest poziomych i do tej pory byly rozdmuchane na caly ekran. Zmierzone na emulatorze przez rozmiar powierzchni wideo (dumpsys activity top): - telefon 1080x2400: pionowy klip 1242x2209 (wypelnienie, jak dotad), poziomy 1080x607 i klip 3:4 1080x1440 (pasy zamiast kadrowania) - rozlozony fold 1768x2208: pionowy klip 1140x1947 z pasami po 314 px, poziomy 1768x1298 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7bfd194485
commit
45754afc69
2 changed files with 31 additions and 3 deletions
|
|
@ -35,6 +35,14 @@ export type ChangelogEntry = {
|
|||
};
|
||||
|
||||
export const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
id: '2026-09-16d',
|
||||
date: 'September 2026',
|
||||
items: [
|
||||
'Edge on a folding phone or a tablet: clips are no longer cropped down to the middle. When the screen and the clip are shaped too differently, you get the whole clip with black bars instead, and the caption and buttons sit on those bars. Wide clips gain from this on normal phones too.',
|
||||
],
|
||||
minRuntime: '1.4',
|
||||
},
|
||||
{
|
||||
id: '2026-09-16c',
|
||||
date: 'September 2026',
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import { Image } from 'expo-image';
|
|||
import type { VideoPlayer } from 'expo-video';
|
||||
import { VideoView } from 'expo-video';
|
||||
import React from 'react';
|
||||
import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import { Animated, Pressable, StyleSheet, Text, View, useWindowDimensions } from 'react-native';
|
||||
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
|
|
@ -49,6 +49,26 @@ function ClipCellBase({ item, active, player, muted, liked, onToggleMute, onLike
|
|||
const [ready, setReady] = React.useState(false);
|
||||
const heart = React.useRef(new Animated.Value(0)).current;
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
// Kadrowac czy dolozyc czarne pasy.
|
||||
//
|
||||
// `cover` wypelnia ekran i tnie to, co wystaje. Na zwyklym telefonie pionowy klip traci
|
||||
// tak ze 20 % szerokosci i nikomu to nie przeszkadza, ale na rozlozonym foldzie ekran
|
||||
// jest prawie kwadratowy i z pionowego klipu zostaje srodek (zgloszenie Jana
|
||||
// 2026-09-16). To samo dotyczy klipow poziomych, ktorych na RedGifs jest ok. 19 %.
|
||||
// Liczymy, ile by sie ucielo: do `MAX_CROP` zostaje `cover`, powyzej `contain`, czyli
|
||||
// cale wideo i pasy po bokach albo u gory. Podpis i kolumna przyciskow stoja przy
|
||||
// krawedziach ekranu, wiec przy pasach same wchodza na pasy zamiast na wideo.
|
||||
// `useWindowDimensions` reaguje na zlozenie i obrot, wiec kadr zmienia sie od razu.
|
||||
const win = useWindowDimensions();
|
||||
const fit = React.useMemo<'cover' | 'contain'>(() => {
|
||||
const MAX_CROP = 1.3;
|
||||
const clipAspect = clip.width && clip.height ? clip.width / clip.height : 9 / 16;
|
||||
const screenAspect = win.width / Math.max(win.height, 1);
|
||||
if (!clipAspect || !screenAspect) return 'cover';
|
||||
const crop = Math.max(screenAspect / clipAspect, clipAspect / screenAspect);
|
||||
return crop > MAX_CROP ? 'contain' : 'cover';
|
||||
}, [clip.width, clip.height, win.width, win.height]);
|
||||
const lift = React.useMemo(
|
||||
() =>
|
||||
barHidden.interpolate({
|
||||
|
|
@ -154,14 +174,14 @@ function ClipCellBase({ item, active, player, muted, liked, onToggleMute, onLike
|
|||
<GestureDetector gesture={gestures}>
|
||||
<View style={StyleSheet.absoluteFill} collapsable={false}>
|
||||
{poster ? (
|
||||
<Image source={{ uri: poster }} style={StyleSheet.absoluteFill} contentFit="cover" transition={0} />
|
||||
<Image source={{ uri: poster }} style={StyleSheet.absoluteFill} contentFit={fit} transition={0} />
|
||||
) : null}
|
||||
{active && player ? (
|
||||
<VideoView
|
||||
player={player}
|
||||
style={[StyleSheet.absoluteFill, !ready && { opacity: 0 }]}
|
||||
nativeControls={false}
|
||||
contentFit="cover"
|
||||
contentFit={fit}
|
||||
allowsPictureInPicture={false}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue