fix(ui): 列表剧名统一两行省略,收藏卡去掉观看进度副标题
筛选、追剧收藏、新片、榜单、缓存与推荐上新等列表卡都按两行剧名预留高度, 超长标题显示省略号;收藏卡不再显示「看到第 N 集」,文字区高度同步收窄。
This commit is contained in:
1 parent
4dd37b2588
commit
c311985601
9 files changed
+31
-48
No files matched your search
@@ -150,8 +150,8 @@ abstract final class AppDimens {
|
|||||||
static const double recommendSectionTitle = 17;
|
static const double recommendSectionTitle = 17;
|
||||||
static const double recommendSectionSubtitle = 11;
|
static const double recommendSectionSubtitle = 11;
|
||||||
static const double recommendSectionMore = 12;
|
static const double recommendSectionMore = 12;
|
||||||
// 封面 122*(4/3)≈163 + 间距6 + 两行标题39 + 间距6 + 标签13 ≈ 227。
|
// 封面 122*(4/3)≈163 + 间距6 + 两行标题≈42 + 间距6 + 标签≈13 ≈ 230,留 6 余量。
|
||||||
static const double recommendRowHeight = 228;
|
static const double recommendRowHeight = 236;
|
||||||
static const double recommendCardWidth = 122;
|
static const double recommendCardWidth = 122;
|
||||||
|
|
||||||
/// 首页热播榜。
|
/// 首页热播榜。
|
||||||
@@ -189,9 +189,9 @@ abstract final class AppDimens {
|
|||||||
static const double followingAddIconStroke = 1.5;
|
static const double followingAddIconStroke = 1.5;
|
||||||
static const double followingGridGap = 6;
|
static const double followingGridGap = 6;
|
||||||
static const double followingGridRowGap = 12;
|
static const double followingGridRowGap = 12;
|
||||||
// 单行标题 16*1.3=20.8 + 间距 6+4 + 副标题行高约 18.6 ≈ 49.4,留 0.6 余量;
|
|
||||||
// 按 48 估算在副标题行高偏高的字体下会溢出 1~2px。
|
/// 追剧网格卡文字区:间距 6 + 两行剧名 16*1.3*2=41.6 ≈ 48,留 4 余量。
|
||||||
static const double followingCardTextExtent = 50;
|
static const double followingCardTextExtent = 52;
|
||||||
static const double followingSubtitleFont = 12;
|
static const double followingSubtitleFont = 12;
|
||||||
static const double followingSubtitleGap = 4;
|
static const double followingSubtitleGap = 4;
|
||||||
static const double followingProgressHeight = 2;
|
static const double followingProgressHeight = 2;
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ class _LicenseTile extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
license.dramaTitle,
|
license.dramaTitle,
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.onSurface,
|
color: AppColors.onSurface,
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ const double _optionHorizontal = 5;
|
|||||||
const double _optionVertical = 5;
|
const double _optionVertical = 5;
|
||||||
const double _optionRunGap = 4;
|
const double _optionRunGap = 4;
|
||||||
const double _cardGap = 14;
|
const double _cardGap = 14;
|
||||||
const double _gridAspectRatio = 0.56;
|
|
||||||
|
/// 卡片比例:三列网格里要装下封面 + 两行剧名 + 元信息。
|
||||||
|
const double _gridAspectRatio = 0.53;
|
||||||
const double _groupFontSize = 13;
|
const double _groupFontSize = 13;
|
||||||
const double _labelFontSize = 12;
|
const double _labelFontSize = 12;
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class FilterResultCard extends StatelessWidget {
|
|||||||
Text(
|
Text(
|
||||||
drama.title,
|
drama.title,
|
||||||
key: Key('filter-title-${drama.id}'),
|
key: Key('filter-title-${drama.id}'),
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.onSurface,
|
color: AppColors.onSurface,
|
||||||
|
|||||||
@@ -167,18 +167,10 @@ class FollowingFavoritesGrid extends StatelessWidget {
|
|||||||
bool isEditing,
|
bool isEditing,
|
||||||
Set<String> picked,
|
Set<String> picked,
|
||||||
) {
|
) {
|
||||||
final l10n = AppLocalizations.of(context)!;
|
|
||||||
if (index == controller.cards.length) {
|
if (index == controller.cards.length) {
|
||||||
return FollowingAddCard(onTap: onGoHome);
|
return FollowingAddCard(onTap: onGoHome);
|
||||||
}
|
}
|
||||||
final drama = controller.cards[index];
|
final drama = controller.cards[index];
|
||||||
final record = history.recordForDrama(drama.id);
|
|
||||||
final episode = drama.episodes.isEmpty ? 1 : drama.episodes.first.number;
|
|
||||||
final watchedEpisode = record?.episodeNumber ?? 0;
|
|
||||||
final total = drama.episodeCount;
|
|
||||||
final subtitle = watchedEpisode > 0 && total > 0
|
|
||||||
? l10n.watchedEpisodeTotal(watchedEpisode, total)
|
|
||||||
: l10n.favoriteEpisodeProgress(episode, total);
|
|
||||||
return FollowingGridCard(
|
return FollowingGridCard(
|
||||||
dramaId: drama.id,
|
dramaId: drama.id,
|
||||||
title: drama.localizedTitle(Localizations.localeOf(context).languageCode),
|
title: drama.localizedTitle(Localizations.localeOf(context).languageCode),
|
||||||
@@ -186,10 +178,7 @@ class FollowingFavoritesGrid extends StatelessWidget {
|
|||||||
viewCount: drama.viewCount,
|
viewCount: drama.viewCount,
|
||||||
editing: isEditing,
|
editing: isEditing,
|
||||||
selected: isEditing ? picked.contains(drama.id) : null,
|
selected: isEditing ? picked.contains(drama.id) : null,
|
||||||
subtitle: subtitle,
|
// TODO(backend): Drama 增加 hasUpdate 字段后,在此传 updateBadge。
|
||||||
// TODO(backend): Drama 增加 hasUpdate / latestEpisodeNumber / isFinished
|
|
||||||
// 字段后,在此传 updateBadge(l10n.hasUpdateBadge)、红色更新副标题
|
|
||||||
// (l10n.updatedToEpisode)或灰色完结副标题(l10n.finishedAllEpisodes)。
|
|
||||||
onTap: () => _openOrToggle(context, drama.id, isEditing),
|
onTap: () => _openOrToggle(context, drama.id, isEditing),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,21 +19,18 @@ class FollowingGridCard extends StatelessWidget {
|
|||||||
required this.title,
|
required this.title,
|
||||||
required this.posterUrl,
|
required this.posterUrl,
|
||||||
required this.viewCount,
|
required this.viewCount,
|
||||||
required this.subtitle,
|
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.progress,
|
this.progress,
|
||||||
this.editing = false,
|
this.editing = false,
|
||||||
this.selected,
|
this.selected,
|
||||||
this.onRemove,
|
this.onRemove,
|
||||||
this.updateBadge,
|
this.updateBadge,
|
||||||
this.subtitleColor,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String dramaId;
|
final String dramaId;
|
||||||
final String title;
|
final String title;
|
||||||
final String posterUrl;
|
final String posterUrl;
|
||||||
final int viewCount;
|
final int viewCount;
|
||||||
final String subtitle;
|
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final double? progress;
|
final double? progress;
|
||||||
final bool editing;
|
final bool editing;
|
||||||
@@ -44,9 +41,6 @@ class FollowingGridCard extends StatelessWidget {
|
|||||||
/// 待后端在 Drama 增加更新状态字段后由收藏网格传入。
|
/// 待后端在 Drama 增加更新状态字段后由收藏网格传入。
|
||||||
final String? updateBadge;
|
final String? updateBadge;
|
||||||
|
|
||||||
/// 副标题颜色;更新中用强调红,完结用默认灰。
|
|
||||||
final Color? subtitleColor;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
@@ -165,7 +159,7 @@ class FollowingGridCard extends StatelessWidget {
|
|||||||
const SizedBox(height: AppDimens.cardCoverTitleGap),
|
const SizedBox(height: AppDimens.cardCoverTitleGap),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -175,17 +169,6 @@ class FollowingGridCard extends StatelessWidget {
|
|||||||
height: AppDimens.cardTitleLineHeight,
|
height: AppDimens.cardTitleLineHeight,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: AppDimens.followingSubtitleGap),
|
|
||||||
Text(
|
|
||||||
subtitle,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
color: subtitleColor ?? AppColors.textTertiary,
|
|
||||||
fontSize: AppDimens.followingCardSubtitleFontNew,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ const int _moreLimit = 12;
|
|||||||
const int _filmHoles = 8;
|
const int _filmHoles = 8;
|
||||||
const double _cardPadding = 8;
|
const double _cardPadding = 8;
|
||||||
const double _cardWidth = 124;
|
const double _cardWidth = 124;
|
||||||
const double _rowHeight = 204;
|
|
||||||
|
/// 横向卡片行高:封面 144 + 两行剧名 + 上映日期。
|
||||||
|
const double _rowHeight = 226;
|
||||||
const double _cardRadius = 12;
|
const double _cardRadius = 12;
|
||||||
const double _loadMoreThreshold = 200;
|
const double _loadMoreThreshold = 200;
|
||||||
|
|
||||||
@@ -173,9 +175,7 @@ class _NewReleasesPageState extends State<NewReleasesPage> {
|
|||||||
child: SizedBox(height: 14),
|
child: SizedBox(height: 14),
|
||||||
),
|
),
|
||||||
if (more.isNotEmpty) ...[
|
if (more.isNotEmpty) ...[
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(child: _moreHeader(l10n)),
|
||||||
child: _moreHeader(l10n),
|
|
||||||
),
|
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
child: SizedBox(height: 10),
|
child: SizedBox(height: 10),
|
||||||
),
|
),
|
||||||
@@ -467,7 +467,7 @@ class _NewReleasesPageState extends State<NewReleasesPage> {
|
|||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
drama.title,
|
drama.title,
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.onSurface,
|
color: AppColors.onSurface,
|
||||||
|
|||||||
@@ -464,7 +464,7 @@ class _RankingRow extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
drama.title,
|
drama.title,
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.textPrimary,
|
color: AppColors.textPrimary,
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ const double _cardCoverHeight = 157;
|
|||||||
const double _cardGap = 9;
|
const double _cardGap = 9;
|
||||||
const double _cardRadius = 12;
|
const double _cardRadius = 12;
|
||||||
|
|
||||||
|
/// 海报卡封面以下的高度:上间距 8 + 两行剧名 + 2 + 集数行 + 余量。
|
||||||
|
///
|
||||||
|
/// 横向列表和网格都要给一个有限的卡片高度,这里是唯一来源,
|
||||||
|
/// 两行剧名撑高时只改这一处,不会出现某个入口高度不够而溢出。
|
||||||
|
const double homePosterCardBodyExtent = 62;
|
||||||
|
|
||||||
/// 上新横滑卡板块。无板块标题,卡片左上角带「上新」角标。
|
/// 上新横滑卡板块。无板块标题,卡片左上角带「上新」角标。
|
||||||
/// 内层横向 ListView 会自行识别横向手势,不与外层纵向滚动冲突。
|
/// 内层横向 ListView 会自行识别横向手势,不与外层纵向滚动冲突。
|
||||||
class HomeNewArrivalRow extends StatelessWidget {
|
class HomeNewArrivalRow extends StatelessWidget {
|
||||||
@@ -32,8 +38,7 @@ class HomeNewArrivalRow extends StatelessWidget {
|
|||||||
if (dramas.isEmpty) return const SizedBox.shrink();
|
if (dramas.isEmpty) return const SizedBox.shrink();
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
key: const Key('home-new-arrival-row'),
|
key: const Key('home-new-arrival-row'),
|
||||||
height:
|
height: _cardCoverHeight + homePosterCardBodyExtent,
|
||||||
_cardCoverHeight + 8 + 20 + 2 + 16, // 封面 + 剧名行 + 集数行 + 余量
|
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: _pageSide),
|
padding: const EdgeInsets.symmetric(horizontal: _pageSide),
|
||||||
@@ -130,7 +135,7 @@ class HomePosterCard extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
drama.localizedTitle(lang),
|
drama.localizedTitle(lang),
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.textPrimary,
|
color: AppColors.textPrimary,
|
||||||
@@ -192,7 +197,11 @@ class HomeEditorPickBanner extends StatelessWidget {
|
|||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
begin: Alignment.centerLeft,
|
begin: Alignment.centerLeft,
|
||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [Color(0xE6000000), Color(0x4D000000), Color(0x1A000000)],
|
colors: [
|
||||||
|
Color(0xE6000000),
|
||||||
|
Color(0x4D000000),
|
||||||
|
Color(0x1A000000),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in new issue
Block a user