Skip to content

Commit 1d1b974

Browse files
committed
feature: core screens redesign
1 parent 0dc8319 commit 1d1b974

5 files changed

Lines changed: 162 additions & 69 deletions

File tree

panel-core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,7 @@ dependencies {
5858
implementation(stack.timber)
5959
implementation(stack.material)
6060

61+
implementation(stack.kotlinx.collections.immutable)
62+
6163
api(androidx.lifecycle.viewmodel)
6264
}

panel-core/src/main/kotlin/com/redmadrobot/debug/core/inapp/compose/DebugPanelScreen.kt

Lines changed: 138 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,102 +3,183 @@
33
package com.redmadrobot.debug.core.inapp.compose
44

55
import androidx.compose.foundation.ExperimentalFoundationApi
6+
import androidx.compose.foundation.background
67
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
712
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
814
import androidx.compose.foundation.pager.HorizontalPager
9-
import androidx.compose.foundation.pager.PagerState
1015
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
2123
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.key
2225
import androidx.compose.runtime.remember
2326
import androidx.compose.runtime.rememberCoroutineScope
27+
import androidx.compose.ui.Alignment
2428
import androidx.compose.ui.Modifier
2529
import androidx.compose.ui.res.painterResource
2630
import androidx.compose.ui.res.stringResource
2731
import androidx.compose.ui.unit.dp
2832
import com.redmadrobot.debug.core.R
2933
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
3137
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
38+
import kotlinx.collections.immutable.ImmutableList
39+
import kotlinx.collections.immutable.toImmutableList
3240
import kotlinx.coroutines.launch
3341

34-
@Suppress("UnusedParameter")
3542
@Composable
3643
public fun DebugPanelScreen(
3744
themeMode: ThemeMode,
45+
onThemeModeChange: (ThemeMode) -> Unit,
3846
onClose: () -> Unit,
39-
onThemeModeChange: (ThemeMode) -> Unit = {}
4047
) {
4148
val plugins = remember { getAllPlugins() }
42-
val pluginsName = remember { plugins.map { it.getName() } }
49+
val pluginNames = remember { plugins.map { it.getName() } }
4350
val pagerState = rememberPagerState(initialPage = 0, pageCount = { plugins.size })
51+
val scope = rememberCoroutineScope()
4452

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()
6570
}
6671
}
6772
}
6873

6974
@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+
}
72110

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(
79130
modifier = Modifier.tabIndicatorOffset(
80-
currentTabPosition = tabPositions[pagerState.currentPage]
131+
selectedTabIndex = selectedIndex,
132+
matchContentSize = false,
81133
),
82134
height = 2.dp,
83-
color = MaterialTheme.colors.secondary
135+
color = DebugPanelTheme.colors.content.accent,
84136
)
85-
}
137+
},
138+
divider = {},
86139
) {
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+
}
95148
}
96149
}
97150
}
98151

99152
@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
103177
}
178+
179+
Text(
180+
modifier = modifier,
181+
text = title,
182+
style = DebugPanelTheme.typography.labelLarge,
183+
color = titleColor,
184+
)
104185
}

panel-core/src/main/kotlin/com/redmadrobot/debug/core/ui/settings/DebugSettingsActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.redmadrobot.debug.core.DebugPanel
1111
import com.redmadrobot.debug.core.extension.getAllPlugins
1212
import com.redmadrobot.debug.core.internal.EditablePlugin
1313
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
14+
import kotlinx.collections.immutable.toImmutableList
1415

1516
internal class DebugSettingsActivity : AppCompatActivity() {
1617
override fun onCreate(savedInstanceState: Bundle?) {
@@ -26,7 +27,7 @@ internal class DebugSettingsActivity : AppCompatActivity() {
2627
val pluginItems = remember { getSettingItems() }
2728
DebugSettingsNavHost(
2829
navController = navController,
29-
pluginItems = pluginItems,
30+
pluginItems = pluginItems.toImmutableList(),
3031
)
3132
}
3233
}

panel-core/src/main/kotlin/com/redmadrobot/debug/core/ui/settings/DebugSettingsNavHost.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@ import androidx.navigation.compose.NavHost
66
import androidx.navigation.compose.composable
77
import com.redmadrobot.debug.core.extension.getPlugin
88
import com.redmadrobot.debug.core.internal.EditablePlugin
9+
import kotlinx.collections.immutable.ImmutableList
910

1011
private const val MAIN_SCREEN_ROUTE = "main"
1112

1213
@Composable
1314
internal fun DebugSettingsNavHost(
1415
navController: NavHostController,
15-
pluginItems: List<PluginSettingsItem>,
16+
pluginItems: ImmutableList<PluginSettingsItem>,
1617
) {
1718
NavHost(navController = navController, startDestination = MAIN_SCREEN_ROUTE) {
1819
composable(MAIN_SCREEN_ROUTE) {
19-
DebugSettingsScreen(pluginItems = pluginItems, navController = navController)
20+
DebugSettingsScreen(
21+
pluginItems = pluginItems,
22+
navController = navController
23+
)
2024
}
2125

2226
pluginItems.forEach { plugin ->
Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
package com.redmadrobot.debug.core.ui.settings
22

3+
import androidx.compose.foundation.background
34
import androidx.compose.foundation.clickable
45
import androidx.compose.foundation.layout.fillMaxSize
56
import androidx.compose.foundation.layout.padding
67
import androidx.compose.foundation.lazy.LazyColumn
78
import androidx.compose.foundation.lazy.items
8-
import androidx.compose.material.Text
9+
import androidx.compose.material3.Text
910
import androidx.compose.runtime.Composable
1011
import androidx.compose.ui.Modifier
1112
import androidx.compose.ui.unit.dp
12-
import androidx.compose.ui.unit.sp
1313
import androidx.navigation.NavController
14+
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
15+
import kotlinx.collections.immutable.ImmutableList
1416

1517
@Composable
1618
internal fun DebugSettingsScreen(
1719
navController: NavController,
18-
pluginItems: List<PluginSettingsItem>,
20+
pluginItems: ImmutableList<PluginSettingsItem>,
1921
) {
2022
LazyColumn(
21-
modifier = Modifier.fillMaxSize(),
23+
modifier = Modifier
24+
.fillMaxSize()
25+
.background(color = DebugPanelTheme.colors.background.primary),
2226
) {
23-
items(pluginItems) { item ->
27+
items(items = pluginItems, key = { it.pluginName }) { item ->
2428
PluginItem(
2529
pluginName = item.pluginName,
2630
onClick = { navController.navigate(item.pluginClassName) },
@@ -30,13 +34,14 @@ internal fun DebugSettingsScreen(
3034
}
3135

3236
@Composable
33-
private fun PluginItem(pluginName: String, onClick: () -> Unit) {
37+
private fun PluginItem(pluginName: String, onClick: () -> Unit, modifier: Modifier = Modifier) {
3438
Text(
35-
modifier = Modifier
39+
modifier = modifier
3640
.fillMaxSize()
3741
.clickable { onClick.invoke() }
38-
.padding(horizontal = 16.dp, vertical = 16.dp),
42+
.padding(all = 16.dp),
3943
text = pluginName,
40-
fontSize = 18.sp,
44+
style = DebugPanelTheme.typography.titleMedium,
45+
color = DebugPanelTheme.colors.content.primary,
4146
)
4247
}

0 commit comments

Comments
 (0)