Skip to content

Commit d7a3d3b

Browse files
Merge pull request #49 from gdg-berlin-android/feature/satin-border
Satin Border and Wizardry
2 parents 963aeef + deddbc6 commit d7a3d3b

17 files changed

Lines changed: 1091 additions & 613 deletions

File tree

app/src/main/java/de/berlindroid/zepatch/MainActivity.kt

Lines changed: 5 additions & 396 deletions
Large diffs are not rendered by default.

app/src/main/java/de/berlindroid/zepatch/WizardViewModel.kt

Lines changed: 325 additions & 62 deletions
Large diffs are not rendered by default.

app/src/main/java/de/berlindroid/zepatch/patchable/Demo.kt

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package de.berlindroid.zepatch.patchable
22

33
import androidx.compose.foundation.Image
44
import androidx.compose.foundation.background
5-
import androidx.compose.foundation.border
65
import androidx.compose.foundation.layout.Column
76
import androidx.compose.foundation.layout.Spacer
87
import androidx.compose.foundation.layout.fillMaxWidth
@@ -203,15 +202,7 @@ fun AndyB(
203202
topStartPercent = 0,
204203
topEndPercent = 50,
205204
bottomStartPercent = 50,
206-
bottomEndPercent = 50
207-
)
208-
)
209-
.border(
210-
12.dp, Color.Black, RoundedCornerShape(
211-
topStartPercent = 0,
212-
topEndPercent = 50,
213-
bottomStartPercent = 50,
214-
bottomEndPercent = 50
205+
bottomEndPercent = 0
215206
)
216207
),
217208
) {
@@ -224,7 +215,7 @@ fun AndyB(
224215
fontSize = 64.sp,
225216
style = TextStyle.Default.copy(shadow = Shadow(blurRadius = 12f)),
226217
color = Color.Black,
227-
text = "Andy",
218+
text = "AndyB",
228219
letterSpacing = (-1).sp
229220
)
230221
Spacer(modifier = Modifier.weight(1f))
@@ -242,7 +233,7 @@ fun Emoji(
242233
shouldCapture = shouldCapture,
243234
onBitmap = onBitmap,
244235
) {
245-
Text("💪", fontSize = 48.sp)
236+
Text("💪", fontSize = 180.sp)
246237
}
247238
}
248239

