|
3 | 3 | package com.redmadrobot.debug.core.inapp.compose |
4 | 4 |
|
5 | 5 | import androidx.compose.foundation.ExperimentalFoundationApi |
| 6 | +import androidx.compose.foundation.background |
6 | 7 | import androidx.compose.foundation.layout.Column |
| 8 | +import androidx.compose.foundation.layout.Row |
| 9 | +import androidx.compose.foundation.layout.fillMaxSize |
| 10 | +import androidx.compose.foundation.layout.fillMaxWidth |
| 11 | +import androidx.compose.foundation.layout.heightIn |
7 | 12 | import androidx.compose.foundation.layout.padding |
| 13 | +import androidx.compose.foundation.layout.size |
8 | 14 | import androidx.compose.foundation.pager.HorizontalPager |
9 | | -import androidx.compose.foundation.pager.PagerState |
10 | 15 | import androidx.compose.foundation.pager.rememberPagerState |
11 | | -import androidx.compose.material.Icon |
12 | | -import androidx.compose.material.IconButton |
13 | | -import androidx.compose.material.MaterialTheme |
14 | | -import androidx.compose.material.Scaffold |
15 | | -import androidx.compose.material.ScrollableTabRow |
16 | | -import androidx.compose.material.Tab |
17 | | -import androidx.compose.material.TabRowDefaults |
18 | | -import androidx.compose.material.TabRowDefaults.tabIndicatorOffset |
19 | | -import androidx.compose.material.Text |
20 | | -import androidx.compose.material.TopAppBar |
| 16 | +import androidx.compose.material3.ExperimentalMaterial3Api |
| 17 | +import androidx.compose.material3.Icon |
| 18 | +import androidx.compose.material3.IconButton |
| 19 | +import androidx.compose.material3.SecondaryScrollableTabRow |
| 20 | +import androidx.compose.material3.Tab |
| 21 | +import androidx.compose.material3.TabRowDefaults |
| 22 | +import androidx.compose.material3.Text |
21 | 23 | import androidx.compose.runtime.Composable |
| 24 | +import androidx.compose.runtime.key |
22 | 25 | import androidx.compose.runtime.remember |
23 | 26 | import androidx.compose.runtime.rememberCoroutineScope |
| 27 | +import androidx.compose.ui.Alignment |
24 | 28 | import androidx.compose.ui.Modifier |
25 | 29 | import androidx.compose.ui.res.painterResource |
26 | 30 | import androidx.compose.ui.res.stringResource |
27 | 31 | import androidx.compose.ui.unit.dp |
28 | 32 | import com.redmadrobot.debug.core.R |
29 | 33 | import com.redmadrobot.debug.core.extension.getAllPlugins |
30 | | -import com.redmadrobot.debug.core.plugin.Plugin |
| 34 | +import com.redmadrobot.debug.uikit.components.ThemeSwitcher |
| 35 | +import com.redmadrobot.debug.uikit.theme.DebugPanelDimensions |
| 36 | +import com.redmadrobot.debug.uikit.theme.DebugPanelTheme |
31 | 37 | import com.redmadrobot.debug.uikit.theme.model.ThemeMode |
| 38 | +import kotlinx.collections.immutable.ImmutableList |
| 39 | +import kotlinx.collections.immutable.toImmutableList |
32 | 40 | import kotlinx.coroutines.launch |
33 | 41 |
|
34 | | -@Suppress("UnusedParameter") |
35 | 42 | @Composable |
36 | 43 | public fun DebugPanelScreen( |
37 | 44 | themeMode: ThemeMode, |
| 45 | + onThemeModeChange: (ThemeMode) -> Unit, |
38 | 46 | onClose: () -> Unit, |
39 | | - onThemeModeChange: (ThemeMode) -> Unit = {} |
40 | 47 | ) { |
41 | 48 | val plugins = remember { getAllPlugins() } |
42 | | - val pluginsName = remember { plugins.map { it.getName() } } |
| 49 | + val pluginNames = remember { plugins.map { it.getName() } } |
43 | 50 | val pagerState = rememberPagerState(initialPage = 0, pageCount = { plugins.size }) |
| 51 | + val scope = rememberCoroutineScope() |
44 | 52 |
|
45 | | - Scaffold( |
46 | | - topBar = { |
47 | | - TopAppBar( |
48 | | - title = { Text(text = stringResource(R.string.debug_panel)) }, |
49 | | - navigationIcon = { |
50 | | - IconButton(onClick = onClose) { |
51 | | - Icon( |
52 | | - painter = painterResource(id = R.drawable.ic_arrow_back), |
53 | | - contentDescription = null, |
54 | | - ) |
55 | | - } |
56 | | - }, |
57 | | - backgroundColor = MaterialTheme.colors.background, |
58 | | - elevation = 0.dp, |
59 | | - ) |
60 | | - }, |
61 | | - ) { paddingValues -> |
62 | | - Column(modifier = Modifier.padding(paddingValues)) { |
63 | | - PluginsTabLayout(pluginsName = pluginsName, pagerState = pagerState) |
64 | | - PluginsPager(plugins = plugins, pagerState = pagerState) |
| 53 | + Column( |
| 54 | + modifier = Modifier |
| 55 | + .fillMaxSize() |
| 56 | + .background(color = DebugPanelTheme.colors.background.primary), |
| 57 | + ) { |
| 58 | + PanelTopBar( |
| 59 | + themeMode = themeMode, |
| 60 | + onThemeModeChange = onThemeModeChange, |
| 61 | + onClose = onClose, |
| 62 | + ) |
| 63 | + PanelTabRow( |
| 64 | + pluginNames = pluginNames.toImmutableList(), |
| 65 | + selectedIndex = pagerState.currentPage, |
| 66 | + onTabClick = { index -> scope.launch { pagerState.animateScrollToPage(index) } }, |
| 67 | + ) |
| 68 | + HorizontalPager(state = pagerState, modifier = Modifier.weight(weight = 1f)) { page -> |
| 69 | + plugins[page].content() |
65 | 70 | } |
66 | 71 | } |
67 | 72 | } |
68 | 73 |
|
69 | 74 | @Composable |
70 | | -private fun PluginsTabLayout(pluginsName: List<String>, pagerState: PagerState) { |
71 | | - val scope = rememberCoroutineScope() |
| 75 | +private fun PanelTopBar( |
| 76 | + themeMode: ThemeMode, |
| 77 | + onThemeModeChange: (ThemeMode) -> Unit, |
| 78 | + onClose: () -> Unit, |
| 79 | + modifier: Modifier = Modifier |
| 80 | +) { |
| 81 | + Row( |
| 82 | + modifier = modifier |
| 83 | + .fillMaxWidth() |
| 84 | + .heightIn(min = DebugPanelDimensions.topBarHeight) |
| 85 | + .padding(horizontal = 8.dp), |
| 86 | + verticalAlignment = Alignment.CenterVertically, |
| 87 | + ) { |
| 88 | + Text( |
| 89 | + text = stringResource(id = R.string.debug_panel), |
| 90 | + style = DebugPanelTheme.typography.titleLarge, |
| 91 | + color = DebugPanelTheme.colors.content.primary, |
| 92 | + modifier = Modifier |
| 93 | + .weight(weight = 1f) |
| 94 | + .padding(start = 4.dp), |
| 95 | + ) |
| 96 | + ThemeSwitcher( |
| 97 | + currentMode = themeMode, |
| 98 | + onModeSelect = onThemeModeChange, |
| 99 | + ) |
| 100 | + IconButton(onClick = onClose) { |
| 101 | + Icon( |
| 102 | + painter = painterResource(id = R.drawable.ic_arrow_back), |
| 103 | + contentDescription = null, |
| 104 | + tint = DebugPanelTheme.colors.content.secondary, |
| 105 | + modifier = Modifier.size(size = DebugPanelDimensions.iconSizeMedium), |
| 106 | + ) |
| 107 | + } |
| 108 | + } |
| 109 | +} |
72 | 110 |
|
73 | | - ScrollableTabRow( |
74 | | - selectedTabIndex = pagerState.currentPage, |
75 | | - backgroundColor = MaterialTheme.colors.background, |
76 | | - edgePadding = 16.dp, |
77 | | - indicator = { tabPositions -> |
78 | | - TabRowDefaults.Indicator( |
| 111 | +@OptIn(ExperimentalMaterial3Api::class) |
| 112 | +@Composable |
| 113 | +private fun PanelTabRow( |
| 114 | + pluginNames: ImmutableList<String>, |
| 115 | + selectedIndex: Int, |
| 116 | + onTabClick: (Int) -> Unit, |
| 117 | + modifier: Modifier = Modifier |
| 118 | +) { |
| 119 | + SecondaryScrollableTabRow( |
| 120 | + selectedTabIndex = selectedIndex, |
| 121 | + modifier = modifier |
| 122 | + .fillMaxWidth() |
| 123 | + .heightIn(min = DebugPanelDimensions.tabRowHeight) |
| 124 | + .background(color = DebugPanelTheme.colors.surface.secondary), |
| 125 | + edgePadding = 4.dp, |
| 126 | + containerColor = DebugPanelTheme.colors.surface.secondary, |
| 127 | + contentColor = DebugPanelTheme.colors.content.secondary, |
| 128 | + indicator = { |
| 129 | + TabRowDefaults.SecondaryIndicator( |
79 | 130 | modifier = Modifier.tabIndicatorOffset( |
80 | | - currentTabPosition = tabPositions[pagerState.currentPage] |
| 131 | + selectedTabIndex = selectedIndex, |
| 132 | + matchContentSize = false, |
81 | 133 | ), |
82 | 134 | height = 2.dp, |
83 | | - color = MaterialTheme.colors.secondary |
| 135 | + color = DebugPanelTheme.colors.content.accent, |
84 | 136 | ) |
85 | | - } |
| 137 | + }, |
| 138 | + divider = {}, |
86 | 139 | ) { |
87 | | - pluginsName.forEachIndexed { index, _ -> |
88 | | - Tab( |
89 | | - text = { Text(text = pluginsName[index]) }, |
90 | | - selected = pagerState.currentPage == index, |
91 | | - onClick = { |
92 | | - scope.launch { pagerState.animateScrollToPage(index) } |
93 | | - } |
94 | | - ) |
| 140 | + pluginNames.forEachIndexed { index, title -> |
| 141 | + key(title) { |
| 142 | + PluginTab( |
| 143 | + isSelected = selectedIndex == index, |
| 144 | + title = title, |
| 145 | + onTabClick = { onTabClick(index) } |
| 146 | + ) |
| 147 | + } |
95 | 148 | } |
96 | 149 | } |
97 | 150 | } |
98 | 151 |
|
99 | 152 | @Composable |
100 | | -private fun PluginsPager(plugins: List<Plugin>, pagerState: PagerState) { |
101 | | - HorizontalPager(state = pagerState) { page -> |
102 | | - plugins[page].content() |
| 153 | +private fun PluginTab( |
| 154 | + title: String, |
| 155 | + isSelected: Boolean, |
| 156 | + onTabClick: () -> Unit, |
| 157 | + modifier: Modifier = Modifier |
| 158 | +) { |
| 159 | + Tab( |
| 160 | + modifier = modifier.padding(horizontal = 4.dp), |
| 161 | + selected = isSelected, |
| 162 | + onClick = { onTabClick.invoke() }, |
| 163 | + text = { PluginTabTitle(title = title, isSelected = isSelected) }, |
| 164 | + ) |
| 165 | +} |
| 166 | + |
| 167 | +@Composable |
| 168 | +private fun PluginTabTitle( |
| 169 | + title: String, |
| 170 | + isSelected: Boolean, |
| 171 | + modifier: Modifier = Modifier |
| 172 | +) { |
| 173 | + val titleColor = if (isSelected) { |
| 174 | + DebugPanelTheme.colors.content.accent |
| 175 | + } else { |
| 176 | + DebugPanelTheme.colors.content.secondary |
103 | 177 | } |
| 178 | + |
| 179 | + Text( |
| 180 | + modifier = modifier, |
| 181 | + text = title, |
| 182 | + style = DebugPanelTheme.typography.labelLarge, |
| 183 | + color = titleColor, |
| 184 | + ) |
104 | 185 | } |
0 commit comments