You need to sign in before continuing.

Commit 6fa813b72c3d8c3ba4903e15d4dea048755d2148

Authored by yibo
1 parent 03db2ccf

refactor(lifelog): 底部精简为 5 tab,录音/时间轴、声纹/纪要 各并为顶部子 tab

底部导航 7 → 5:录音 / 对话 / 纪要 / 相册 / 设置。
- 「录音」页顶部 TabRow 切 录音 / 时间轴
- 「纪要」页顶部 TabRow 切 声纹 / 纪要
- 跨页跳转保留:声纹点某人 / 纪要点要点 → 自动切到「录音」页的时间轴子 tab

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
lifelog-recorder/app/src/main/kotlin/com/lemon/lifelog/MainActivity.kt
... ... @@ -121,11 +121,9 @@ class MainActivity : ComponentActivity() {
121 121 }
122 122  
123 123 private enum class Tab(val label: String, val icon: String) {
124   - Home("录音", "⏺"),
  124 + Recording("录音", "⏺"), // 顶部子页:录音 / 时间轴
125 125 Chat("对话", "💬"),
126   - Timeline("时间轴", "≣"),
127   - Speakers("声纹", "👤"),
128   - Summaries("纪要", "✎"),
  126 + Memo("纪要", "✎"), // 顶部子页:声纹 / 纪要
129 127 Photolog("相册", "🖼"),
130 128 Settings("设置", "⚙"),
131 129 }
... ... @@ -145,14 +143,17 @@ enum class TimeFilter(val label: String) {
145 143  
146 144 @Composable
147 145 private fun MainScreen() {
148   - var tab by remember { mutableStateOf(Tab.Home) }
  146 + var tab by remember { mutableStateOf(Tab.Recording) }
149 147 val activity = androidx.compose.ui.platform.LocalContext.current
150 148 val repo = remember(activity) { Repository(activity) }
151 149  
152   - // Cross-tab state: speaker filter is settable from the Speakers tab.
  150 + // Cross-tab state: speaker filter is settable from the Speakers sub-tab.
153 151 var filterSpeakerId by remember { mutableStateOf<Long?>(null) }
154 152 // Cross-tab jump: a summary bullet sets an absolute timestamp to scroll the timeline to.
155 153 var jumpToTs by remember { mutableStateOf<Long?>(null) }
  154 + // 合并页的顶部子 tab:录音页 0=录音 1=时间轴;纪要页 0=声纹 1=纪要。
  155 + var recordingSub by remember { mutableStateOf(0) }
  156 + var memoSub by remember { mutableStateOf(0) }
156 157  
157 158 val speakers by repo.speakers.observeAll().collectAsState(initial = emptyList())
158 159  
... ... @@ -174,35 +175,82 @@ private fun MainScreen() {
174 175 ) { inner ->
175 176 Box(modifier = Modifier.padding(inner)) {
176 177 when (tab) {
177   - Tab.Home -> HomeTab(activity, repo, onOpenTimeline = { tab = Tab.Timeline })
  178 + Tab.Recording -> RecordingScreen(
  179 + activity = activity, repo = repo, speakers = speakers,
  180 + sub = recordingSub, onSub = { recordingSub = it },
  181 + filterSpeakerId = filterSpeakerId, onFilterSpeakerId = { filterSpeakerId = it },
  182 + jumpToTs = jumpToTs, onJumpConsumed = { jumpToTs = null },
  183 + )
178 184 Tab.Chat -> ChatTab(repo)
179   - Tab.Timeline -> TimelineTab(
  185 + Tab.Memo -> MemoScreen(
  186 + repo = repo, activity = activity, speakers = speakers,
  187 + sub = memoSub, onSub = { memoSub = it },
  188 + onFilterBySpeaker = { id -> filterSpeakerId = id; recordingSub = 1; tab = Tab.Recording },
  189 + onJumpToTime = { ts -> filterSpeakerId = null; jumpToTs = ts; recordingSub = 1; tab = Tab.Recording },
  190 + )
  191 + Tab.Photolog -> PhotologTab(repo)
  192 + Tab.Settings -> SettingsScreen(activity)
  193 + }
  194 + }
  195 + }
  196 +}
  197 +
  198 +// ============================================================ 合并页(顶部子 tab 切换)
  199 +
  200 +@Composable
  201 +private fun RecordingScreen(
  202 + activity: Context,
  203 + repo: Repository,
  204 + speakers: List<SpeakerProfile>,
  205 + sub: Int,
  206 + onSub: (Int) -> Unit,
  207 + filterSpeakerId: Long?,
  208 + onFilterSpeakerId: (Long?) -> Unit,
  209 + jumpToTs: Long?,
  210 + onJumpConsumed: () -> Unit,
  211 +) {
  212 + Column(modifier = Modifier.fillMaxSize()) {
  213 + androidx.compose.material3.TabRow(selectedTabIndex = sub) {
  214 + androidx.compose.material3.Tab(selected = sub == 0, onClick = { onSub(0) }, text = { Text("录音") })
  215 + androidx.compose.material3.Tab(selected = sub == 1, onClick = { onSub(1) }, text = { Text("时间轴") })
  216 + }
  217 + Box(modifier = Modifier.weight(1f)) {
  218 + if (sub == 0) {
  219 + HomeTab(activity, repo, onOpenTimeline = { onSub(1) })
  220 + } else {
  221 + TimelineTab(
180 222 repo = repo,
181 223 speakers = speakers,
182 224 filterSpeakerId = filterSpeakerId,
183   - onFilterSpeakerId = { filterSpeakerId = it },
  225 + onFilterSpeakerId = onFilterSpeakerId,
184 226 jumpToTs = jumpToTs,
185   - onJumpConsumed = { jumpToTs = null },
  227 + onJumpConsumed = onJumpConsumed,
186 228 )
187   - Tab.Speakers -> SpeakersTab(
188   - repo = repo,
189   - speakers = speakers,
190   - onFilterBySpeaker = { id ->
191   - filterSpeakerId = id
192   - tab = Tab.Timeline
193   - },
194   - )
195   - Tab.Summaries -> SummariesTab(
196   - repo = repo,
197   - activity = activity,
198   - onJumpToTime = { ts ->
199   - filterSpeakerId = null
200   - jumpToTs = ts
201   - tab = Tab.Timeline
202   - },
203   - )
204   - Tab.Photolog -> PhotologTab(repo)
205   - Tab.Settings -> SettingsScreen(activity)
  229 + }
  230 + }
  231 + }
  232 +}
  233 +
  234 +@Composable
  235 +private fun MemoScreen(
  236 + repo: Repository,
  237 + activity: Context,
  238 + speakers: List<SpeakerProfile>,
  239 + sub: Int,
  240 + onSub: (Int) -> Unit,
  241 + onFilterBySpeaker: (Long) -> Unit,
  242 + onJumpToTime: (Long) -> Unit,
  243 +) {
  244 + Column(modifier = Modifier.fillMaxSize()) {
  245 + androidx.compose.material3.TabRow(selectedTabIndex = sub) {
  246 + androidx.compose.material3.Tab(selected = sub == 0, onClick = { onSub(0) }, text = { Text("声纹") })
  247 + androidx.compose.material3.Tab(selected = sub == 1, onClick = { onSub(1) }, text = { Text("纪要") })
  248 + }
  249 + Box(modifier = Modifier.weight(1f)) {
  250 + if (sub == 0) {
  251 + SpeakersTab(repo = repo, speakers = speakers, onFilterBySpeaker = onFilterBySpeaker)
  252 + } else {
  253 + SummariesTab(repo = repo, activity = activity, onJumpToTime = onJumpToTime)
206 254 }
207 255 }
208 256 }
... ...