Kototoro UI 改进方案
文档版本
- 创建日期:2026-03-18
- 最后更新:2026-03-19
- 状态:进行中(部分方案已落地)
目录
1. 主页(Dashboard)设计
1.1 设计目标
- 提供统一的信息聚合中心
- 快速访问常用功能
- 支持多种内容类型和来源的展示
- 降低导航复杂度
1.2 页面结构
┌─────────────────────────────────────┐ │ 🔍 搜索框 │ ← AppBar ├─────────────────────────────────────┤ │ 📊 同步状态卡片 │ │ ┌─────────────────────────────────┐│ │ │ WebDAV 同步 ││ │ │ ✓ 已同步 · 2分钟前 ││ │ │ [立即同步] ││ │ └─────────────────────────────────┘│ │ │ │ 📖 历史 (8) [筛选][更多] │ │ ┌─────┬─────┬─────┬─────┬─────┐ │ │ │ │ │ │ │ │ → │ ← 横向滚动 │ └─────┴─────┴─────┴─────┴─────┘ │ │ │ │ ⭐ 更新 (8) [筛选][更多] │ │ ┌─────┬─────┬─────┬─────┬─────┐ │ │ │ │ │ │ │ │ → │ ← 横向滚动 │ └─────┴─────┴─────┴─────┴─────┘ │ │ │ │ 🔔 推荐 (8) [筛选][更多] │ │ ┌─────┬─────┬─────┬─────┬─────┐ │ │ │ │ │ │ │ │ → │ ← 横向滚动 │ └─────┴─────┴─────┴─────┴─────┘ │ │ │ │ 🔌 源管理 [管理>]│ │ ┌─────────────────────────────────┐│ │ │ 已启用: 12 个源 ││ │ │ 内置(3) · Mihon(4) · Legado(5) ││ │ └─────────────────────────────────┘│ └─────────────────────────────────────┘
1.3 卡片设计
1.3.1 同步状态卡片
- 显示 WebDAV/云同步状态
- 最后同步时间
- 快速同步按钮
- 同步冲突提示
1.3.2 历史卡片
- 横向滚动封面列表
- 默认预览 8 个最近阅读记录
- 封面 + 标题 + 阅读进度
- 点击直接继续阅读
- 过滤器右侧提供紧凑型"更多"按钮
- "更多"按钮跳转到完整历史页面
1.3.3 更新卡片
- 横向滚动封面列表
- 默认预览 8 个最近更新作品
- 封面 + 更新信息
- 点击跳转到详情页
- 过滤器右侧提供紧凑型"更多"按钮
- "更多"按钮跳转到完整更新页面
1.3.4 订阅动态卡片
- 显示订阅源的更新摘要
- 源名称 + 更新数量
- 点击查看该源的更新列表
- "更多"按钮跳转到完整订阅页面
1.3.5 源管理卡片
- 显示已启用源的统计
- 按源类型分组显示数量
- 快速启用/禁用常用源
- "管理"按钮跳转到源设置
1.4 技术实现
1.4.1 数据模型
data class DashboardState(
val syncStatus: SyncStatus,
val recentHistory: List<HistoryItem>,
val favouriteUpdates: List<UpdateItem>,
val feedSummary: List<FeedSummary>,
val sourcesStats: SourcesStats
)
data class SyncStatus(
val isEnabled: Boolean,
val lastSyncTime: Long?,
val isSyncing: Boolean,
val hasConflicts: Boolean
)
data class UpdateItem(
val content: Content,
val newChaptersCount: Int,
val latestChapter: String
)
data class FeedSummary(
val source: ContentSource,
val updatesCount: Int
)
data class SourcesStats(
val totalEnabled: Int,
val byType: Map<SourceType, Int>
)
1.4.2 ViewModel
@HiltViewModel
class HomeViewModel @Inject constructor(
private val historyRepository: HistoryRepository,
private val favouritesRepository: FavouritesRepository,
private val feedRepository: FeedRepository,
private val sourcesRepository: ContentSourcesRepository,
private val syncCoordinator: BackupStartupCoordinator
) : ViewModel() {
val dashboardState: StateFlow<DashboardState> = combine(
historyRepository.observeRecentHistory(limit = 10),
favouritesRepository.observeUpdates(),
feedRepository.observeSummary(),
sourcesRepository.observeStats(),
syncCoordinator.observeSyncStatus()
) { history, updates, feed, sources, sync ->
DashboardState(
syncStatus = sync,
recentHistory = history,
favouriteUpdates = updates,
feedSummary = feed,
sourcesStats = sources
)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = DashboardState.Empty
)
}
1.4.3 Fragment
@AndroidEntryPoint
class HomeFragment : BaseFragment<FragmentHomeBinding>() {
private val viewModel by viewModels<HomeViewModel>()
override fun onViewBindingCreated(binding: FragmentHomeBinding, savedInstanceState: Bundle?) {
super.onViewBindingCreated(binding, savedInstanceState)
val adapter = HomeDashboardAdapter(
onHistoryClick = { router.openReader(it) },
onUpdateClick = { router.openDetails(it) },
onFeedClick = { router.openFeed(it) },
onSyncClick = { viewModel.triggerSync() },
onManageSourcesClick = { router.openSourceSettings() }
)
binding.recyclerView.adapter = adapter
viewModel.dashboardState.observe(viewLifecycleOwner) { state ->
adapter.submitList(state.toCardList())
}
}
}
1.5 卡片配置
- 用户可以自定义显示哪些卡片
- 可以调整卡片顺序
- 可以设置每个卡片显示的数量
---
2. 导航栏优化
2.1 当前问题
- 导航项过多(历史、收藏、浏览、订阅 + 可选项)
- 最多支持 6 个导航项,容易拥挤
- 新增主页后需要重新规划
2.2 推荐方案:精简导航栏
2.2.1 默认导航栏(5项)
┌─────────────────────────────────────┐
│ [🏠] [📖] [⭐] [🔍] [🔔] │
│ 主页 历史 收藏 浏览 订阅 │
└─────────────────────────────────────┘
- 主页 (Home):新增,作为默认启动页
- 历史 (History):高频使用
- 收藏 (Favourites):高频使用
- 浏览 (Browse/Explore):发现新内容
- 订阅 (Feed):追踪更新
2.2.2 其他功能访问方式
- 本地 (Local):通过主页的源管理卡片或设置访问
- 建议 (Suggestions):通过主页或浏览页面访问
- 书签 (Bookmarks):通过详情页或阅读器访问
- 更新 (Updates):合并到订阅页面
- 发现 (Discover):新增独立页面(见第4节)
2.2.3 可配置导航栏
保留现有的 settings.mainNavItems 配置功能:
- 用户可以从 8-10 个可选项中选择
- 最多显示 5-6 个导航项
- 支持拖拽排序
- 主页建议默认开启但可选
2.3 导航栏实现
2.3.1 NavItem 枚举扩展
enum class NavItem(
@IdRes val id: Int,
@StringRes val title: Int,
@DrawableRes val icon: Int,
val isDefault: Boolean = false
) {
HOME(R.id.nav_home, R.string.home, R.drawable.ic_home, isDefault = true),
HISTORY(R.id.nav_history, R.string.history, R.drawable.ic_history, isDefault = true),
FAVORITES(R.id.nav_favorites, R.string.favourites, R.drawable.ic_favourite, isDefault = true),
EXPLORE(R.id.nav_explore, R.string.explore, R.drawable.ic_explore, isDefault = true),
FEED(R.id.nav_feed, R.string.feed, R.drawable.ic_feed, isDefault = true),
DISCOVER(R.id.nav_discover, R.string.discover, R.drawable.ic_discover, isDefault = false),
LOCAL(R.id.nav_local, R.string.local_storage, R.drawable.ic_storage, isDefault = false),
SUGGESTIONS(R.id.nav_suggestions, R.string.suggestions, R.drawable.ic_suggestions, isDefault = false),
BOOKMARKS(R.id.nav_bookmarks, R.string.bookmarks, R.drawable.ic_bookmark, isDefault = false),
UPDATED(R.id.nav_updated, R.string.updated, R.drawable.ic_updated, isDefault = false);
companion object {
fun getDefaultItems(): List<NavItem> = entries.filter { it.isDefault }
}
}
2.3.2 MainNavigationDelegate 更新
private fun onNavigationItemSelected(@IdRes itemId: Int): Boolean {
val newFragment = when (itemId) {
R.id.nav_home -> HomeFragment::class.java
R.id.nav_history -> HistoryListFragment::class.java
R.id.nav_favorites -> FavouritesContainerFragment::class.java
R.id.nav_explore -> ExploreFragment::class.java
R.id.nav_feed -> FeedFragment::class.java
R.id.nav_discover -> DiscoverFragment::class.java // 新增
R.id.nav_local -> LocalListFragment::class.java
R.id.nav_suggestions -> SuggestionsFragment::class.java
R.id.nav_bookmarks -> AllBookmarksFragment::class.java
R.id.nav_updated -> UpdatesFragment::class.java
else -> return false
}
// ...
}
2.4 启动页设置
- 默认启动页:主页
- 用户可以在设置中修改默认启动页
- 记住上次退出时的页面(可选)
---
3. 过滤器界面改进
3.1 当前问题
- 两组 Chip(内容类型 + 源类型)在同一行,容易溢出
- 使用 HorizontalScrollView,但体验不够直观
- 搜索框在 AppBar 中,与过滤条分离
3.2 源类型说明
- 内容类型:漫画、小说、视频(媒体类型)
- 源类型:内置源、Mihon源、Aniyomi源、Legado源、TVBox源(插件类型)
3.3 兼容性矩阵
内置源 Mihon源 Aniyomi源 Legado源 TVBox源
漫画 ✓ ✓ ✗ ✓ ✗
小说 ✓ ✗ ✗ ✓ ✗
视频 ✓ ✗ ✓ ✗ ✓
3.4 推荐方案:两行紧凑图标布局
3.4.1 界面设计
┌─────────────────────────────────────┐
│ 🔍 搜索框 │ ← AppBar
├─────────────────────────────────────┤
│ [📚] [📖] [🎬] │ ← 内容类型(紧凑图标)
│ [内置] [Mihon] [Aniyomi] [Legado] [TV] │ ← 源类型(紧凑图标)
├─────────────────────────────────────┤
│ [分类标签页...] │ ← TabLayout
└─────────────────────────────────────┘
3.4.2 设计要点
1. 使用纯图标 Chip(无文字,只有图标 + Tooltip)
2. 两行固定布局,不使用 HorizontalScrollView
3. 自动禁用不兼容的选项(已实现)
4. 每个 Chip 宽度约 40-48dp,5个源类型总宽度约 240dp,不会溢出
3.4.3 布局实现
<LinearLayout
android:id="@+id/filterChipsContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="@dimen/list_spacing_normal"
android:paddingVertical="8dp">
<!-- 内容类型行 -->
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroupContentType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chipSpacingHorizontal="8dp"
app:singleLine="true"
app:singleSelection="true"
app:selectionRequired="false" />
<!-- 源类型行 -->
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroupSourceTag"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:chipSpacingHorizontal="8dp"
app:singleLine="true"
app:singleSelection="false"
app:selectionRequired="false" />
</LinearLayout>
3.4.4 Chip 样式优化
private fun createCompactChip(
text: String,
@DrawableRes iconRes: Int,
colors: ChipColors,
density: Float,
): Chip {
return Chip(requireContext()).apply {
id = View.generateViewId()
this.text = "" // 关键:不显示文字
contentDescription = text
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
tooltipText = text // 长按显示完整名称
}
isCheckable = true
isChipIconVisible = true
setChipIconResource(iconRes)
chipIconSize = 24f * density // 稍大的图标
// 更紧凑的尺寸
chipMinHeight = 40 * density
minHeight = 0
chipStartPadding = 12 * density // 左右各12dp
chipEndPadding = 12 * density
textStartPadding = 0f
textEndPadding = 0f
setEnsureMinTouchTargetSize(true) // 保持48dp触摸区域
chipStrokeWidth = 0f
chipBackgroundColor = colors.bg
setTextColor(colors.text)
}
}
3.5 替代方案
3.5.1 方案 B:底部菜单 + 指示器
┌─────────────────────────────────────┐
│ 🔍 搜索框 [🎯 过滤器] │ ← AppBar
├─────────────────────────────────────┤
│ 当前过滤: 漫画 · 内置 · Mihon × │ ← 过滤指示器
├─────────────────────────────────────┤
│ [分类标签页...] │
└─────────────────────────────────────┘
点击"过滤器"按钮弹出 BottomSheet,包含所有过滤选项。
优点:
- 界面最简洁,不占用垂直空间
- 支持更复杂的过滤逻辑
- 当前过滤状态清晰可见
缺点:
- 需要额外点击才能修改过滤
3.5.2 方案 C:智能折叠
默认状态下隐藏过滤条,点击按钮展开,已过滤时显示过滤指示器。
3.6 图标资源需求
需要为以下源类型设计图标:
- ic_source_builtin.xml - 内置源
- ic_source_mihon.xml - Mihon 源
- ic_source_aniyomi.xml - Aniyomi 源
- ic_source_legado.xml - Legado 源
- ic_source_tvbox.xml - TVBox 源
---
4. 追踪站点集成
4.1 站点无关产品层
4.1.1 功能概述
集成 Bangumi 等二次元追踪网站,提供:
- 权威的内容库和元数据
- 排行榜和推荐
- 跨源内容聚合
- 阅读进度同步
- 当前进度:`Discover`、追踪站点详情页、详情页追踪增强与本地缓存骨架已落地,后续继续补同步增强与更完整的多站点交互
4.1.2 新增"发现"页面(Discover)
4.1.2.1 页面结构
┌─────────────────────────────────────┐
│ 🔍 搜索发现内容 │
├─────────────────────────────────────┤
│ [📚 漫画] [📖 小说] [🎬 动画] │ ← 内容类型切换
├─────────────────────────────────────┤
│ 📊 排行榜 │
│ ┌─────┬─────┬─────┬─────┐ │
│ │ 1 │ 2 │ 3 │ 4 │ → │ ← 横向滚动
│ └─────┴─────┴─────┴─────┘ │
│ │
│ 🔥 本季新番 │
│ ┌─────┬─────┬─────┬─────┐ │
│ │ │ │ │ │ → │
│ └─────┴─────┴─────┴─────┘ │
│ │
│ 🏷️ 按标签浏览 │
│ [恋爱] [冒险] [科幻] [更多...] │
│ │
│ 📅 按年份/季度 │
│ [2026] [2025] [2024]... │
└─────────────────────────────────────┘
4.1.2.2 功能模块
1. 排行榜:显示追踪站点的热门作品(默认 Bangumi)
2. 本季新番:当季新作品
3. 标签浏览:按类型、标签筛选
4. 年份/季度:按时间筛选
5. 搜索:搜索追踪站点数据库(默认 Bangumi,当前已落地 MVP)
4.1.3 追踪站点详情页设计
当前实现已落地最小详情页容器,可展示远端详情、已绑定状态、本地入口、绑定/管理入口与站外打开入口。
4.1.3.1 页面结构
┌─────────────────────────────────────┐
│ ← 返回 │
│ │
│ [封面图] 作品名称 │
│ ⭐ 8.5 (站点评分) │
│ 📅 2024年1月 │
│ 🏷️ 恋爱 · 校园 │
│ │
│ [❤️ 想看] [📖 在看] [✓ 看过] │ ← 站点状态同步
│ │
├─────────────────────────────────────┤
│ 📚 可用来源 (3) │ ← 核心功能
│ ┌─────────────────────────────────┐│
│ │ ✓ 源1 (内置) - 已匹配 ││
│ │ 12话 · 更新至第10话 ││
│ │ [📖 开始阅读] [❤️ 加入收藏] ││
│ ├─────────────────────────────────┤│
│ │ ✓ 源2 (Mihon) - 已匹配 ││
│ │ 12话 · 更新至第12话 (完结) ││
│ │ [📖 开始阅读] ││
│ ├─────────────────────────────────┤│
│ │ ? 未找到匹配 ││
│ │ [🔍 手动搜索] [➕ 添加源] ││
│ └─────────────────────────────────┘│
│ │
├─────────────────────────────────────┤
│ 📝 简介 │
│ 这是一部关于... │
│ │
│ 💬 站点评论 (123) │
│ [查看更多评论] │
│ │
│ 🔗 相关作品 │
│ [续集] [前传] [同系列] │
└─────────────────────────────────────┘
4.1.3.2 核心功能:自动源匹配
- 自动搜索所有已启用的源
- 使用多维度匹配算法(标题、年份、作者)
- 显示匹配置信度
- 支持手动搜索和关联
4.1.4 现有详情页增强
4.1.4.1 添加追踪信息卡片
当前实现仍复用既有 `scrobbling` 区块作为详情页入口,不再单独保留平行卡片。
在现有的内容详情页(DetailsActivity)中添加:
┌─────────────────────────────────────┐
│ [封面] 作品标题 │
│ 来源:某个源 │
│ │
├─────────────────────────────────────┤
│ 🔗 追踪信息 │
│ ┌─────────────────────────────────┐│
│ │ 追踪站点 ││
│ │ ⭐ 8.5 · #123 ││
│ │ [❤️ 想看] [📖 在看] [✓ 看过] ││
│ │ [查看详情] ││
│ └─────────────────────────────────┘│
│ │
│ 📖 章节列表 │
│ ... │
└─────────────────────────────────────┘
4.1.4.2 自动关联功能
- 打开详情页时自动搜索默认追踪站点
- 显示匹配结果和置信度
- 用户可以确认或手动选择
- 关联后保存到数据库
- 当前实现已支持自动建议、已关联/推荐动作菜单与手动确认落表
4.2 Bangumi 默认实现层
4.2.1 数据模型
说明:
- 产品层统一面向站点无关概念,例如 `TrackingSiteItem`、`TrackingSiteState`、`TrackingSiteLink`
- `BangumiItem`、`BangumiTrackingEntity`、`BangumiSourceLinkEntity` 只是默认实现层的具体命名
- 后续如接入 AniList / MAL,应保持通用接口不变,仅新增对应站点的实现模型与映射层
- 当前进度:`TrackingSiteItem` / `TrackingSiteItemDetails` / `TrackingSiteLink` 已落地,`TrackingSiteState` 仍预留给后续同步增强
4.2.1.1 Bangumi 数据
推荐的通用抽象命名如下:
data class TrackingSiteItem(
val site: TrackingSite,
val remoteId: String,
val title: String,
val altTitles: List<String>,
val type: TrackingContentType,
val rating: Float?,
val rank: Int?,
val summary: String?,
val tags: List<String>,
val year: Int?,
val authors: List<String>,
val coverUrl: String?,
val totalEpisodes: Int?,
val publishDate: String?
)
data class TrackingSiteState(
val site: TrackingSite,
val remoteId: String,
val status: TrackingStatus,
val matchedSources: List<MatchedSource>,
val lastSyncTime: Long,
val currentEpisode: Int?,
val score: Int?
)
data class TrackingSiteLink(
val site: TrackingSite,
val remoteId: String,
val contentId: Long,
val sourceName: String,
val confidence: Float,
val isManual: Boolean,
val createdAt: Long
)
其中,Bangumi 默认实现负责把 `BangumiItem` / `BangumiTrackingEntity` / `BangumiSourceLinkEntity`
映射到这些通用模型,而不是让上层 UI 或交互直接依赖 Bangumi-specific 类型。
data class BangumiItem(
val id: Long,
val name: String,
val nameCn: String,
val nameJp: String,
val type: BangumiType, // 书籍、动画、游戏等
val rating: Float,
val rank: Int,
val summary: String,
val tags: List<String>,
val year: Int?,
val authors: List<String>,
val coverUrl: String,
val totalEpisodes: Int?,
val airDate: String?
)
enum class BangumiType {
BOOK, // 书籍(漫画、小说)
ANIME, // 动画
MUSIC, // 音乐
GAME, // 游戏
REAL // 三次元
}
4.2.1.2 匹配结果
data class MatchedSource(
val source: ContentSource,
val content: Content,
val confidence: Float, // 0.0 - 1.0
val isManuallyLinked: Boolean = false
)
4.2.1.3 追踪状态
data class TrackingState(
val bangumiId: Long,
val status: TrackingStatus,
val matchedSources: List<MatchedSource>,
val lastSyncTime: Long,
val currentEpisode: Int?,
val score: Int? // 用户评分 1-10
)
enum class TrackingStatus {
WISH, // 想看
WATCHING, // 在看
COMPLETED, // 看过
ON_HOLD, // 搁置
DROPPED // 弃坑
}
4.2.2 数据库设计
4.2.2.1 Bangumi 条目表
@Entity(tableName = "bangumi_items")
data class BangumiItemEntity(
@PrimaryKey val id: Long,
val name: String,
val nameCn: String,
val nameJp: String,
val type: String,
val rating: Float,
val rank: Int,
val summary: String,
val tags: String, // JSON array
val year: Int?,
val authors: String, // JSON array
val coverUrl: String,
val totalEpisodes: Int?,
val airDate: String?,
val cachedAt: Long
)
4.2.2.2 追踪状态表
@Entity(
tableName = "bangumi_tracking",
foreignKeys = [
ForeignKey(
entity = BangumiItemEntity::class,
parentColumns = ["id"],
childColumns = ["bangumiId"],
onDelete = ForeignKey.CASCADE
)
]
)
data class BangumiTrackingEntity(
@PrimaryKey val bangumiId: Long,
val status: String,
val currentEpisode: Int?,
val score: Int?,
val lastSyncTime: Long
)
4.2.2.3 源关联表
@Entity(
tableName = "bangumi_source_links",
foreignKeys = [
ForeignKey(
entity = BangumiItemEntity::class,
parentColumns = ["id"],
childColumns = ["bangumiId"],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = MangaEntity::class,
parentColumns = ["manga_id"],
childColumns = ["contentId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [
Index("bangumiId"),
Index("contentId")
]
)
data class BangumiSourceLinkEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val bangumiId: Long,
val contentId: Long,
val sourceName: String,
val confidence: Float,
val isManual: Boolean,
val createdAt: Long
)
4.2.3 自动匹配算法
4.2.3.1 匹配流程
class ContentMatcher @Inject constructor(
private val sourcesRepository: ContentSourcesRepository,
private val searchRepository: SearchRepository
) {
suspend fun findSources(
bangumiItem: BangumiItem,
enabledSources: List<ContentSource>
): List<MatchedSource> {
// 1. 准备搜索关键词(多语言标题)
val titles = listOf(
bangumiItem.name,
bangumiItem.nameCn,
bangumiItem.nameJp
).filter { it.isNotBlank() }
// 2. 并行搜索所有源
val results = enabledSources.map { source ->
async(Dispatchers.IO) {
searchInSource(source, titles)
}
## 6. Implementation Priority & Sequence
## 目标
定义 `ui_improvement.md` 的推荐实施顺序,明确:
- 哪些任务必须先做
- 哪些任务可以并行
- 哪些任务属于增强项,不应阻塞主线
- 如何避免把追踪站点能力写死为 Bangumi 单站点实现
---
## 当前状态概览(2026-03-19)
### 已完成或已实质完成的阶段
- `P0` 信息架构稳定:已完成
- 主页导航入口已接入
- 默认启动链路已切到主页
- 导航配置页已兼容 `Home`
- `P1` 主页最小可用版本:已实质完成
- 主页 Dashboard 首版已可用
- 真实数据聚合已接入
- `P2` Explore 过滤器体验优化:已实质完成
- 两行固定布局已落地
- 横向滚动已移除
- `JavaScript` 源类型标签与图标已补齐
- `P3` 追踪站点抽象层:已继续推进
- discovery / matcher / preferred-site 抽象已落地
- 详情页增强方案已收敛为复用既有 `scrobbling` 入口,并补齐空态引导
### 尚未开始的阶段
- `P4` Discover 一期
- `P5` 自动关联与同步增强
- `P6` 主页配置化增强
---
## 总体优先级
### P0:信息架构稳定
- 主页导航入口
- 默认启动页策略
- 导航配置兼容 `Home`
状态:已完成
### P1:主页最小可用版本
- 主页容器与卡片列表
- 主页状态聚合
- 继续阅读、最近阅读、Library、最近更新、源概览、同步状态
状态:已实质完成
### P2:Explore 过滤器体验优化
- 两行固定布局
- 去除横向滚动
- 补齐源类型图标资源
状态:已实质完成
### P3:追踪站点抽象与详情页增强
- 梳理现有 `scrobbling/common`
- 建立站点无关 discovery 抽象
- 详情页追踪信息卡增强
状态:抽象层已落地,详情页增强已复用既有 scrobbling 区块并补齐空态与首选站点优先展示
### P4:发现页 Discover 一期
- 页面结构
- 站点切换
- 默认 Bangumi 实现
- 搜索、热门列表、详情跳转
状态:进行中,已落地导航入口、最小站点切换、热门列表、搜索与站内详情跳转
### P4.5:追踪站点详情页一期
- 远端详情展示
- 已绑定状态与本地入口
- 绑定/管理入口
- 站外打开入口
- 后续接入本地入口与绑定能力
状态:进行中,已落地最小详情页容器、远端详情展示、已绑定状态、本地入口与绑定/管理入口
### P5:自动关联与同步增强
- 自动匹配
- 手动纠正
- 状态、评分、进度同步增强
状态:未开始
### P6:配置化增强
- 主页卡片显隐
- 主页卡片数量
- 主页卡片顺序
状态:未开始
---
## 推荐阶段划分
### 阶段 1:入口稳定
- Issue 1:新增主页导航入口
- Issue 4:导航配置页兼容 Home
- Issue 5:主页默认启动页策略
状态:已完成
### 阶段 2:主页 MVP
- Issue 2:主页模块 MVP 落地
- Issue 3:主页数据聚合与状态模型收敛
状态:已实质完成
### 阶段 3:Explore 过滤器改造
- Issue 6:Explore 过滤器改为两行固定布局
- Issue 7:补齐 Explore 源类型图标资源
状态:已实质完成
### 阶段 4:追踪站点抽象层
- Issue 9:梳理并复用现有追踪站点基础能力
- Issue 10:预留追踪站点切换接口
- Issue 12:追踪站点本地模型与缓存表设计
状态:前两项已完成基础骨架,Issue 12 已进入读写接入阶段
### 阶段 5:详情页追踪增强
- Issue 11:详情页追踪信息卡一期
状态:进行中(方案已收敛到复用既有入口,空态引导已落地)
### 阶段 6:Discover 一期
- Issue 14:发现页 Discover 一期
- Issue 15:追踪站点详情页一期
状态:进行中(Discover MVP 与追踪站点详情页一期均已进入可运行状态)
### 阶段 7:自动关联与同步增强
- Issue 13:追踪站点自动关联基础版
- Issue 16:追踪状态同步增强
状态:进行中(Issue 13 已进入 matcher、关联落表与推荐项动作菜单阶段)
### 阶段 8:主页配置化增强
- Issue 8:主页卡片配置能力
状态:未开始
---
## 推荐执行顺序
当前推荐顺序如下:
1. 基于既有 scrobbling 入口完善详情页追踪增强
2. 发现页 Discover 一期
3. 追踪站点详情页一期
4. 追踪站点本地模型与缓存表设计
5. 自动关联基础版
6. 追踪状态同步增强
7. 主页卡片配置能力
原因:
- 主页与 Explore 主线已经收敛到可交付状态
- discovery 抽象已落地,下一步应尽快接到真实 UI 入口
- 详情页追踪卡比 Discover 更贴近当前主阅读链路,价值更直接
- 自动关联和同步增强复杂度最高,应排在展示链路稳定之后
---
## 并行开发建议
### 可并行组合 A
- 分支 1:详情页追踪信息卡
- 分支 2:追踪站点本地模型与缓存表
原因:
- 一个偏 UI 聚合,一个偏数据层
- 改动边界相对独立
### 可并行组合 B
- 分支 3:Discover 一期
- 分支 4:主页配置化增强
原因:
- 两者业务边界独立
- 主页配置化不阻塞追踪站点主线
---
## 推荐分支顺序
1. `feature/details-tracking-card`
2. `feature/discover-page-v1`
3. `feature/tracking-site-cache-model`
4. `feature/tracking-auto-match`
5. `feature/tracking-sync-enhancement`
6. `feature/home-dashboard-config`
---
## 判断原则
- KISS:先把现有抽象接到真实页面,不先做通用平台
- YAGNI:未进入当前排期的评论聚合、跨站统一排序先不做
- DRY:继续复用 `scrobbling/common` 与现有详情页能力
- SOLID:UI 仅依赖站点无关接口,不直接依赖 `BangumiRepository`
## 7. Tasks & Issues
## 目标
将 `ui_improvement.md` 中的设计方案拆分为可执行任务,并明确当前已落地进度、未完成部分和下一步顺序。
约束如下:
- 先稳定主页与主导航信息架构
- 再完成 `Explore` 过滤器体验优化
- 追踪站点能力必须基于站点无关抽象扩展,不能把 Bangumi 写死为唯一实现
- 优先交付最小可运行闭环,避免过度设计
---
## 当前实现进度(2026-03-19)
### 已完成或已实质落地
- `Issue 1` 已完成:`Home` 已接入主导航,默认导航顺序已调整,并兼容现有导航配置入口。
- `Issue 2` 已实质完成:主页已从占位页推进为可用的 Dashboard 首版。
- `Issue 3` 已实质完成:主页状态已接入真实数据聚合,覆盖阅读历史、收藏、分类、更新、源数量、源分布、首选追踪站点与同步状态。
- `Issue 4` 已完成:导航配置页已兼容 `Home`。
- `Issue 5` 已完成:主页已作为默认导航首项接入启动链路。
- `Issue 6` 已完成:`Explore` 过滤器已改为两行固定布局,移除了横向滚动依赖。
- `Issue 7` 已实质完成:源类型图标体系已补齐到当前实现范围,额外新增了 `JavaScript` 源类型与图标,并打通到 `Explore`、搜索等共享标签模型。
- 追踪站点切换预留接口已落地:已新增站点无关的 discovery / matcher / preferred-site 抽象,以及默认实现骨架与 `AppSettings` 持久化入口。
- tracking/discovery 术语已开始对齐:发现列表模型已收敛到 `TrackingSiteItem`,并明确 `State` / `Link` 属于后续同步与持久化层。
- tracking/discovery 术语继续收敛:详情模型已对齐为 `TrackingSiteItemDetails`,与 `TrackingSiteItem` 命名保持同层级一致。
- `Issue 11` 已推进:详情页原有 `scrobbling` 区块已补齐基础空态、未关联引导与首选站点优先展示,后续增强继续基于现有追踪入口合并演进,不再新增平行卡片。
- `Issue 14` 已推进:`Discover` 最小骨架已接入主导航,已支持基于首选追踪站点的最小站点切换、热门列表、站内搜索与站内详情跳转。
- `Issue 12` 已推进:已落地追踪站点本地缓存骨架,并接入 `Discover` 与详情页的缓存读写链路,后续再补状态表与更完整的同步能力。
- `Issue 15` 已推进:追踪站点详情页已落地最小容器,可展示远端详情、绑定/管理入口与站外打开入口,绑定状态与本地内容入口正统一到 `tracking_site_links` 链路。
### 当前主页首版包含内容
- 总览卡:最近阅读数量、未读更新数量、首选追踪站点、同步状态
- 继续阅读卡:阅读入口与详情入口
- 历史卡:默认 8 个最近阅读封面,支持横向滑动
- Library 卡:收藏总数、分类数、进入收藏页入口
- 更新卡:默认 8 个最近更新封面,支持横向滑动
- 源概览卡:启用源数量、来源分布、进入源管理入口
- 快捷入口卡:`Reader settings` 与 `Settings`
### 已落地代码入口
- 主页与导航:
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/core/prefs/NavItem.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/core/prefs/AppSettings.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/main/ui/MainNavigationDelegate.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/settings/nav/NavConfigViewModel.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/home/ui/HomeFragment.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/home/ui/HomeViewModel.kt`
- `app/src/main/res/layout/fragment_home.xml`
- Explore:
- `app/src/main/res/layout/fragment_explore.xml`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/explore/ui/model/SourceTag.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/explore/ui/model/BrowseGroupTab.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/search/domain/SearchSourceTypes.kt`
- `app/src/main/res/drawable/ic_source_js.xml`
- 追踪站点 discovery 抽象:
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/domain/TrackingSiteDiscoveryService.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/domain/TrackingSiteMatcher.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/domain/PreferredTrackingSiteProvider.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/domain/TrackingDiscoveryModels.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/data/DefaultTrackingSiteDiscoveryService.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/data/AppSettingsPreferredTrackingSiteProvider.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/tracking/discovery/TrackingDiscoveryModule.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/discover/ui/DiscoverFragment.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/discover/ui/DiscoverViewModel.kt`
- `app/src/main/kotlin/org/Kototoro-app/Kototoro/discover/ui/DiscoverAdapter.kt`
- `app/src/main/res/layout/item_discover_site.xml`
### 尚未开始或尚未进入可交付状态
- `Issue 8`:主页卡片配置化尚未开始
- 详情页追踪增强尚未覆盖自动关联与更完整的多站点交互
- `Discover` 页面一期已进入 MVP 阶段
- 自动关联、手动纠正与详情页消费 `tracking_site_links` 的最小闭环已进入收尾阶段,追踪状态增强同步尚未开始
- Bangumi 本地缓存表与跨站点详情模型已进入数据库骨架阶段,但尚未进入最终形态
---
## 里程碑
### M1:主页与导航稳定
- `Issue 1`
- `Issue 2`
- `Issue 3`
- `Issue 4`
- `Issue 5`
状态:已完成或已实质完成
### M2:Explore 过滤器优化
- `Issue 6`
- `Issue 7`
状态:已完成或已实质完成
### M3:追踪站点最小价值闭环
- `Issue 9`
- `Issue 10`
- `Issue 11`
状态:已完成抽象层骨架,详情页增强方案已收敛到复用既有 scrobbling 入口
### M4:追踪站点扩展能力
- `Issue 12`
- `Issue 13`
- `Issue 14`
- `Issue 15`
状态:已进入 Discover MVP 与站点详情页最小闭环阶段
### M5:主页增强
- `Issue 8`
状态:未开始
---
## Issue 列表
### Issue 1:新增主页导航入口
- 目标:在主导航中引入 `Home`,并作为默认信息聚合入口
- 工作量:S
- 状态:已完成
### Issue 2:主页模块 MVP 落地
- 目标:实现最小可用 Dashboard
- 工作量:M
- 状态:已实质完成
### Issue 3:主页数据聚合与状态模型收敛
- 目标:让主页基于真实数据流渲染
- 工作量:M
- 状态:已实质完成
### Issue 4:导航配置页兼容 Home
- 目标:让现有导航配置能力支持 `Home`
- 工作量:S
- 状态:已完成
### Issue 5:主页默认启动页策略
- 目标:把主页变成默认启动页
- 工作量:S
- 状态:已完成
### Issue 6:Explore 过滤器改为两行固定布局
- 目标:消除横向滚动,改成两行布局
- 工作量:M
- 状态:已完成
### Issue 7:补齐 Explore 源类型图标资源
- 目标:为过滤器提供统一图标,并补齐共享标签模型
- 工作量:S
- 状态:已实质完成
### Issue 8:主页卡片配置能力
- 目标:支持卡片显隐、数量和顺序配置
- 工作量:M
- 状态:未开始
### Issue 9:梳理并复用现有追踪站点基础能力
- 目标:明确现有 `scrobbling/common` 能力边界
- 工作量:S
- 状态:已完成基础梳理
### Issue 10:预留追踪站点切换接口
- 目标:站点发现与详情能力通过站点无关接口暴露
- 工作量:M
- 状态:已完成接口与默认实现骨架
### Issue 11:详情页追踪信息卡一期
- 目标:在现有详情页中显示站点无关追踪信息
- 工作量:M
- 状态:进行中(已复用既有 scrobbling 区块,并补齐空态引导、首选站点优先展示与推荐项动作菜单)
### Issue 12:追踪站点本地模型与缓存表设计
- 目标:为发现页和详情页提供本地可缓存模型
- 工作量:M
- 状态:进行中(已落地通用缓存表、链接表、DAO 与数据库迁移,并接入 `Discover`/详情页读写链路)
### Issue 13:追踪站点自动关联基础版
- 目标:实现本地内容与远端条目的最小可用匹配
- 工作量:L
- 状态:进行中(已落地 matcher、自动建议、已关联/推荐动作菜单与手动确认落表,详情页对 `tracking_site_links` 的消费链路正在补齐)
### Issue 14:发现页 Discover 一期
- 目标:实现站点切换、搜索、热门列表和详情跳转
- 工作量:M
- 状态:进行中(已落地导航入口、最小站点切换、热门列表、搜索与站内详情跳转)
### Issue 15:追踪站点详情页一期
- 目标:展示远端详情与本地入口
- 工作量:M
- 状态:进行中(已落地最小详情页容器、远端详情展示、绑定/管理入口与站外打开入口,绑定状态与本地内容入口正统一到 `tracking_site_links` 链路)
### Issue 16:追踪状态同步增强
- 目标:支持站点状态、评分、进度同步增强
- 工作量:M
- 状态:未开始
---
## 当前建议的下一步顺序
1. 基于 `tracking_site_links` 推进自动关联基础版
2. 在此基础上推进状态同步增强
3. 继续增强追踪站点详情页与本地详情页的双向联动
4. 最后做主页卡片配置化