Skip to content

Commit 6a8be2f

Browse files
authored
Merge pull request #106 from Code-Kotliners-Inc/create-text-fix
create screen finally fixed
2 parents 3506d50 + f08c2a6 commit 6a8be2f

9 files changed

Lines changed: 155 additions & 345 deletions

File tree

app/src/main/java/com/codekotliners/memify/features/create/presentation/ui/CreateScreen.kt

Lines changed: 74 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@ package com.codekotliners.memify.features.create.presentation.ui
22

33
import android.content.Intent
44
import androidx.compose.animation.AnimatedVisibility
5+
import androidx.compose.animation.core.animateFloatAsState
56
import androidx.compose.foundation.Image
67
import androidx.compose.foundation.background
78
import androidx.compose.foundation.clickable
89
import androidx.compose.foundation.gestures.rememberTransformableState
910
import androidx.compose.foundation.gestures.transformable
10-
import androidx.compose.foundation.layout.Arrangement
1111
import androidx.compose.foundation.layout.Box
1212
import androidx.compose.foundation.layout.Column
1313
import androidx.compose.foundation.layout.PaddingValues
14-
import androidx.compose.foundation.layout.Row
1514
import androidx.compose.foundation.layout.Spacer
1615
import androidx.compose.foundation.layout.WindowInsets
1716
import androidx.compose.foundation.layout.aspectRatio
@@ -20,9 +19,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
2019
import androidx.compose.foundation.layout.height
2120
import androidx.compose.foundation.layout.padding
2221
import androidx.compose.foundation.layout.size
22+
import androidx.compose.foundation.layout.wrapContentHeight
2323
import androidx.compose.foundation.layout.wrapContentSize
24-
import androidx.compose.foundation.lazy.LazyColumn
25-
import androidx.compose.foundation.shape.CircleShape
2624
import androidx.compose.foundation.shape.RoundedCornerShape
2725
import androidx.compose.material.icons.Icons
2826
import androidx.compose.material.icons.filled.KeyboardArrowDown
@@ -58,7 +56,6 @@ import androidx.compose.runtime.setValue
5856
import androidx.compose.ui.Alignment
5957
import androidx.compose.ui.Modifier
6058
import androidx.compose.ui.draw.drawWithContent
61-
import androidx.compose.ui.geometry.Offset
6259
import androidx.compose.ui.graphics.Color
6360
import androidx.compose.ui.graphics.ImageBitmap
6461
import androidx.compose.ui.graphics.asAndroidBitmap
@@ -68,7 +65,6 @@ import androidx.compose.ui.graphics.layer.drawLayer
6865
import androidx.compose.ui.graphics.rememberGraphicsLayer
6966
import androidx.compose.ui.layout.ContentScale
7067
import androidx.compose.ui.platform.LocalContext
71-
import androidx.compose.ui.res.painterResource
7268
import androidx.compose.ui.res.stringResource
7369
import androidx.compose.ui.text.font.Font
7470
import androidx.compose.ui.text.font.FontFamily
@@ -87,7 +83,6 @@ import com.codekotliners.memify.core.ui.components.AppScaffold
8783
import com.codekotliners.memify.features.create.presentation.ui.components.ActionsRow
8884
import com.codekotliners.memify.features.create.presentation.ui.components.DrawingRow
8985
import com.codekotliners.memify.features.create.presentation.ui.components.EditingCanvasElements
90-
import com.codekotliners.memify.features.create.presentation.ui.components.InstrumentsTextBox
9186
import com.codekotliners.memify.features.create.presentation.ui.components.TextEditingRow
9287
import com.codekotliners.memify.features.create.presentation.ui.components.TextInputDialog
9388
import com.codekotliners.memify.features.create.presentation.viewmodel.CanvasViewModel
@@ -181,15 +176,21 @@ private fun CreateScreenBottomSheet(
181176
val bitmapState = remember { mutableStateOf<ImageBitmap?>(null) }
182177
val isPublishing by viewModelViewer.isPublishing.collectAsState()
183178

179+
var scale by remember { mutableFloatStateOf(1f) }
180+
184181
BottomSheetScaffold(
185182
topBar = {
186183
CreateScreenTopBar(
187184
scrollBehavior,
188185
onMenuClick = {
189-
coroutineScope.launch {
190-
showImageViewer.value = true
191-
val bitmapCompose = graphicsLayer.toImageBitmap()
192-
bitmapState.value = bitmapCompose
186+
if (scale == 1f) {
187+
coroutineScope.launch {
188+
showImageViewer.value = true
189+
val bitmapCompose = graphicsLayer.toImageBitmap()
190+
bitmapState.value = bitmapCompose
191+
}
192+
} else {
193+
scale = 1f
193194
}
194195
},
195196
)
@@ -206,13 +207,20 @@ private fun CreateScreenBottomSheet(
206207
coroutineScope.launch {
207208
bottomSheetState.partialExpand()
208209
}
210+
viewModel.clearCanvas()
209211
},
210212
)
211213
},
212214
sheetPeekHeight = 58.dp,
213215
sheetSwipeEnabled = true,
214216
) { innerPadding ->
215-
CreateScreenContent(innerPadding, viewModel, graphicsLayer)
217+
CreateScreenContent(
218+
innerPadding,
219+
viewModel,
220+
graphicsLayer,
221+
scale,
222+
onScaleChange = { newScale -> scale = newScale },
223+
)
216224

217225
if (showImageViewer.value && bitmapState.value != null) {
218226
ImagePreviewDialog(
@@ -342,20 +350,22 @@ private fun CreateScreenTopBar(scrollBehavior: TopAppBarScrollBehavior, onMenuCl
342350
}
343351

344352
@Composable
345-
private fun CreateScreenContent(innerPadding: PaddingValues, viewModel: CanvasViewModel, graphicsLayer: GraphicsLayer) {
346-
LazyColumn(
353+
private fun CreateScreenContent(
354+
innerPadding: PaddingValues,
355+
viewModel: CanvasViewModel,
356+
graphicsLayer: GraphicsLayer,
357+
scale: Float,
358+
onScaleChange: (Float) -> Unit,
359+
) {
360+
Column(
347361
modifier =
348362
Modifier
349363
.fillMaxSize()
350364
.padding(innerPadding)
351365
.background(MaterialTheme.colorScheme.background),
352366
horizontalAlignment = Alignment.CenterHorizontally,
353-
contentPadding = PaddingValues(bottom = 80.dp),
354367
) {
355-
item { ActionsRow(viewModel) }
356-
item {
357-
InteractiveCanvas(viewModel, graphicsLayer)
358-
}
368+
InteractiveCanvas(viewModel, graphicsLayer, scale, onScaleChange)
359369
}
360370
}
361371

@@ -385,7 +395,12 @@ fun BottomSheetHandle(bottomSheetState: SheetState) {
385395
}
386396

387397
@Composable
388-
private fun InteractiveCanvas(viewModel: CanvasViewModel, graphicsLayer: GraphicsLayer) {
398+
private fun InteractiveCanvas(
399+
viewModel: CanvasViewModel,
400+
graphicsLayer: GraphicsLayer,
401+
scale: Float,
402+
onScaleChange: (Float) -> Unit,
403+
) {
389404
val context = LocalContext.current
390405
val painter =
391406
rememberAsyncImagePainter(
@@ -405,107 +420,32 @@ private fun InteractiveCanvas(viewModel: CanvasViewModel, graphicsLayer: Graphic
405420
}
406421
}
407422

408-
Column(
409-
modifier = Modifier.fillMaxWidth(),
410-
horizontalAlignment = Alignment.CenterHorizontally,
411-
verticalArrangement = Arrangement.spacedBy(10.dp),
412-
) {
413-
Tools(viewModel)
414-
415-
ImageBox(viewModel, graphicsLayer, painter)
416-
417-
if (viewModel.showTextInput) {
418-
TextInputDialog(viewModel)
419-
}
420-
421-
AnimatedVisibility(
422-
visible = (viewModel.isPaintingEnabled == false && viewModel.isWritingEnabled == false),
423-
) {
424-
InstrumentsTextBox()
425-
}
426-
427-
AnimatedVisibility(visible = viewModel.isPaintingEnabled) {
428-
DrawingRow(viewModel)
429-
}
430-
431-
AnimatedVisibility(visible = viewModel.isWritingEnabled) {
432-
TextEditingRow(viewModel)
433-
}
434-
}
435-
}
436-
437-
@Composable
438-
private fun Tools(viewModel: CanvasViewModel) {
439-
Row(
440-
modifier =
441-
Modifier
442-
.padding(16.dp)
443-
.background(MaterialTheme.colorScheme.surface, CircleShape)
444-
.padding(8.dp),
445-
horizontalArrangement = Arrangement.spacedBy(8.dp),
423+
Box(
424+
modifier = Modifier.fillMaxSize(),
446425
) {
447-
// Состояния
448-
val isPaintSelected = viewModel.isPaintingEnabled
449-
val isWriteSelected = viewModel.isWritingEnabled
450-
451-
// Кнопка Paint
452-
IconButton(
453-
onClick = {
454-
viewModel.isPaintingEnabled = !viewModel.isPaintingEnabled
455-
viewModel.isWritingEnabled = false
456-
},
457-
modifier =
458-
Modifier
459-
.size(48.dp)
460-
.background(
461-
if (isPaintSelected) {
462-
MaterialTheme.colorScheme.primary
463-
} else {
464-
MaterialTheme.colorScheme.background
465-
},
466-
CircleShape,
467-
),
468-
) {
469-
Icon(
470-
painter = painterResource(R.drawable.baseline_brush_24),
471-
contentDescription = "Paint",
472-
tint =
473-
if (isPaintSelected) {
474-
MaterialTheme.colorScheme.onPrimary
475-
} else {
476-
MaterialTheme.colorScheme.onSurface
477-
},
478-
)
479-
}
426+
Box(
427+
modifier = Modifier.fillMaxSize(),
428+
contentAlignment = Alignment.Center,
429+
) { ImageBox(viewModel, graphicsLayer, painter, scale, onScaleChange) }
480430

481-
// Кнопка Write
482-
IconButton(
483-
onClick = {
484-
viewModel.isWritingEnabled = !viewModel.isWritingEnabled
485-
viewModel.isPaintingEnabled = false
486-
},
431+
Column(
487432
modifier =
488433
Modifier
489-
.size(48.dp)
490-
.background(
491-
if (isWriteSelected) {
492-
MaterialTheme.colorScheme.primary
493-
} else {
494-
MaterialTheme.colorScheme.background
495-
},
496-
CircleShape,
497-
),
434+
.align(Alignment.TopCenter)
435+
.fillMaxWidth()
436+
.wrapContentHeight(),
437+
horizontalAlignment = Alignment.CenterHorizontally,
498438
) {
499-
Icon(
500-
painter = painterResource(R.drawable.round_text_fields_24),
501-
contentDescription = "Write",
502-
tint =
503-
if (isWriteSelected) {
504-
MaterialTheme.colorScheme.onPrimary
505-
} else {
506-
MaterialTheme.colorScheme.onSurface
507-
},
508-
)
439+
ActionsRow(viewModel)
440+
AnimatedVisibility(visible = viewModel.isWritingEnabled) {
441+
TextEditingRow(viewModel)
442+
}
443+
AnimatedVisibility(visible = viewModel.isPaintingEnabled) {
444+
DrawingRow(viewModel)
445+
}
446+
if (viewModel.showTextInput) {
447+
TextInputDialog(viewModel)
448+
}
509449
}
510450
}
511451
}
@@ -515,46 +455,43 @@ private fun ImageBox(
515455
viewModel: CanvasViewModel,
516456
graphicsLayer: GraphicsLayer,
517457
painter: AsyncImagePainter,
458+
scale: Float,
459+
onScaleChange: (Float) -> Unit,
518460
) {
519-
var scale by remember { mutableFloatStateOf(1f) }
520-
var angle by remember { mutableFloatStateOf(0f) }
521-
var offset by remember { mutableStateOf(Offset.Zero) }
461+
val animatedScale = animateFloatAsState(targetValue = scale)
522462
val state =
523-
rememberTransformableState { scaleChange, offsetChange, rotationChange ->
524-
scale *= scaleChange
525-
angle += rotationChange
526-
offset += offsetChange
463+
rememberTransformableState { scaleChange, _, _ ->
464+
onScaleChange(scale * scaleChange)
465+
}
466+
467+
val aspectRatio =
468+
if (viewModel.imageWidth > 0 && viewModel.imageHeight > 0) {
469+
viewModel.imageWidth / viewModel.imageHeight
470+
} else {
471+
1f
527472
}
528473

529474
Box(
530475
modifier =
531476
Modifier
532477
.fillMaxWidth()
533-
.aspectRatio(
534-
if (viewModel.imageWidth > 0 && viewModel.imageHeight > 0) {
535-
viewModel.imageWidth / viewModel.imageHeight
536-
} else {
537-
// Дефолтное соотношение, пока не загрузилось
538-
1f
539-
},
540-
).padding(4.dp)
478+
.aspectRatio(aspectRatio)
479+
.padding(4.dp)
541480
.drawWithContent {
542481
graphicsLayer.record {
543482
this@drawWithContent.drawContent()
544483
}
545484
drawLayer(graphicsLayer)
546-
}.then(
485+
}.clickable(onClick = { onScaleChange(1f) })
486+
.then(
547487
if (viewModel.isWritingEnabled) {
548488
Modifier.clickable(onClick = { viewModel.startWriting() })
549489
} else {
550490
Modifier
551491
},
552492
).graphicsLayer(
553-
scaleX = scale,
554-
scaleY = scale,
555-
rotationZ = angle,
556-
translationX = offset.x,
557-
translationY = offset.y,
493+
scaleX = animatedScale.value,
494+
scaleY = animatedScale.value,
558495
).transformable(state = state),
559496
) {
560497
Image(

0 commit comments

Comments
 (0)