@@ -262,6 +253,24 @@ fun Emoji2(
262253

263254
@Preview
264255
@Composable
265-
fun PreviewDemo() {
256+
fun PreviewAndyA() {
266257
AndyA()
267258
}
259+
260+
@Preview
261+
@Composable
262+
fun PreviewAndyB() {
263+
AndyB()
264+
}
265+
266+
@Preview
267+
@Composable
268+
fun PreviewFlex() {
269+
Emoji()
270+
}
271+
272+
@Preview
273+
@Composable
274+
fun PreviewBerlindroid() {
275+
BerlindroidLogo()
276+
}

app/src/main/java/de/berlindroid/zepatch/ui/BitmapToStitches.kt

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@ import androidx.compose.ui.graphics.asAndroidBitmap
1717
import androidx.compose.ui.tooling.preview.Preview
1818
import com.embroidermodder.punching.Histogram
1919
import com.embroidermodder.punching.colorHistogram
20+
import de.berlindroid.zepatch.WizardViewModel.UiState.SetupEmbroidery
21+
import de.berlindroid.zepatch.isBusy
2022

2123
@Composable
2224
fun BitmapToStitches(
2325
modifier: Modifier = Modifier,
24-
reducedImageBitmap: ImageBitmap,
25-
reducedHistogram: Histogram,
26-
name: String,
27-
onCreateEmbroidery: (name: String, bitmap: ImageBitmap, histogram: Histogram) -> Unit,
28-
previewImage: ImageBitmap?,
29-
creatingEmbroidery: Boolean,
26+
state: SetupEmbroidery,
27+
onCreateEmbroidery: () -> Unit,
3028
) {
3129
Column(
3230
modifier = modifier.fillMaxSize(),
@@ -38,22 +36,20 @@ fun BitmapToStitches(
3836
helpText = "Turn the reduced bitmap into an embroidery stitch file and preview the result."
3937
)
4038
Image(
41-
bitmap = reducedImageBitmap,
42-
contentDescription = "patch bitmap",
39+
bitmap = state.reducedBitmap,
40+
contentDescription = "reduced bitmap",
4341
modifier = Modifier.fillMaxWidth()
4442
)
45-
Button(onClick = {
46-
onCreateEmbroidery(name, reducedImageBitmap, reducedHistogram)
47-
}) { Text("Generate") }
43+
Button(onClick = onCreateEmbroidery, enabled = !state.isCompleted() && !state.isBusy()) { Text("Generate") }
4844

49-
previewImage?.let {
45+
state.embroideryPreviewImage?.let {
5046
Image(
5147
bitmap = it,
5248
contentDescription = "patch bitmap",
5349
modifier = Modifier.fillMaxWidth()
5450
)
5551
} ?: Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
56-
if (creatingEmbroidery) CircularProgressIndicator()
52+
if (state.currentlyEmbroidering) CircularProgressIndicator()
5753
}
5854
}
5955
}
@@ -64,12 +60,15 @@ fun BitmapToStitchesPreview() {
6460
val imageBitmap = ImageBitmap(width = 100, height = 100)
6561
val histogram = imageBitmap.asAndroidBitmap().colorHistogram()
6662
BitmapToStitches(
67-
reducedImageBitmap = imageBitmap,
68-
reducedHistogram = histogram,
69-
name = "MyPatch",
70-
onCreateEmbroidery = { _, _, _ -> },
71-
previewImage = null,
72-
creatingEmbroidery = false,
63+
state = SetupEmbroidery(
64+
image = imageBitmap,
65+
colorCount = 44,
66+
reducedBitmap = imageBitmap,
67+
reducedHistogram = histogram,
68+
name = "MyPatch",
69+
currentlyEmbroidering = false,
70+
),
71+
onCreateEmbroidery = {},
7372
)
7473
}
7574

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package de.berlindroid.zepatch.ui
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxSize
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.material3.Text
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Alignment
11+
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.text.style.TextAlign
13+
import androidx.compose.ui.unit.sp
14+
import de.berlindroid.zepatch.WizardViewModel.UiState.Done
15+
16+
@Composable
17+
fun Celebration(
18+
modifier: Modifier = Modifier,
19+
state: Done
20+
) {
21+
Column(
22+
modifier = modifier.fillMaxSize(),
23+
verticalArrangement = Arrangement.Center,
24+
horizontalAlignment = Alignment.CenterHorizontally,
25+
) {
26+
WizardSectionTitle(
27+
title = "Done!",
28+
helpText = "You have successfully completed a patch. Congratulations and now give your self a pat on the back."
29+
)
30+
Image(
31+
bitmap = state.embroideryPreviewImage,
32+
contentDescription = "reduced bitmap",
33+
modifier = Modifier.fillMaxWidth()
34+
)
35+
36+
if (state.error.isNullOrBlank()) {
37+
// TODO @ DROIDCON -> MAKE FANCY HURRAY ANIMATION
38+
Text(
39+
modifier = Modifier.fillMaxWidth(),
40+
text = "🎉",
41+
fontSize = 300.sp,
42+
textAlign = TextAlign.Center
43+
)
44+
Text(
45+
modifier = Modifier.fillMaxWidth(),
46+
text = "Patch '${state.name}' seems to have saved successfully!"
47+
)
48+
} else {
49+
Text(
50+
modifier = Modifier.fillMaxWidth(),
51+
text = "🥺",
52+
fontSize = 300.sp,
53+
textAlign = TextAlign.Center,
54+
)
55+
Text(
56+
modifier = Modifier.fillMaxWidth(),
57+
text = "Error in '${state.name}': ${state.error}."
58+
)
59+
}
60+
}
61+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package de.berlindroid.zepatch.ui
2+
3+
import androidx.activity.compose.rememberLauncherForActivityResult
4+
import androidx.activity.result.contract.ActivityResultContracts
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.foundation.rememberScrollState
8+
import androidx.compose.foundation.verticalScroll
9+
import androidx.compose.material.icons.Icons
10+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
11+
import androidx.compose.material3.ExperimentalMaterial3Api
12+
import androidx.compose.material3.Icon
13+
import androidx.compose.material3.IconButton
14+
import androidx.compose.material3.Scaffold
15+
import androidx.compose.material3.Text
16+
import androidx.compose.material3.TopAppBar
17+
import androidx.compose.runtime.Composable
18+
import androidx.compose.runtime.LaunchedEffect
19+
import androidx.compose.runtime.getValue
20+
import androidx.compose.ui.Modifier
21+
import androidx.compose.ui.graphics.ImageBitmap
22+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
23+
import androidx.lifecycle.viewmodel.compose.viewModel
24+
import de.berlindroid.zepatch.WizardViewModel
25+
import de.berlindroid.zepatch.WizardViewModel.UiState.SetupEmbroidery
26+
27+
@ExperimentalMaterial3Api
28+
@Composable
29+
fun PatchableDetail(
30+
modifier: Modifier = Modifier,
31+
name: String,
32+
onBackClick: () -> Unit,
33+
patchable: @Composable (Boolean, (ImageBitmap) -> Unit) -> Unit,
34+
) {
35+
val viewModel: WizardViewModel = viewModel()
36+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
37+
38+
// Once we SAFed a file, we should fill it
39+
val launcher = rememberLauncherForActivityResult(
40+
contract = ActivityResultContracts.StartActivityForResult()
41+
) { result ->
42+
viewModel.savePesAfterSelection(result)
43+
}
44+
45+
// Reset wizard state when a different patchable is opened
46+
LaunchedEffect(name) {
47+
viewModel.setPatchableNameAndStart(name)
48+
}
49+
50+
LaunchedEffect(uiState) {
51+
if (uiState is SetupEmbroidery) {
52+
viewModel.setLauncher(launcher)
53+
}
54+
}
55+
56+
Scaffold(
57+
modifier = modifier,
58+
topBar = {
59+
TopAppBar(
60+
navigationIcon = {
61+
IconButton(onClick = {
62+
viewModel.reset()
63+
onBackClick()
64+
}) {
65+
Icon(
66+
imageVector = Icons.AutoMirrored.Default.ArrowBack,
67+
contentDescription = "back",
68+
)
69+
}
70+
},
71+
title = {
72+
Text(name)
73+
},
74+
)
75+
},
76+
) { innerPadding ->
77+
val scrollState = rememberScrollState()
78+
79+
Column(
80+
modifier = Modifier
81+
.padding(innerPadding)
82+
.verticalScroll(scrollState)
83+
) {
84+
WizardContent(
85+
uiState,
86+
patchable = patchable,
87+
onBitmapUpdated = viewModel::updateBitmap,
88+
onColorCountUpdated = viewModel::updateColorCount,
89+
onComputeReducedBitmap = viewModel::computeReducedBitmap,
90+
onCreateEmbroidery = viewModel::createEmbroidery,
91+
)
92+
93+
WizardProgress(
94+
state = uiState,
95+
onPrev = viewModel::onBackPressed,
96+
onNext = {
97+
if (viewModel.isStateCompleted()) {
98+
viewModel.progressToNextState()
99+
}
100+
},
101+
onDone = {
102+
viewModel.reset()
103+
onBackClick()
104+
}
105+
)
106+
}
107+
}
108+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package de.berlindroid.zepatch.ui
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.WindowInsets
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.height
10+
import androidx.compose.foundation.layout.navigationBars
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.windowInsetsBottomHeight
13+
import androidx.compose.foundation.lazy.LazyColumn
14+
import androidx.compose.foundation.lazy.items
15+
import androidx.compose.material.icons.Icons
16+
import androidx.compose.material.icons.automirrored.filled.ArrowForward
17+
import androidx.compose.material3.Card
18+
import androidx.compose.material3.Icon
19+
import androidx.compose.material3.Text
20+
import androidx.compose.runtime.Composable
21+
import androidx.compose.ui.Modifier
22+
import androidx.compose.ui.unit.dp
23+
import de.berlindroid.zepatch.patchables
24+
25+
@Composable
26+
fun PatchableList(
27+
modifier: Modifier = Modifier,
28+
onItemClicked: (name: String) -> Unit,
29+
) {
30+
LazyColumn(
31+
modifier = modifier,
32+
verticalArrangement = Arrangement.spacedBy(8.dp),
33+
) {
34+
items(
35+
items = patchables.toList(),
36+
key = { it.first },
37+
) { (name, patchable) ->
38+
Card(
39+
modifier = Modifier.fillMaxWidth(),
40+
onClick = { onItemClicked(name) },
41+
) {
42+
Column(
43+
modifier = Modifier.padding(8.dp)
44+
) {
45+
Row(
46+
modifier = Modifier.fillMaxWidth(),
47+
horizontalArrangement = Arrangement.SpaceBetween,
48+
) {
49+
Text(name)
50+
Icon(
51+
imageVector = Icons.AutoMirrored.Filled.ArrowForward,
52+
contentDescription = "TODO",
53+
)
54+
}
55+
Box(Modifier.height(4.dp))
56+
Row(
57+
modifier = Modifier.fillMaxWidth(),
58+
horizontalArrangement = Arrangement.Center
59+
) {
60+
PatchableBoundingBox(patchable = patchable)
61+
}
62+
}
63+
}
64+
}
65+
item(key = "navigationBar") {
66+
Box(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)