状态:实施中,分页已接入文件与区域解码适配器,尚未完成真机验收。2026-09-26 对照仓库源码、Coil 3.6.3、 Telephoto 0.19.0 与本机 Komikku 校正。进度与尺寸修复已提交为
9f6f87872; 存储切片dea63568d接入有效性检查、原子发布及等待者安全的文件锁; 当前切片接入分页 File 请求、读取租约与在线文件字节预算。目标:分页缩放时按需读取原图细节;阅读与后续漫画下载共用同一份有效文件, 已有文件不重复获取,已保留的章节断网可读。 “清晰”以源图分辨率为上限,不承诺放大超过原图仍有新增细节; “复用”不等于不再解码,preview、瓦片和重开后的解码仍是正常工作。
MangaReaderScreen 的请求保留完整原始 URL 身份,共用显式解码尺寸。
分页预取、展示与背景提色携带 MangaImageFileOwner;CoverInterceptor 在首次解码前
经 BookHelp 获取原图并把请求改为 File,返回结果的 request.data 也是 File。
条漫也复用原图 File 获取链路,继续使用 AsyncImage 整页绘制。
条漫按窗口宽度与侧边留白解码;分页适应高度按高度解码,拉伸同时满足宽高,
原始尺寸保留原图,旋转适配保守覆盖交换后的窗口尺寸。CoverFetcher 的网络流或内存 Buffer 无法提供区域解码所需的文件模型。
分页现在绕过该路径,Telephoto 可从 File 的 DISK/MEMORY_CACHE 结果建立区域解码源。
MangaZoomableImageSource 保留其格式判断,并为实际瓦片源补上独立读取租约;
EInk 明确使用 Coil painter,避免未变换原图瓦片覆盖二值化预览。MemoryCacheService
会验证尺寸、采样状态和 precision;稳定目标减少布局引起的差异,但不提供缩放细节。MangaChapterPageLoader 目前只加载章节文本和图片 URL,未向阅读页提供缓存图片文件。BookHelp.getImage(book, src) 的路径是
externalFiles/book_cache/<bookFolderName>/images/<md5Encode16(src)>.<suffix>。
flowImages 与下载使用同一章节基地址解析图片地址,应该沿用完整解析后原始 src
(包含书源选项)作为身份,不能用带临时 token 的最终网络 URL 替代。isImageExist 仍只看 exists,保留旧 UI/队列的低成本提示语义,不是下载完成证明。
首个存储切片让 saveImage 在文件锁内检查文件格式/尺寸,字节与流写入都先写临时文件、
校验后原子替换;不再发布新坏图或降级为直接复制到可见目标。
历史文件目前只检查结构,不具备完整性/书源版本的持久有效记录。saveImage 的锁现在按实际书籍文件路径建立,引用数包括等待者,最后一个退出才移除。
当前是串行获取:成功后的等待者复用文件;首位取消时下一位接手获取。
尚未实现独立于任一订阅者的共享任务,也未接入阅读 Fetcher;不能宣称完整跨消费者去重已完成。clearInvalidCache 在应用启动及主页面清理时执行;clearComicCache 按阅读章节窗口删除图片。
现有规则不识别显式下载、活动阅读和瓦片解码中的文件。MangaSettings.autoOfflineCache 已存在,不要新增同名设置。当前主要控制章节预取,
不是图片已持久化或章节可离线的完成证明。Telephoto 0.19.0 的 Coil3ImageSource.kt 在成功结果为 BitmapImage 时,尝试:
result.diskCacheKey 打开 Coil DiskCache snapshot;dataSource == DISK || MEMORY_CACHE 时,把 结果请求的 data 映射为本地 URI,
构造文件/content URI 区域解码源;内存命中时还检查文件存在。之后还要通过 canBeSubSampled,否则回退普通 painter。拿不到源时会重试一次请求,
第二次关闭内存读取;自定义 Fetcher 不会因设置 diskCachePolicy 自动接上 Coil 磁盘缓存。
EngineInterceptor 只从文件型 ImageSource 提取 diskCacheKey,任意 Buffer 不会自动写入磁盘。
因此 ImageRequest.data = File(path) 配合默认 FileUriFetcher,可以自动走区域解码,
无需手写瓦片组件。这里复用的文件必须是完成书源解密但未应用灰度/EInk 等展示变换的原图。
来源:本机相应版本 sources.jar; Telephoto 0.19.0 Coil3ImageSource。
对照仓库 D:/Project/komikku 的下列实际调用链(只读参考,不修改该工程):
HttpPageLoader.internalLoadPage:优先查 ChapterCache,miss 才请求网络;
putImageToCache 完成后才设置 page.stream 与 Ready。加载顺序可借鉴:完整文件在先,渲染在后。HttpPageLoader 的 PriorityBlockingQueue:当前页/重试优先于普通预取,线程数有限。
可借鉴调度语义,不照搬独立的 readerThreads 设置与全局协程管理。ChapterCache:保存章节 page list 和原图,DiskLruCache editor commit 后才发布。
在线缓存具有明确字节容量,支持重开、识别已淘汰图片并重新排队。Downloader.getOrDownloadImage:已有下载优先,否则使用 ChapterCache 字节,最后才联网。
copyImageFromCache 把缓存复制到下载目录并删缓存文件;因此这是获取复用,不是同一文件存储,
也不能把“使用了缓存”当作无复制、无额外磁盘占用的证明。ReaderPageImageView:静态图使用 SubsamplingScaleImageView,动画图单独渲染,
设置 onReady/onImageLoadError 再更新阅读器状态。可参考就绪与解码失败的阶段划分。结论:plan 的文件优先/区域解码方向与成熟阅读器一致;“阅读与下载永远共用同一份文件” 是本项目自己的增强目标,Komikku 没有替我们证明它。不能照搬其在线 LRU 清理来删除保留下载, 也不在本项目引入 SSIV、Voyager、SQLDelight 或其 source extension 架构。
所有分页阅读都先取得可用于随机读取的文件,再交给 ZoomableAsyncImage。
自动离线开关不控制是否生成解码文件,只控制章节预取与长期保留。
关闭开关仍应清晰缩放,不能退回现在的 URL/Buffer 整图路径。
沿用 BookHelp 图片路径,文件内容为存储真相;增加最小的章节索引与保留记录,管理用途和有效性。 阅读、自动离线和显式下载使用同一获取入口、同一去重机制、同一文件,不复制到第二个 Coil 缓存。 不要为此新建 Gradle 模块或通用存储框架。
| 用途 | 获取方式 | 保留与淘汰 |
|---|---|---|
| 普通在线阅读 | 当前页优先,有限预取;完成后发布本地文件 | 可淘汰,受阅读缓存预算限制 |
| 自动离线 | 同一入口补齐配置范围内章节及元数据 | 受明确的自动离线保留窗口约束 |
| 用户显式下载 | 同一入口补齐指定章节 | 持久保留,不受阅读 LRU 或阅读位置窗口删除 |
| 活动渲染/获取 | 持有文件使用凭证 | 使用期间不可删除,不等于永久保留 |
同一张图可关联多个章节与用途。取消一个用途不能删除仍被其他用途保留的文件。 下载成功只是保留用途升级,不再获取或再复制已有有效图片。
BookHelp 外部专属目录通常不被系统作为 cache 回收,但可能因应用清数据、卸载、 外部存储不可用或应用自己的清理而失效,不能写成“只有卸载才会删除”。
在现有 Android 数据层 manga owner 内形成获取能力;读者是漫画会话,下载者是现有图片下载调用链。 ViewModel 经现有 Gateway/Repository 使用它,不访问 BookHelp、DAO 或 File。 仅在接入真实调用者的同一切片增加窄契约,不先生成无调用方接口。
一次获取的身份至少包含书籍存储身份、书源身份与完整原始 src;最终网络 URL 只是请求结果。
落盘保持现有路径兼容,迁移时确认书籍改名/来源切换与 updateCacheFolder 的语义。
如果书源变化可能改变解密结果,必须使旧有效记录失效,而不是只靠路径存在。
获取步骤:
.tmp 文件,完成读取与解密后校验,再以原子替换发布最终文件。
不把临时文件交给 Coil;不允许退回向可见最终路径逐字节复制。“有效”至少要求文件非空、格式受支持、头部尺寸有效,且本次完整读取成功; 已知 Content-Length 应匹配,解密后重新校验。服务端未知长度不伪造百分比。 格式校验通过也不保证每台设备都能区域解码,设备解码失败属于渲染降级流程。 失败冷却/坏图诊断与有效文件分开,不能把失败占位放进下载完成判定。
remove(key)。在同一书籍目录保存版本化、原子更新的最小索引(具体模型以契约测试为准): 章节 URL/index、章节文本文件、预期图片完整 src 列表、有效文件关联、保留用途和最后访问时间。 不在元数据里保存最终带 token URL 或认证 header 明文副本;完整身份需要持久化时评估敏感选项。
下载完成 = 章节列表/正文足以重建阅读页 + 所有预期图片有效且被保留。 单个图片下载完、预取请求成功或 UI Ready 均不能单独标为整章可离线。 索引不代替真实文件;打开时发现缺失应降级为未完成/可重试,并修正下载状态。 索引损坏时重建可重建部分,不清空整本书原图,更不能无声删除已有下载。
旧图片缺少用途记录时,不能直接当阅读缓存淘汰;先保守保留,再由明确迁移规则或用户清理分类。
新策略必须接管 clearComicCache、clearInvalidCache 与改名/移除书籍清理。
当前删除路径已协调读写租约,章节窗口不会清理预算管理的在线文件;
updateCacheFolder 同时检查源/目标目录的使用登记,忙时延迟迁移,释放租约后在 IO 上重试。
连续改名的待迁移依赖也保留;这不是持久化迁移队列,进程中断后的旧目录恢复仍需后续索引支持。
迁移仍沿用既有 rename 语义,目标目录已存在时不会合并;需要稳定目录身份/迁移索引解决
活动阅读期间改名后,新路径暂未迁移而产生的缓存 miss。
.data(File(path)) 请求。
不默认先走 URL 图片请求再切 File,避免两条获取链路与重复 preview 解码。ContentScale.None 必须单独验证:缩小 preview 不应改变原图固有尺寸或初始缩放。ZoomableAsyncImage(File) 或设置 diskCachePolicy 不能关闭该区域解码路径。
此模式暂不承诺区域解码清晰度;之后验证等价渲染滤镜再统一,不能悄悄失去二值化。ZoomableImage 未暴露 SubSamplingImageErrorReporter,
也没有对应 CompositionLocal;不能假定直接调用它已经接入错误回退。
现在在 SubSamplingImageSource.decoder() 返回的 factory/decoder 边界捕获初始化和瓦片异常,
发出一次请求 owner 的降级状态,保留预览直到 Coil 整图 painter 接管;取消照常传播。
错误适配与在线文件租约独立:本地目录、CBZ 解压文件及 content URI 同样包装原 source,
在线原图额外获取瓦片租约。无租约不再跳过错误恢复,原 source 的格式/URI 能力与关闭语义保留。
ImageRegionDecoder 在 0.19.0 虽处于 internal 包,声明为 public;没有复制库渲染代码,
但升级依赖时必须复核此适配点。降级绑定当前请求 owner,重试建立新 owner 后允许再次区域解码;
尚未实现跨请求的文件版本失败记忆。images/.online/<原图文件名> 登记用途,marker 的修改时间记录访问时间;
避免用图片后缀判断用途,也不保存 URL/token/header 副本。新获取文件在发布前登记,
历史未分类文件保守保留;现有章节下载复用时删除 marker,升级为预算外保留文件。
这是可淘汰文件的软预算:活动请求/瓦片暂不删除,释放租约后在 IO 上合并清理请求并再次淘汰。
不是整本书缓存的硬上限,不能靠超预算删除正在使用的文件。
该预算不包含用户显式保留下载;下载界面单独显示占用。imageRetainNum 是现有章节窗口语义,不改名为字节上限。用于自动离线时需说明保留范围,
不能影响显式下载或替代字节预算。manga_cache 仅作过渡。
是否还能利用旧 HTTP 缓存、如何避免新网络获取的双份落盘,必须按实际 AnalyzeUrl 客户端验证,
不凭修改一个容量数字宣称已消除双份存储。每个切片可独立验证;不要一次同时更换网络、数据库、DI、导航和 UI。
先写测试,再修正 BookHelp 发布与有效性语义;接入现有 saveImage/saveImages 真实调用方。 测试:取消/IO 失败无半文件、坏文件可重试、同图并发一次获取、等待者取消、锁回收竞争、 原始 src/headers/解密参数兼容、历史文件采纳、失败批次不标下载完成。
首个已实现子切片:BookImageFileStore 由 BookHelp 实际使用,负责非空/格式校验、
同目录临时写入、原子发布与按文件串行获取;下载完成检查改为实际图片有效性检查。
hasImageContent 不再边检查边删除坏图,避免检查后新文件已发布却被旧检查删除的竞争。
图片及目录清理与写入登记原子协调:存在写入者或排队等待者时跳过清理,
章节窗口清理不删除写入中的临时文件;同步 writeImage 也登记写入保护。
目前是写入保护,不代表已经保护未来瓦片解码器的读取生命周期。
此时还没有引入阅读自动落盘,所以不会增加无限增长的在线阅读存储。
仍未完成:持久有效记录/源版本失效、完整传输长度记录、共享任务订阅取消语义、 完整离线清单。读取保护、预算与目录迁移协调由 B 补齐;用途保护由 C 补齐。 格式/尺寸检查不是整图所有像素可解码的证明; 后续渲染错误必须保持可重试,不能因已有文件无条件标 Ready。
首个子切片的验证:BookImageFileStoreTest 10 项、BookHelpImageFileTest 在 API 26/35
各 5 项 native graphics 测试、BookHelpImageCacheCompleteTest 1 项,共 21 项通过。
compileAppDebugKotlin、verifyConfigArchitecture、lintAppDebug 与 git diff --check 通过;
lint 仍有现有的 118 个警告、13 个提示,本切片没有放宽 baseline。
覆盖并发、等待者取消、传输失败、发布前取消、坏数据不覆盖原图、PNG/SVG、
历史坏文件重试、已有有效文件不解析网络 URL、写入与清理竞争。
校验通过显式关闭的输入流读取图片头部。
这些测试不替代真实外部存储、认证书源 JS 解密、断网章节恢复和瓦片生命周期的验证。
接入当前页与有限预取,替换 URL 图片请求与自动背景提色;接 File 模型、错误降级、 EInk 整图分支及活动文件保护。首版保持 preview 尺寸,不先做 1/4 优化。 这一切片启用在线落盘时必须同时提供可淘汰预算与安全清理,不能先交付无上限版本。
当前已接入分页展示/预取/背景提色的 File 请求、1000 MiB 预算、请求租约与瓦片独立租约、 EInk painter 分支;未降低 preview 尺寸,也未向共享领域泄漏 File。 原图被预算淘汰后,即使预览还在内存缓存,拦截器也先恢复原图并发出真实获取事件, 让之前 Ready 的页面恢复 Loading;有效原图命中不强制降级 Ready。 解析器按书籍/渲染请求 owner 重建,重试代次进入内存键,避免新请求接着使用旧 owner 的瓦片源。 格式回退沿用 Telephoto/Coil;区域解码初始化/瓦片错误现已自动降级,源/文件版本失效仍未完成。 自动离线仍沿用既有章节窗口;显式下载由 C 的用途索引保护,不参与窗口淘汰。
新增验证覆盖在线预算的重启恢复/LRU/历史保护、活动瓦片阻止清理、请求销毁后迟到获取释放、
在线文件升级章节保留以及 Coil DISK/MEMORY_CACHE 两种结果的 File 身份。
本切片编译、架构门禁与 69 项相关测试通过:存储 14 项、BookHelp 在 API 26/35 各 7 项、
Coil 集成在 API 26/35 各 1 项、owner 2 项、下载完成 1 项、交互 31 项、尺寸 5 项。
lintAppDebug 通过,仍为现有 118 个警告与 13 个提示;未放宽 baseline。
Windows Robolectric 的 API 35 ImageDecoder 文件 JNI 返回 "Only supported on Android";
集成测试指定真实 BitmapFactoryDecoder,生产解码器配置不变。
这些测试尚不证明真实 Compose 页面已出现瓦片或达到 full-quality,需要设备验收。
接章节索引/完成判定、现有 autoOfflineCache 和受保护清理,验证断网重建; 后续下载 UI/队列只补齐同一文件并升级保留用途。历史未分类文件不纳入新增在线预算; 现有章节窗口清理语义继续保留,无法从旧文件本身推断此前是否显式下载。 旧文件再次经过显式下载队列时会无网络补登记索引,之后受显式用途保护。
当前 C 的最小实现:每张原图在 images/.downloads/<原图文件名> 有版本化 Properties 索引,
原子记录 chapter.<index>.<章节 URL 哈希>=explicit。索引只保存引用身份,不复制 src/token/header。
多个章节共享一张原图时追加引用;失败下载也保留已登记用途,但文件缺失/无效时绝不判定完成。
Manual/Batch 队列请求保留显式用途,ReadPreload 不降级已有用途;暂停、优先级与失败重试保留用途。
已有图片命中也会补登记索引,不因 hasImageContent 提前跳过升级;执行中的预加载收到显式请求,
完成回调会再次复核用途并补登记。用途复核和完成提交与入队共用模型锁;
仍在执行的同章再次请求保留在队列,范围游标经过执行中章节时转为待复核索引,
执行中请求不算可启动章节,避免调度循环空转。正文与真实有效原图仍决定章节完成,索引不能代替文件。
在线预算与章节窗口均保护显式用途;整本缓存的主动清理仍可删除下载,读取租约继续保护活动文件。
索引损坏时原图仍受保护,完成判定为 false,可通过显式重试补齐引用。
这是原图→章节用途索引,尚非完整章节下载清单:稳定目录身份、源版本失效、下载取消后主动取消保留、
逐章删除/共享引用回收与独立下载列表恢复留待后续;现有章节正文/数据库继续负责重建阅读页。
本轮验证:13 个相关测试类、104 项测试全部通过(包含 API 26/35 native graphics 文件链路测试),
覆盖区域解码初始化/瓦片失败与取消、本地无在线租约 source 的降级/关闭、在线生产适配器的瓦片租约、
灰度矩阵与通道滤镜组合/EInk 优先级、索引重启/损坏恢复/共享引用、显式用途升级不联网、
保留文件不占在线预算、执行中 Single/Range 请求的保留与可启动判断、既有阅读交互。
复用审查阶段的编译产物队列复现程序,执行中的同章显式请求现可在预加载完成后再次出队。实际执行 :app:testAppDebugUnitTest
(按上述测试类过滤)、verifyConfigArchitecture、lintAppDebug,并完成 Kotlin 编译与
git diff --check;lint 仍为原有 118 个警告、13 个提示,未修改 baseline。
区域错误使用可控 decoder 注入验证,灰度验证矩阵对原图像素的结果与滤镜顺序;
真机原生瓦片/CBZ/content URI 失败、实际灰度绘制、回退后的缩放体验和完整断网重建仍未验收。
对照原版 Legado 的 downloadOnly() 预取,远端预取只准备原图,
不生成预览位图、不执行 EInk 转换、不发送页面 Ready。分页和条漫在线页均进入共享原图文件链路,
同图展示、预取、下载通过文件 mutex 合并成功获取;条漫继续由 AsyncImage 整页绘制,避免页边界细线。
开启预取时,普通分页额外保留前后各两屏的真实渲染;原尺寸模式不额外保留,避免提前解码完整大图。
条漫显示预热改用 Foundation 1.12.1 的 LazyLayoutCacheWindow:滚动方向前方四个视口、
后方两个视口,按实际测量高度决定准备/保留哪些项,不以图片张数封顶。
预组合项使用同一个 AsyncImage 请求和租约,移除重复的手工预览解码队列;
原图纯数据预取持续准备实际当前整章,不再以十张封顶;显示缓存窗口仍按视口范围控制。
设置改为“预加载当前章图片”开关,原先非零页数继续视为开启,关闭时取消整章准备并将额外显示缓存窗口设为零。
条漫的窗口锚点和进度过滤跟随滑动中的可见页(footerItemIndex),不等停手提交阅读进度;
显示窗口由 LazyColumn 直接随滚动方向更新,不经过 footerItemIndex/业务状态往返;
预组合和预测量由框架按帧调度,图片请求仍异步执行,不增加网络或原图获取的全局槽位。
原图获取后即读取头部/EXIF 宽高比,保存到 images/.dimensions 的版本化可重建索引,
索引匹配原图长度/修改时间,损坏或原图替换时重建;布局不再被降采样后的近似比例反复改写。
尺寸发布早于位图解码,纯数据预取也发布尺寸。静止时重测保持视口中已有图片的 key/像素位置;
手势或惯性滚动期间,可见项的尺寸变更暂存,停手后合并一次重测;
离屏项仍立即更新尺寸,以便进入视口前完成准备。停手后只保留仍存在的页键和最新尺寸,
同页后续即时更新会覆盖旧暂存。滚动或显式导航期间不强制 requestScrollToItem,避免取消手势或覆盖导航。
冷加载越过预取范围时,可见图片可能暂时保持占位高度,停手才切换真实高度;不承诺网络/解码必能赶上任意速度。
本地/content 路径仍沿用平台加载器与解码后尺寸回调,尚未接入这个尺寸索引。
原图链路的内存预览命中关闭本次淡入,避免 Telephoto 对缓存图重复淡入时露出底色;
首次获取/解码仍遵循淡入设置。
条漫另有 256 MiB 可再生成的无损 PNG 预览磁盘缓存,键包含原图版本、渲染身份、目标尺寸/缩放、
变换 cacheKey。内存淘汰后可从预览文件恢复,不必每次重新降采样原图;损坏预览自动移除并回退原图。
编码在后台进行,只保留一个编码任务,忙时跳过保存以免排队持有大量长图;不阻塞可见页首显。
只有最终 BitmapImage 保存,动画 Drawable 不转为静态图;缓存命中不重复应用 EInk 等变换。
预览不参与下载完成/显式保留,不代替分页区域解码原图;访问前仍取得原图租约和有效性检查。
原图发布仍保持 fsync/校验/原子替换,未为提速降低下载共用文件的可靠性。
仅数据预取的临时结果不进入位图内存缓存;没有原图 owner 的流仍须读取到 EOF 并关闭。
整章原图准备有两个独立后台任务,当前页及邻近页优先,剩余页持续排队。
同章滑动只重排等待项,不取消在途任务;切章、切书、关闭预取或退出时取消旧任务。
每页完成即释放租约,只记录页键/重试代次,避免把整章变成不可淘汰文件或持有整章位图。
失败跳过继续后续页,不自动循环重试;显式重试通过新代次重新准备,重新进入章节也重新检查。
后台任务数量仅约束这个整章准备队列,不限制可见页、显式下载或全局网络并发。
列表可能含前后章节,但准备只选可见页所属章;边界项使用当前业务章节,未加载章节不隐式拉取。
当前仍按文件 mutex 合并成功获取,尚不是订阅计数式共享传输任务:
切章/退出等获取取消时,等待展示/下载可能重试未完成的传输,不能宣称这一取消边界已解决。
跨图片获取/解密的额外全局槽位已经移除,书源限流和同文件互斥保留。
预算扫描改为后台合并清理,展示获取不等待全目录枚举;活动租约仍保护超预算原图。
清理排序先快照每个候选的访问时间和大小,比较器不读取会被并发 touch 修改的文件属性,
避免 TimSort 的比较契约异常;删除前仍复核在线标记、显式下载用途和活动租约。
后台清理记录普通异常并继续接收请求,协程取消正常传播。此修复通过 BookImageFileStoreTest、
BookHelpImageFileTest 共 34 项测试、Kotlin 编译、架构检查及 diff 检查;未在报错设备重现或重跑 lint。
同一个渲染 owner 的预览/取色/降级复用已获取文件,长度或修改时间变化/文件缺失时重新获取;
跨 owner 仍验证原图,不用未经校验的快速命中替代正确性检查。
位图缓存键附带原图长度/修改时间,文件替换不会沿用旧预览;同时间同长度的外部修改尚不检测。
回调携带书籍、页键、重试代次;旧重试/其他书籍的完成、失败和强制 Loading 被丢弃。
已 Ready 的当前请求出现真实解码失败时仍进入可重试失败态。
加载指示器延迟 150 ms 显示,并结合分页实际图/占位预览、条漫 painter 的显示状态隐藏,
不把传输完成或纯数据预取完成当成显示完成;快速缓存命中不会立即闪转圈。
原图/尺寸索引/预览磁盘缓存改动此前通过 Kotlin 编译、架构检查和 100 项相关测试
(包括 API 26/35 文件及流预取);当时 lint 通过,仍有现有 118 个警告、13 个提示,未放宽 baseline。
本次切换 LazyColumn 缓存窗口并延后可见项重测后,运行 :app:testAppDebugUnitTest
(过滤 MangaReaderInteractionTest、MangaFileRequestTest、MangaPrefetchRequestsTest,共 45 项),
Kotlin 编译、45 项测试、verifyConfigArchitecture 和 git diff --check 均通过;本次未重跑 lint。
随后改为整章原图准备,运行 :app:testAppDebugUnitTest(过滤 MangaReaderInteractionTest、
MangaPrefetch*Test、MangaFileRequestTest、MangaImageDimensionsTest,共 55 项)、
:app:assembleAppDebug、verifyConfigArchitecture 和 git diff --check,均通过;未重跑 lint。
新增覆盖超过十页的整章选择、相邻章节过滤、等待任务重排/在途保留、自动推进至章尾、
切章/禁用取消、失败继续且不循环重试、显式重试代次。整章准备完成后仍受阅读缓存预算淘汰,
不是显式下载保留;超预算章节不承诺所有原图同时留存。真实书源整章网络耗时和快速滑动体验待设备验证。
分页复核补齐竖向 Pager 的稳定页键,并让横/竖可见页监听使用最新状态而不随加载进度重启。
横向双页/宽页拆分的尺寸重排等待滚动结束,优先保留 spread 键(包含 LEFT/RIGHT 半页身份),
组合失效时回落到当前原图页;显式导航仍按目标原图页执行。
重排后的 spread 列表与 Pager 位置尚未校正一致时暂停可见页上报,避免旧页码写入新布局的阅读进度。
整章预取组合逻辑独立为私有 MangaChapterImagePrefetch,背景色缓存随书籍隔离。
本次 :app:testAppDebugUnitTest(过滤 *Manga*Test、BookImageFileStoreTest、BookHelpImageFileTest)
共 131 项通过,Kotlin 编译、架构检查和 diff 检查通过。Pager 重排时序仅检查源码及纯函数,
真机横/竖快速翻页、拆页右半页重排、缩放/旋转与低内存行为仍待验收。
最终源码重新运行同一组 131 项测试、:app:assembleAppDebug、verifyConfigArchitecture、
:app:lintAppDebug 均通过;lint 仍为现有 118 个警告、13 个提示,未修改 baseline。
测试覆盖重叠窗口保留/退出/重试、EOF 与流关闭、预取不污染位图缓存或发送 Ready、
同 owner 复用与文件变化重新获取、相邻预览内存命中/文件替换后解码、旧代次与跨书籍回调过滤,
以及原图存储、下载保留、既有阅读交互和本地区域错误降级。
新测试覆盖滚动中的窗口锚点、可见尺寸延后/离屏尺寸即时更新/批量重测/过期页和尺寸过滤、EXIF/尺寸索引恢复和损坏重建、
解码前尺寸发布、清空内存后的预览磁盘复用及损坏预览回退;布局锚点仅验证选择/偏移,未做设备重测时序测试。
加载遮罩依赖实际渲染状态,尚未运行设备绘制时序测试;真机首次显示/放大清晰耗时、
相邻屏内存、条漫长图/页边界、网络并发与加密书源峰值内存仍待测量。
确认支持格式下 subSamplingState != null 且最终达到 full-quality 状态,
再比较 preview 尺寸、内存、首次清晰时间及是否闪烁。不把正常瓦片解码计为多余完整请求。
必须覆盖:
按修改运行真实任务:
.\gradlew.bat :app:compileAppDebugKotlin
.\gradlew.bat :app:testAppDebugUnitTest --tests <受影响测试类>
.\gradlew.bat verifyConfigArchitecture lintAppDebug --continue --no-configuration-cache
# 涉及资源、Manifest 或打包时
.\gradlew.bat :app:assembleAppDebug
git diff --check
不承诺尚未运行的真机、性能与离线兼容验证;不以“文件已经落盘”作为区域解码和下载完成证明。