Commit 4d7bade5ae5fb9f8ef856253006c7d0b6ee660c1
1 parent
a0423a9f
refactor(lifelog): 底部精简为 5 tab,录音/时间轴、声纹/纪要 各并为顶部子 tab
底部导航 7 → 5:录音 / 对话 / 纪要 / 相册 / 设置。 - 「录音」页顶部 TabRow 切 录音 / 时间轴 - 「纪要」页顶部 TabRow 切 声纹 / 纪要 - 跨页跳转保留:声纹点某人 / 纪要点要点 → 自动切到「录音」页的时间轴子 tab Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Showing
1 changed file
with
77 additions
and
29 deletions
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 | } | ... | ... |