yayacal/docs/superpowers/specs/2026-06-16-dog-park-easter-egg-design.md

5.9 KiB
Raw Blame History

关于页面「小狗乐园」彩蛋设计

背景

在「关于鸭鸭日历」页面中,版本号目前是一个无实际功能的 TextButton。本设计为其增加一个隐藏彩蛋:连续点击版本号 7 次后进入「小狗乐园」页面,全屏循环播放一段彩蛋视频。

目标

  • 提升应用趣味性,给用户一个可发现的隐藏彩蛋。
  • 保持现有架构:所有 UI 与业务逻辑留在 :core:app 仅作为 Activity 壳。
  • 不引入过度复杂的依赖或状态管理。

设计决策摘要

决策项 选择 说明
总点击次数 7 次 足够隐藏,又不会太难触发
提示开始时机 第 4 次点击 前 3 次静默,避免普通用户误触时被打扰
提示文案 「再点击 N 下进入小狗乐园」 N 为剩余次数,简洁明确
超时重置 1.5 秒 与 Android 开发者选项等经典彩蛋保持一致节奏
进度持久化 不持久化 离开页面或超时即重置
提示组件 系统 Toast 最符合「小气泡」语义,轻量
视频播放 Media3 ExoPlayer 功能强、与 Compose 集成成熟
视频位置 core/src/main/assets/video/enter_screen_bg1.mp4 与现有 app_icon.webp 等资源保持一致
视频显示 等比裁剪铺满(RESIZE_MODE_ZOOM 填满屏幕,视觉沉浸
声音 静音 不打扰用户
屏幕方向 跟随系统 不强制横竖屏
退出方式 系统返回键 支持预测性返回手势Activity 自然 finish
进入过渡动画 淡入 400ms 营造进入彩蛋的仪式感
退出过渡动画 默认 slide 保持现有返回风格

触发机制(关于页面)

状态

  • AboutScreen 内使用 remember { mutableIntStateOf(0) } 保存当前连续点击次数。
  • 计数为局部状态,不提升到 ViewModel也不持久化。
  • AboutScreen 离开 Composition 时计数自然消失。

点击行为

当前点击次数 行为
1 ~ 3 计数 +1无 Toast
4 Toast「再点击 3 下进入小狗乐园」
5 Toast「再点击 2 下进入小狗乐园」
6 Toast「再点击 1 下进入小狗乐园」
7 调用 onNavigateToDogPark(),进入彩蛋页面

超时重置

每次点击启动/重启一个 LaunchedEffect

  • 在 1.5 秒内收到下一次点击:取消旧 Job计数 +1。
  • 1.5 秒内无新点击Job 执行,计数重置为 0。

导航链路

MainActivity
  └── startActivityWithSlide → AboutActivity
        └── onNavigateToDogPark → startActivityWithSlide → DogParkActivity
  • AboutActivityAboutScreen 新增回调 onNavigateToDogPark: () -> Unit
  • DogParkActivity 继承 BaseActivity,自动获得 edge-to-edge 和 slide 转场支持。

小狗乐园页面

组件

  • DogParkScreen:位于 :core,无业务参数,只负责全屏视频播放。
  • DogParkActivity:位于 :app,继承 BaseActivity,壳逻辑。

视频播放

  • 使用 Media3 ExoPlayer + PlayerView
  • 通过 Compose AndroidView 嵌入 PlayerView
  • 配置:
    • resizeMode = RESIZE_MODE_ZOOM:等比裁剪铺满全屏。
    • useController = false:不显示播放控件。
    • player.volume = 0f:静音。
    • repeatMode = Player.REPEAT_MODE_ONE:循环播放。
  • 媒体源 URIasset:///video/enter_screen_bg1.mp4

生命周期

  • onStartplayer.play()
  • onStopplayer.pause()
  • onDestroyplayer.release()
  • 使用 DisposableEffect 绑定释放逻辑。

退出

  • 用户按系统返回键或执行返回手势时 Activity finish。
  • 预测性返回手势由 Manifest 中的 android:enableOnBackInvokedCallback="true" 支持。
  • 退出动画保留 BaseActivity 默认 slide。

过渡动画

进入动画(淡入)

  • 新增 app/src/main/res/anim/fade_in.xml
  • DogParkActivity.onCreate 中:
    • Android 14+overrideActivityTransition(OVERRIDE_TRANSITION_OPEN, R.anim.fade_in, R.anim.fade_out)
    • 低版本:overridePendingTransition(R.anim.fade_in, R.anim.fade_out)(在 super.onCreate 之后、setContent 之前调用)
  • 淡入时长约 400ms。

退出动画

  • 保留 BaseActivity 默认的 slide 返回动画,不覆盖。

资源

  • 视频文件:
    • 来源:~/Pictures/enter_screen_bg1.mp4
    • 目标:core/src/main/assets/video/enter_screen_bg1.mp4
  • 动画资源:
    • 新增 app/src/main/res/anim/fade_in.xml

依赖变更

gradle/libs.versions.toml

新增:

[versions]
androidx-media3 = "1.6.1"

[libraries]
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "androidx-media3" }
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "androidx-media3" }

core/build.gradle.kts

新增:

implementation(libs.androidx.media3.exoplayer)
implementation(libs.androidx.media3.ui)

错误处理

  • 视频加载/准备失败时,直接 finishWithSlideBack() 静默返回关于页面。
  • 不显示弹窗或 Snackbar避免破坏彩蛋体验。

测试计划

单元测试

  • 抽离纯函数 getToastMessage(clickCount: Int): String? 并测试:
    • 1 ~ 3 返回 null
    • 4 返回「再点击 3 下进入小狗乐园」
    • 5 返回「再点击 2 下进入小狗乐园」
    • 6 返回「再点击 1 下进入小狗乐园」
    • 7 返回 null(此时已跳转)

手动测试

  • 连续点击版本号 7 次,确认进入 DogParkActivity
  • 点击过程中停顿 1.5 秒,确认计数重置。
  • 确认进入动画为淡入。
  • 确认视频全屏、静音、无控件、循环播放。
  • 确认系统返回键正常退出,并回到关于页面。
  • 确认低版本(< Android 14和 Android 14+ 的淡入动画都生效。

未包含在本期

  • 多次进入彩蛋后的不同内容。
  • 视频下载/动态更新。
  • 屏幕常亮保持。
  • 分享彩蛋入口。