Skip to content

Commit c31f176

Browse files
committed
feature: about app screen redesign
1 parent 1d1b974 commit c31f176

3 files changed

Lines changed: 102 additions & 69 deletions

File tree

Lines changed: 85 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,131 @@
11
package com.redmadrobot.debug.plugin.aboutapp.ui
22

3+
import android.content.ClipData
4+
import androidx.compose.foundation.clickable
35
import androidx.compose.foundation.layout.Arrangement
4-
import androidx.compose.foundation.layout.Column
56
import androidx.compose.foundation.layout.PaddingValues
6-
import androidx.compose.foundation.layout.defaultMinSize
7+
import androidx.compose.foundation.layout.Row
78
import androidx.compose.foundation.layout.fillMaxSize
89
import androidx.compose.foundation.layout.fillMaxWidth
910
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.layout.systemBarsPadding
1012
import androidx.compose.foundation.lazy.LazyColumn
1113
import androidx.compose.foundation.lazy.items
12-
import androidx.compose.material.Card
13-
import androidx.compose.material.MaterialTheme
14-
import androidx.compose.material.Text
14+
import androidx.compose.material3.Scaffold
15+
import androidx.compose.material3.SnackbarHost
16+
import androidx.compose.material3.SnackbarHostState
17+
import androidx.compose.material3.Text
1518
import androidx.compose.runtime.Composable
19+
import androidx.compose.runtime.LaunchedEffect
1620
import androidx.compose.runtime.collectAsState
1721
import androidx.compose.runtime.getValue
1822
import androidx.compose.runtime.remember
23+
import androidx.compose.ui.Alignment
1924
import androidx.compose.ui.Modifier
20-
import androidx.compose.ui.text.font.FontWeight
25+
import androidx.compose.ui.draw.clip
26+
import androidx.compose.ui.platform.ClipEntry
27+
import androidx.compose.ui.platform.Clipboard
28+
import androidx.compose.ui.platform.LocalClipboard
29+
import androidx.compose.ui.res.stringResource
2130
import androidx.compose.ui.text.style.TextOverflow
22-
import androidx.compose.ui.tooling.preview.Preview
2331
import androidx.compose.ui.unit.dp
2432
import com.redmadrobot.debug.core.extension.getPlugin
2533
import com.redmadrobot.debug.core.extension.provideViewModel
2634
import com.redmadrobot.debug.plugin.aboutapp.AboutAppPlugin
2735
import com.redmadrobot.debug.plugin.aboutapp.AboutAppPluginContainer
36+
import com.redmadrobot.debug.plugin.aboutapp.R
2837
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppInfo
38+
import com.redmadrobot.debug.uikit.theme.DebugPanelShapes
39+
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
2940

