fix:
1. 修复安卓部分机型顶部安全区遮挡回忆录标题的问题; 2. 降低封面图生成阈值和展示逻辑,独立封面图未生成时,使用正文图; 3. 去掉“嗯。”生硬回答,去掉不合理段首承接词; 4. 新增章节封面所需最少插图数的配置项
This commit is contained in:
@@ -18,8 +18,13 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Icon } from '@/components/ui/icon';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { ScreenHeader } from '@/components/screen-header';
|
||||
import {
|
||||
getScreenHeaderLayoutMetrics,
|
||||
ScreenHeader,
|
||||
} from '@/components/screen-header';
|
||||
import { ScreenGutter } from '@/constants/layout';
|
||||
import { useTypography } from '@/core/typography-context';
|
||||
import { useAppSettings } from '@/hooks/use-app-settings';
|
||||
import {
|
||||
MarkdownRenderer,
|
||||
ReadingMarkdownHorizontalRuleInColumn,
|
||||
@@ -353,6 +358,8 @@ function ReadingSettingsModal({
|
||||
export default function ChapterScreen() {
|
||||
const { id } = useLocalSearchParams<{ id: string }>();
|
||||
const insets = useSafeAreaInsets();
|
||||
const { largeText } = useAppSettings();
|
||||
const typography = useTypography();
|
||||
const { width } = useWindowDimensions();
|
||||
const { t } = useTranslation('memoir');
|
||||
const { data: chapter, isLoading } = useChapterDetail(id ?? '');
|
||||
@@ -429,8 +436,13 @@ export default function ChapterScreen() {
|
||||
const useReadingSegments =
|
||||
Array.isArray(readingSegments) && readingSegments.length > 0;
|
||||
|
||||
/** 与 ScreenHeader(reading、useSafeArea)可视高度对齐,避免返回栏与首屏内容之间出现空隙 */
|
||||
const headerOccupiedHeight = Math.max(insets.top, 12) + 56;
|
||||
/** 与 ScreenHeader(reading、useSafeArea)实际总高度一致,避免章节标题被顶栏或安全区遮挡 */
|
||||
const headerOccupiedHeight = getScreenHeaderLayoutMetrics(insets, {
|
||||
useSafeArea: true,
|
||||
variant: 'reading',
|
||||
largeText,
|
||||
typography,
|
||||
}).totalHeight;
|
||||
|
||||
const handleDeletePress = () => {
|
||||
Alert.alert(
|
||||
|
||||
@@ -9,6 +9,8 @@ import { useTypography } from '@/core/typography-context';
|
||||
import { ScreenGutter } from '@/constants/layout';
|
||||
import { useAppSettings } from '@/hooks/use-app-settings';
|
||||
|
||||
import type { TypographyTokens } from '@/core/typography-context';
|
||||
|
||||
/** 默认最小触控目标 48dp;大字模式下与标题字号匹配,略向左扩展便于够到边缘 */
|
||||
const BACK_HIT_MIN = 48;
|
||||
const BACK_HIT_MIN_LARGE = 56;
|
||||
@@ -18,6 +20,52 @@ const BACK_EXTRA_HIT_LEFT = 4;
|
||||
|
||||
export type ScreenHeaderVariant = 'default' | 'chat' | 'reading';
|
||||
|
||||
export type ScreenHeaderLayoutOpts = {
|
||||
useSafeArea: boolean;
|
||||
variant: ScreenHeaderVariant;
|
||||
largeText: boolean;
|
||||
typography: TypographyTokens;
|
||||
};
|
||||
|
||||
/**
|
||||
* 与组件内布局一致的总高度(含顶部安全区内边距),供绝对定位顶栏下的 ScrollView paddingTop 等使用。
|
||||
*/
|
||||
export function getScreenHeaderLayoutMetrics(
|
||||
insets: { top: number },
|
||||
opts: ScreenHeaderLayoutOpts,
|
||||
) {
|
||||
const barPaddingBottom = opts.largeText ? 18 : 16;
|
||||
const titleRowPaddingV = opts.largeText ? 8 : 4;
|
||||
const backTouchMin = opts.largeText ? BACK_HIT_MIN_LARGE : BACK_HIT_MIN;
|
||||
const { variant, typography, largeText } = opts;
|
||||
const titleFontSize =
|
||||
variant === 'chat'
|
||||
? largeText
|
||||
? typography.headingMedium
|
||||
: typography.headingSmall
|
||||
: Math.max(typography.titleLarge, typography.headingSmall);
|
||||
const titleLineMin =
|
||||
variant === 'chat'
|
||||
? Math.ceil(titleFontSize * (largeText ? 1.45 : 1.38)) +
|
||||
(largeText ? 14 : 10)
|
||||
: Math.ceil(titleFontSize * 1.32) + (largeText ? 10 : 8);
|
||||
const titleRowMinHeight = Math.max(backTouchMin, titleLineMin);
|
||||
const titleRowOuterHeight = titleRowMinHeight + 2 * titleRowPaddingV;
|
||||
const paddingTop = opts.useSafeArea ? Math.max(insets.top, 12) : 12;
|
||||
const totalHeight = paddingTop + titleRowOuterHeight + barPaddingBottom;
|
||||
return {
|
||||
barPaddingBottom,
|
||||
titleRowPaddingV,
|
||||
titleFontSize,
|
||||
titleLineMin,
|
||||
titleRowMinHeight,
|
||||
titleRowOuterHeight,
|
||||
paddingTop,
|
||||
totalHeight,
|
||||
backTouchMin,
|
||||
};
|
||||
}
|
||||
|
||||
const VARIANT_COLORS = {
|
||||
default: {
|
||||
title: undefined, // use theme foreground
|
||||
@@ -76,7 +124,6 @@ export function ScreenHeader({
|
||||
const typography = useTypography();
|
||||
const colors = VARIANT_COLORS[variant];
|
||||
|
||||
const backTouchMin = largeText ? BACK_HIT_MIN_LARGE : BACK_HIT_MIN;
|
||||
const backIconSize = largeText ? BACK_ICON_SIZE_LARGE : BACK_ICON_SIZE;
|
||||
|
||||
const handleBack = onBack ?? (() => router.back());
|
||||
@@ -88,27 +135,26 @@ export function ScreenHeader({
|
||||
* 不要用外层 minHeight「框死」整块栏:paddingTop 含安全区时会把内容区压扁。
|
||||
* 标题行最小高度随当前排版 token 计算(关大字也要留够,避免裁字 / Android font padding)。
|
||||
*/
|
||||
const barPaddingBottom = largeText ? 18 : 16;
|
||||
const titleRowPaddingV = largeText ? 8 : 4;
|
||||
const titleFontSize =
|
||||
variant === 'chat'
|
||||
? largeText
|
||||
? typography.headingMedium
|
||||
: typography.headingSmall
|
||||
: Math.max(typography.titleLarge, typography.headingSmall);
|
||||
const titleLineMin =
|
||||
variant === 'chat'
|
||||
? Math.ceil(titleFontSize * (largeText ? 1.45 : 1.38)) +
|
||||
(largeText ? 14 : 10)
|
||||
: Math.ceil(titleFontSize * 1.32) + (largeText ? 10 : 8);
|
||||
const titleRowMinHeight = Math.max(backTouchMin, titleLineMin);
|
||||
const {
|
||||
barPaddingBottom,
|
||||
titleRowPaddingV,
|
||||
titleFontSize,
|
||||
titleRowMinHeight,
|
||||
paddingTop: headerPaddingTop,
|
||||
backTouchMin,
|
||||
} = getScreenHeaderLayoutMetrics(insets, {
|
||||
useSafeArea,
|
||||
variant,
|
||||
largeText,
|
||||
typography,
|
||||
});
|
||||
|
||||
const containerStyle = {
|
||||
flexDirection: 'row' as const,
|
||||
alignItems: 'center' as const,
|
||||
justifyContent: 'space-between' as const,
|
||||
paddingHorizontal: Math.max(ScreenGutter, 16),
|
||||
paddingTop: useSafeArea ? Math.max(insets.top, 12) : 12,
|
||||
paddingTop: headerPaddingTop,
|
||||
paddingBottom: barPaddingBottom,
|
||||
...(bgColor && { backgroundColor: bgColor }),
|
||||
...(absolute && {
|
||||
|
||||
Reference in New Issue
Block a user