小组件换行文案更新

This commit is contained in:
吕新雨
2026-02-10 13:35:32 +08:00
29 changed files with 751 additions and 208 deletions

View File

@@ -55,6 +55,7 @@ import { getBootId } from '@/src/utils/bootSession';
import { advanceSuixinState, buildInitialSuixinState, NEUTRAL_THEME_COLORS } from '@/src/features/suixinTheme';
import { wrapText } from '@/src/features/textWrap';
import { defaultMeasureWidthImpl } from '@/src/features/textWrap/measure';
import { ensureDailyWidgetRecoUpToDate } from '@/src/modules/dailyWidgetReco';
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
@@ -265,11 +266,24 @@ export default function HomeScreen() {
maxLines: 3,
overflowMode: 'CLIP',
lineMode: 'AUTO',
configVersion: 'v1',
// Home采用“更偏好语气停顿/更好看”的排版风格微调(不影响算法默认 v1
configVersion: 'v1-home',
debug: __DEV__,
fontSpec,
contextProfile: `APP|${Platform.OS}|home|${lang}`,
measureWidthImpl: defaultMeasureWidthImpl,
scoringOverrides:
lang === 'TC'
? {
// 更偏好在逗号/句号等处断行(即便宽度允许也不一定要塞满)
weights: { R_PUNCT_BREAK: 180 },
// 让“理想行宽”更短,避免宽屏下过度延后断行
idealWidthRatio: { APP: 0.82 },
// 更宽容短行(尤其是第一行在标点处停顿)
minPreferredRatio: 0.45,
shortLastLineRatio: 0.45,
}
: undefined,
});
if (cancelled) return;
@@ -377,6 +391,11 @@ export default function HomeScreen() {
setIndex(0);
fetchNewFeed();
}
// Widget前台辅助刷新尽力而为
// - 写入 App Group 的 dailyReco 缓存
// - 生成 wrapped_text_by_family供 Widget 直接渲染
ensureDailyWidgetRecoUpToDate({ reason: 'home_focus' }).catch(() => {});
})();
return () => {
cancelled = true;
@@ -444,13 +463,41 @@ export default function HomeScreen() {
});
}, [busy, index, currentFeed.length, isFetching, fetchNewFeed, translateY, opacity]);
// 切换到上一条文案的统一动画逻辑(下滑触发)
const triggerPrevContent = useCallback(() => {
if (busy) return;
setBusy(true);
// 1. 当前文案向下移动并消失
translateY.value = withTiming(40, { duration: 300, easing: Easing.out(Easing.quad) });
opacity.value = withTiming(0, { duration: 300 }, (finished) => {
if (finished) {
// 2. 切换数据索引(循环回退)
const nextIndex = index - 1 < 0 ? Math.max(0, currentFeed.length - 1) : index - 1;
runOnJS(setIndex)(nextIndex);
runOnJS(setLikeFilled)(false);
// 3. 准备上一条文案:先瞬移到上方 40pt
translateY.value = -40;
// 4. 上一条文案向下移动到原位并显现
translateY.value = withTiming(0, { duration: 400, easing: Easing.out(Easing.back(1)) });
opacity.value = withTiming(1, { duration: 400 }, (finished) => {
if (finished) {
runOnJS(setBusy)(false);
}
});
}
});
}, [busy, index, currentFeed.length, translateY, opacity]);
const lastTapRef = useRef<number>(0);
// 使用 Ref 解决 PanResponder 闭包陷阱,确保手势回调能拿到最新的 state 和 function
const handlersRef = useRef({ onPressLike, triggerNextContent });
const handlersRef = useRef({ onPressLike, triggerNextContent, triggerPrevContent });
useEffect(() => {
handlersRef.current = { onPressLike, triggerNextContent };
}, [onPressLike, triggerNextContent]);
handlersRef.current = { onPressLike, triggerNextContent, triggerPrevContent };
}, [onPressLike, triggerNextContent, triggerPrevContent]);
// 使用系统自带的 PanResponder 代替第三方手势库
const panResponder = useRef(
@@ -475,9 +522,11 @@ export default function HomeScreen() {
}
lastTapRef.current = now;
// 2. 上滑逻辑判定
// 2. 上滑/下滑逻辑判定
if (gestureState.dy < -50) { // 上滑超过 50pt
runOnJS(handlersRef.current.triggerNextContent)();
} else if (gestureState.dy > 50) { // 下滑超过 50pt
runOnJS(handlersRef.current.triggerPrevContent)();
}
},
})
@@ -549,13 +598,13 @@ export default function HomeScreen() {
onPress={() => setThemeOpen(true)}
accessibilityLabel={t('home.theme')}
>
<ThemeIcon width={18} height={18} />
<ThemeIcon width={20} height={20} />
</CircleIconButton>
<CircleIconButton
onPress={() => setProfileOpen(true)}
accessibilityLabel={t('home.profile')}
>
<MyIcon width={18} height={18} />
<MyIcon width={20} height={20} />
</CircleIconButton>
</View>
@@ -577,15 +626,16 @@ export default function HomeScreen() {
onPress={onPressLike}
accessibilityRole="button"
accessibilityLabel={t('home.like')}
hitSlop={20}
// 稍微增大可点击区域,提升单手操作成功率
hitSlop={24}
style={styles.reactionInner}
>
{likeFilled ? (
<LikeFilledIcon width={35} height={36} color="#EA6969" />
<LikeFilledIcon width={40} height={41} color="#EA6969" />
) : (
<LikeIcon
width={35}
height={36}
width={40}
height={41}
color={themeMode === 'scenery' ? '#FFFFFF' : '#5E2A28'}
/>
)}
@@ -615,7 +665,8 @@ function CircleIconButton({
return (
<Pressable
onPress={onPress}
hitSlop={10}
// 稍微增大可点击区域,提升易用性
hitSlop={14}
accessibilityRole="button"
accessibilityLabel={accessibilityLabel}
style={styles.circleBtn}
@@ -640,9 +691,9 @@ const styles = StyleSheet.create({
zIndex: 30,
},
circleBtn: {
width: 34,
height: 34,
borderRadius: 17,
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: 'rgba(255,255,255,0.75)',
alignItems: 'center',
justifyContent: 'center',