Skip to content

Commit 1b0b17e

Browse files
committed
practice jetpack
1 parent 3f36db5 commit 1b0b17e

2 files changed

Lines changed: 341 additions & 0 deletions

File tree

app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ plugins{
1818
alias(libs.plugins.jetbrainsCompose)
1919
alias(libs.plugins.serialization)
2020
alias(libs.plugins.download)
21+
2122
}
2223

2324
repositories{
@@ -110,6 +111,7 @@ dependencies {
110111
implementation(compose.ui)
111112
implementation(compose.components.resources)
112113
implementation(compose.components.uiToolingPreview)
114+
implementation(compose.materialIconsExtended)
113115

114116
implementation(compose.desktop.currentOs)
115117

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
package processing.app.ui
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.*
6+
import androidx.compose.foundation.lazy.LazyColumn
7+
import androidx.compose.foundation.lazy.grid.*
8+
import androidx.compose.material.icons.outlined.Info
9+
import androidx.compose.ui.graphics.Color
10+
import androidx.compose.foundation.background
11+
import androidx.compose.foundation.lazy.items
12+
import androidx.compose.material.Text
13+
import androidx.compose.material.icons.Icons
14+
import androidx.compose.material.*
15+
import androidx.compose.material.icons.outlined.Add
16+
import androidx.compose.material.icons.outlined.AddCircle
17+
import androidx.compose.material.icons.outlined.Build
18+
import androidx.compose.material.icons.outlined.Face
19+
import androidx.compose.material.icons.outlined.MailOutline
20+
import androidx.compose.runtime.*
21+
import androidx.compose.ui.Alignment
22+
import androidx.compose.ui.Modifier
23+
import androidx.compose.ui.graphics.vector.ImageVector
24+
import androidx.compose.ui.unit.dp
25+
import androidx.compose.ui.window.*
26+
27+
data class SketchItem(
28+
val name: String,
29+
val isFolder: Boolean,
30+
val lastModified: Long = 0L // default for folders
31+
)
32+
33+
fun main() = application {
34+
Window(
35+
onCloseRequest = ::exitApplication,
36+
title = "Sketchbook Prototype",
37+
state = WindowState(width = 800.dp, height = 600.dp, position = WindowPosition(Alignment.Center))
38+
) {
39+
Sketchbook()
40+
}
41+
}
42+
43+
@Composable
44+
fun Sketchbook() {
45+
// TODO: Replace dummy data with reading from folder.
46+
val sketchList = listOf(
47+
SketchItem("Fun", false, 1680000000000),
48+
SketchItem("Cute", false, 1660000000000),
49+
SketchItem("MyFolder", true),
50+
SketchItem("Silly", false, 1670000000000),
51+
)
52+
53+
var sortOption by remember { mutableStateOf("Recently Updated") }
54+
55+
val sortedSketches = when (sortOption) {
56+
"Alphabetical" -> sketchList.sortedBy { it.name.lowercase() }
57+
"Recently Updated" -> sketchList.sortedByDescending { it.lastModified }
58+
else -> sketchList
59+
}
60+
61+
62+
Row(Modifier.fillMaxSize()) {
63+
Column(
64+
modifier = Modifier
65+
.weight(0.35f)
66+
.fillMaxHeight()
67+
.padding(8.dp)
68+
) {
69+
Sidebar(sketchList)
70+
}
71+
72+
Column(
73+
modifier = Modifier
74+
.weight(0.65f)
75+
.fillMaxHeight()
76+
.padding(8.dp)
77+
) {
78+
MainSketchGrid(
79+
sketches = sortedSketches.filter { !it.isFolder },
80+
selectedFolder = null,
81+
searchQuery = "",
82+
sortOption = sortOption,
83+
onSortChange = { sortOption = it }
84+
)
85+
}
86+
}
87+
}
88+
89+
@Composable
90+
fun Sidebar(sketches: List<SketchItem>) {
91+
var searchText by remember { mutableStateOf("") }
92+
93+
Column(
94+
modifier = Modifier.fillMaxHeight().width(350.dp)
95+
) {
96+
Row(
97+
modifier = Modifier
98+
.fillMaxWidth()
99+
.padding(8.dp),
100+
verticalAlignment = Alignment.CenterVertically
101+
) {
102+
Column() {
103+
Text(
104+
text = "Sketchbook",
105+
style = MaterialTheme.typography.h4,
106+
)
107+
TextField(
108+
value = searchText,
109+
onValueChange = { searchText = it },
110+
placeholder = { Text("Search...") },
111+
modifier = Modifier.fillMaxWidth()
112+
)
113+
}
114+
}
115+
116+
LazyColumn(
117+
modifier = Modifier
118+
.fillMaxSize()
119+
.weight(1f)
120+
.padding(8.dp)
121+
) {
122+
123+
items(sketches) { sketch ->
124+
SketchRow(sketch)
125+
}
126+
}
127+
128+
Row(
129+
modifier = Modifier
130+
.fillMaxWidth()
131+
.padding(8.dp),
132+
horizontalArrangement = Arrangement.spacedBy(8.dp),
133+
verticalAlignment = Alignment.CenterVertically
134+
) {
135+
Button(onClick = { println("Clicked track folder") },
136+
modifier = Modifier
137+
.weight(1f)
138+
.height(48.dp),
139+
contentPadding = PaddingValues(
140+
start = 8.dp, // less left padding (default is 16.dp)
141+
top = 12.dp,
142+
end = 16.dp,
143+
bottom = 12.dp
144+
)
145+
) {
146+
Image(
147+
imageVector = Icons.Outlined.Build,
148+
contentDescription = null,
149+
modifier = Modifier.size(16.dp)
150+
)
151+
Spacer(modifier = Modifier.width(8.dp))
152+
Text("Track Folder")
153+
}
154+
Button(onClick = { println("Clicked add folder") },
155+
modifier = Modifier
156+
.weight(1f)
157+
.height(48.dp),
158+
contentPadding = PaddingValues(
159+
start = 8.dp, // less left padding (default is 16.dp)
160+
top = 12.dp,
161+
end = 16.dp,
162+
bottom = 12.dp
163+
)
164+
) {
165+
Image(
166+
imageVector = Icons.Outlined.AddCircle,
167+
contentDescription = null,
168+
modifier = Modifier.size(16.dp)
169+
)
170+
Spacer(modifier = Modifier.width(8.dp))
171+
Text("New Folder")
172+
}
173+
}
174+
}
175+
}
176+
177+
@Composable
178+
fun SketchRow(sketch: SketchItem) {
179+
Row(
180+
modifier = Modifier
181+
.fillMaxWidth()
182+
.padding(4.dp)
183+
.clickable { println("Clicked on ${sketch.name}") },
184+
verticalAlignment = Alignment.CenterVertically
185+
) {
186+
val icon: ImageVector = if (sketch.isFolder) Icons.Outlined.MailOutline else Icons.Outlined.Face
187+
Image(
188+
imageVector = icon,
189+
contentDescription = null,
190+
modifier = Modifier.size(24.dp)
191+
)
192+
Spacer(modifier = Modifier.width(8.dp))
193+
Text(text = sketch.name)
194+
}
195+
}
196+
197+
@Composable
198+
fun MainSketchGrid(
199+
sketches: List<SketchItem>,
200+
selectedFolder: String?,
201+
searchQuery: String,
202+
sortOption: String,
203+
onSortChange: (String) -> Unit
204+
) {
205+
val displayedHeader = when {
206+
selectedFolder != null -> selectedFolder
207+
searchQuery.isNotBlank() -> "Search results for \"$searchQuery\""
208+
else -> "All Sketches"
209+
}
210+
211+
var expanded by remember { mutableStateOf(false) }
212+
213+
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
214+
Text(
215+
text = displayedHeader,
216+
style = MaterialTheme.typography.h5,
217+
modifier = Modifier.padding(bottom = 8.dp)
218+
)
219+
220+
Box {
221+
Button(onClick = { expanded = true }) {
222+
Text("Sort by: $sortOption")
223+
}
224+
225+
DropdownMenu(
226+
expanded = expanded,
227+
onDismissRequest = { expanded = false }
228+
) {
229+
DropdownMenuItem(onClick = {
230+
onSortChange("Recently Updated")
231+
expanded = false
232+
}) {
233+
Text("Recently Updated")
234+
}
235+
DropdownMenuItem(onClick = {
236+
onSortChange("Alphabetical")
237+
expanded = false
238+
}) {
239+
Text("Alphabetical")
240+
}
241+
}
242+
}
243+
244+
Spacer(Modifier.height(16.dp))
245+
246+
LazyVerticalGrid(
247+
columns = GridCells.Adaptive(minSize = 160.dp),
248+
modifier = Modifier.fillMaxSize(),
249+
verticalArrangement = Arrangement.spacedBy(16.dp),
250+
horizontalArrangement = Arrangement.spacedBy(16.dp)
251+
) {
252+
item {
253+
AddNewSketchCard()
254+
}
255+
items(sketches) { sketch ->
256+
SketchCard(sketch)
257+
}
258+
}
259+
}
260+
}
261+
262+
@Composable
263+
fun AddNewSketchCard() {
264+
Card(
265+
modifier = Modifier.fillMaxWidth(),//.aspectRatio(1f), // square
266+
elevation = 4.dp
267+
) {
268+
Column(
269+
modifier = Modifier.padding(8.dp)
270+
) {
271+
Box(
272+
modifier = Modifier
273+
.fillMaxWidth()
274+
.height(100.dp).clickable {
275+
println("Clicked to Add New Sketch")
276+
},
277+
contentAlignment = Alignment.Center
278+
) {
279+
Text("+", color = Color.DarkGray)
280+
Icon(
281+
imageVector = Icons.Outlined.Add,
282+
contentDescription = "Add New",
283+
modifier = Modifier.size(32.dp)
284+
)
285+
}
286+
287+
Spacer(Modifier.height(8.dp))
288+
289+
Row(
290+
verticalAlignment = Alignment.CenterVertically,
291+
horizontalArrangement = Arrangement.SpaceBetween,
292+
modifier = Modifier.fillMaxWidth()
293+
) {
294+
Text("Add New", style = MaterialTheme.typography.body1)
295+
}
296+
}
297+
}
298+
}
299+
300+
@Composable
301+
fun SketchCard(sketch: SketchItem) {
302+
Card(
303+
modifier = Modifier.fillMaxWidth().height(160.dp),//.aspectRatio(1f), // square
304+
elevation = 4.dp
305+
) {
306+
Column(
307+
modifier = Modifier.padding(8.dp)
308+
) {
309+
Box(
310+
modifier = Modifier
311+
.fillMaxWidth()
312+
.height(100.dp)
313+
.background(Color.LightGray).clickable {
314+
println("Clicked open ${sketch.name}")
315+
},
316+
contentAlignment = Alignment.Center
317+
) {
318+
Text("Thumbnail", color = Color.DarkGray)
319+
}
320+
321+
Spacer(Modifier.height(8.dp))
322+
323+
Row(
324+
verticalAlignment = Alignment.CenterVertically,
325+
horizontalArrangement = Arrangement.SpaceBetween,
326+
modifier = Modifier.fillMaxWidth()
327+
) {
328+
Text(sketch.name, style = MaterialTheme.typography.body1)
329+
Icon(
330+
imageVector = Icons.Outlined.Info,
331+
contentDescription = "Sketch Info",
332+
modifier = Modifier.size(20.dp).clickable {
333+
println("Clicked info for ${sketch.name}")
334+
}
335+
)
336+
}
337+
}
338+
}
339+
}

0 commit comments

Comments
 (0)