3041
@Composable
3142
internal fun AboutAppScreen(
3243
viewModel: AboutAppViewModel = provideViewModel {
3344
getPlugin<AboutAppPlugin>()
3445
.getContainer<AboutAppPluginContainer>()
3546
.createAboutAppViewModel()
36-
}
47+
},
3748
) {
49+
val snackbarHostState = remember { SnackbarHostState() }
50+
3851
val state by viewModel.state.collectAsState()
52+
val event by viewModel.event.collectAsState()
53+
val clipboard = LocalClipboard.current
3954

40-
AboutAppLayout(state = state)
41-
}
55+
LaunchedEffect(event) {
56+
event?.let { appInfoSelectionEvent ->
57+
val item = appInfoSelectionEvent.item
4258

43-
@Composable
44-
private fun AboutAppLayout(state: AboutAppViewState) {
45-
LazyColumn(
46-
modifier = Modifier.fillMaxSize(),
47-
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
48-
contentPadding = PaddingValues(all = 16.dp),
49-
) {
50-
items(items = state.appInfoList, key = { it.id }) { item ->
51-
AboutAppItem(item = item)
59+
copyToClipboard(clipboard = clipboard, item = item)
60+
val message = appInfoSelectionEvent.message.format(item.title)
61+
snackbarHostState.showSnackbar(message = message)
5262
}
5363
}
54-
}
5564

56-
@Composable
57-
private fun AboutAppItem(item: AboutAppInfo, modifier: Modifier = Modifier) {
58-
Card(
59-
modifier = modifier
60-
.fillMaxWidth()
61-
.defaultMinSize(minHeight = 56.dp),
62-
elevation = 4.dp
63-
) {
64-
Column(
65+
Scaffold(
66+
containerColor = DebugPanelTheme.colors.background.primary,
67+
snackbarHost = {
68+
SnackbarHost(
69+
modifier = Modifier.systemBarsPadding(),
70+
hostState = snackbarHostState
71+
)
72+
},
73+
) { paddingValues ->
74+
LazyColumn(
6575
modifier = Modifier
66-
.fillMaxWidth()
67-
.padding(all = 16.dp),
68-
verticalArrangement = Arrangement.spacedBy(space = 4.dp),
76+
.fillMaxSize()
77+
.padding(paddingValues = paddingValues),
78+
contentPadding = PaddingValues(vertical = 8.dp),
6979
) {
70-
Text(
71-
text = item.title,
72-
style = MaterialTheme.typography.caption,
73-
fontWeight = FontWeight.SemiBold,
74-
color = MaterialTheme.colors.primary,
75-
)
76-
Text(
77-
text = item.value,
78-
style = MaterialTheme.typography.body1,
79-
color = MaterialTheme.colors.onSurface,
80-
maxLines = 2,
81-
overflow = TextOverflow.Ellipsis,
82-
)
80+
items(items = state.appInfoList, key = { it.id }) { item ->
81+
InfoRow(
82+
label = item.title,
83+
value = item.value,
84+
onClick = { message ->
85+
viewModel.onInfoItemClicked(message = message, item = item)
86+
},
87+
)
88+
}
8389
}
8490
}
8591
}
8692

87-
@Preview(showBackground = true)
8893
@Composable
89-
private fun Preview() {
90-
val previewTitle = "Версия"
91-
val previewValue = "3,14"
92-
val state = remember {
93-
AboutAppViewState(
94-
appInfoList = listOf(
95-
AboutAppInfo(title = previewTitle, value = previewValue),
96-
AboutAppInfo(
97-
title = "Номер билда",
98-
value = "fgkdfjgkdfgjdfkgjdfkjgkdfjgkdfjgkdfjgkdjgskdjgkdgfjdsfgjdsfgdsfgjdsfgdskjfgdsjkfgdjfgdsfg"
99-
),
100-
AboutAppInfo(title = previewTitle, value = previewValue),
101-
AboutAppInfo(title = previewTitle, value = previewValue),
102-
AboutAppInfo(title = previewTitle, value = previewValue),
103-
AboutAppInfo(title = previewTitle, value = previewValue),
104-
AboutAppInfo(title = previewTitle, value = previewValue),
105-
AboutAppInfo(title = previewTitle, value = previewValue),
106-
AboutAppInfo(title = previewTitle, value = previewValue),
107-
)
94+
private fun InfoRow(
95+
label: String,
96+
value: String,
97+
onClick: (String) -> Unit,
98+
modifier: Modifier = Modifier
99+
) {
100+
val copiedMessage = stringResource(id = R.string.about_app_copied)
101+
102+
Row(
103+
modifier = modifier
104+
.fillMaxWidth()
105+
.clip(shape = DebugPanelShapes.medium)
106+
.clickable(onClick = { onClick.invoke(copiedMessage) })
107+
.padding(horizontal = 12.dp, vertical = 8.dp),
108+
verticalAlignment = Alignment.Top,
109+
horizontalArrangement = Arrangement.Center
110+
) {
111+
Text(
112+
text = label.uppercase(),
113+
style = DebugPanelTheme.typography.labelMedium,
114+
color = DebugPanelTheme.colors.content.tertiary,
115+
modifier = Modifier.padding(end = 12.dp),
116+
)
117+
Text(
118+
text = value,
119+
style = DebugPanelTheme.typography.bodySmall,
120+
color = DebugPanelTheme.colors.content.primary,
121+
modifier = Modifier.weight(weight = 1f),
122+
overflow = TextOverflow.Ellipsis,
108123
)
109124
}
125+
}
110126

111-
MaterialTheme {
112-
AboutAppLayout(state = state)
113-
}
127+
private suspend fun copyToClipboard(clipboard: Clipboard, item: AboutAppInfo) {
128+
val clipData = ClipData.newPlainText(item.title, item.value)
129+
130+
clipboard.setClipEntry(clipEntry = ClipEntry(clipData))
114131
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
package com.redmadrobot.debug.plugin.aboutapp.ui
22

3+
import com.redmadrobot.debug.core.DebugEvent
34
import com.redmadrobot.debug.core.internal.PluginViewModel
45
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppInfo
56
import kotlinx.coroutines.flow.MutableStateFlow
67
import kotlinx.coroutines.flow.StateFlow
78
import kotlinx.coroutines.flow.asStateFlow
9+
import kotlinx.coroutines.flow.update
810

911
internal class AboutAppViewModel(appInfoList: List<AboutAppInfo>) : PluginViewModel() {
1012
private val _state = MutableStateFlow(value = AboutAppViewState(appInfoList = appInfoList))
1113
val state: StateFlow<AboutAppViewState> = _state.asStateFlow()
14+
15+
private val _event = MutableStateFlow<AppInfoSelectionEvent?>(null)
16+
val event: StateFlow<AppInfoSelectionEvent?> = _event.asStateFlow()
17+
18+
fun onInfoItemClicked(message: String, item: AboutAppInfo) {
19+
_event.update { AppInfoSelectionEvent(message = message, item = item) }
20+
}
1221
}
22+
23+
internal data class AppInfoSelectionEvent(
24+
val message: String,
25+
val item: AboutAppInfo
26+
) : DebugEvent
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<resources />
2+
<resources>
3+
<string name="about_app_copied">«%s» is copied</string>
4+
</resources>

0 commit comments

Comments
 (0)