From 15ad27bf512eb76cca67418cabf1fec59c167252 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Thu, 29 Aug 2024 12:33:59 +0300 Subject: [PATCH 1/9] experiments --- .../main/java/io/artmaker/actions/DrawEvent.kt | 2 +- .../artmaker/composables/ArtMakerDrawScreen.kt | 14 +++++++++++--- .../java/io/artmaker/export/DrawingManager.kt | 16 +++++++++++----- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt index cb7f639f..30baa325 100644 --- a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt +++ b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.geometry.Offset * Events that happen during drawing */ sealed interface DrawEvent { - data class AddNewShape(val offset: Offset) : DrawEvent + data class AddNewShape(val offset: Offset, val pressure: Float) : DrawEvent data class UpdateCurrentShape(val offset: Offset) : DrawEvent data object UndoLastShapePoint : DrawEvent data object Undo : DrawEvent diff --git a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt index d3741cb2..5539e498 100644 --- a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt +++ b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt @@ -109,6 +109,8 @@ internal fun ArtMakerDrawScreen( val graphicsLayer = rememberGraphicsLayer() val snackbarHostState = remember { SnackbarHostState() } + var isDrawing by remember { mutableStateOf(false) } + val writeStorageAccessState = rememberMultiplePermissionsState( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // No permissions are needed on Android 10+ to add files in the shared storage @@ -159,6 +161,7 @@ internal fun ArtMakerDrawScreen( } .pointerInteropFilter { event -> val offset = Offset(event.x, event.y) + val pressure = event.getPressure(event.actionIndex) when (event.action) { MotionEvent.ACTION_DOWN -> { getDialogType(context, event, state.shouldUseStylusOnly)?.let { type -> @@ -167,17 +170,20 @@ internal fun ArtMakerDrawScreen( } if (!event.validateEvent(context, state.shouldUseStylusOnly)) return@pointerInteropFilter false - - onDrawEvent(DrawEvent.AddNewShape(offset)) + isDrawing = true + onDrawEvent(DrawEvent.AddNewShape(offset, pressure)) } MotionEvent.ACTION_MOVE -> { + isDrawing = true val clampedOffset = Offset(x = offset.x, y = clamp(offset.y, 0f, maxDrawingHeight)) - onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset)) + onDrawEvent(DrawEvent.AddNewShape(clampedOffset, pressure)) +// onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset)) } MotionEvent.ACTION_CANCEL -> { + isDrawing = false onDrawEvent(DrawEvent.UndoLastShapePoint) } } @@ -193,7 +199,9 @@ internal fun ArtMakerDrawScreen( size = Size(bitmapWidth.toFloat(), bitmapHeight.toFloat()), ) } + state.pathList.forEach { data -> + println("Points ------------------ ${data.points.joinToString()}") drawPoints( points = data.points, pointMode = if (data.points.size == 1) PointMode.Points else PointMode.Polygon, // Draw a point if the shape has only one item otherwise a free flowing shape diff --git a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt index b978afb8..d5a4f946 100644 --- a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt +++ b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt @@ -38,9 +38,11 @@ internal class DrawingManager { private val _undoRedoState = MutableStateFlow(UndoRedoState()) val undoRedoState: StateFlow = _undoRedoState + private var finalOffset: Offset? = null + fun onDrawEvent(event: DrawEvent, strokeColor: Int, strokeWidth: Int) { when (event) { - is DrawEvent.AddNewShape -> addNewShape(event.offset, strokeColor, strokeWidth) + is DrawEvent.AddNewShape -> addNewShape(event.offset, strokeColor, strokeWidth, event.pressure) DrawEvent.UndoLastShapePoint -> undoLastShapePoint() is DrawEvent.UpdateCurrentShape -> updateCurrentShape(event.offset) DrawEvent.Clear -> clear() @@ -49,19 +51,23 @@ internal class DrawingManager { } } - private fun addNewShape(offset: Offset, strokeColor: Int, strokeWidth: Int) { + private fun addNewShape(offset: Offset, strokeColor: Int, strokeWidth: Int, pressure: Float) { + val oft = if (finalOffset == null) offset.plus(Offset(0f, 0f)) else finalOffset!! val data = PointsData( - points = mutableStateListOf(offset), + points = mutableStateListOf(offset, oft), strokeColor = Color(strokeColor), strokeWidth = strokeWidth.toFloat(), + alpha = pressure, ) + + finalOffset = offset _pathList.add(data) _undoRedoState.update { computeUndoRedoState() } } private fun updateCurrentShape(offset: Offset) { - val idx = _pathList.lastIndex - _pathList[idx].points.add(offset) +// val idx = _pathList.lastIndex +// _pathList[idx].points.add(offset) } private fun undoLastShapePoint() { From deb617269ec40eca829ec51bb0daf72e3408af76 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 12:18:20 +0300 Subject: [PATCH 2/9] set pressure on individual shapes from start to end --- .../java/io/artmaker/composables/ArtMakerDrawScreen.kt | 4 +--- .../src/main/java/io/artmaker/export/DrawingManager.kt | 7 +++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt index 5539e498..35b04813 100644 --- a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt +++ b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt @@ -178,8 +178,7 @@ internal fun ArtMakerDrawScreen( isDrawing = true val clampedOffset = Offset(x = offset.x, y = clamp(offset.y, 0f, maxDrawingHeight)) - onDrawEvent(DrawEvent.AddNewShape(clampedOffset, pressure)) -// onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset)) + onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset)) } MotionEvent.ACTION_CANCEL -> { @@ -201,7 +200,6 @@ internal fun ArtMakerDrawScreen( } state.pathList.forEach { data -> - println("Points ------------------ ${data.points.joinToString()}") drawPoints( points = data.points, pointMode = if (data.points.size == 1) PointMode.Points else PointMode.Polygon, // Draw a point if the shape has only one item otherwise a free flowing shape diff --git a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt index d5a4f946..4fb5a212 100644 --- a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt +++ b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt @@ -52,9 +52,8 @@ internal class DrawingManager { } private fun addNewShape(offset: Offset, strokeColor: Int, strokeWidth: Int, pressure: Float) { - val oft = if (finalOffset == null) offset.plus(Offset(0f, 0f)) else finalOffset!! val data = PointsData( - points = mutableStateListOf(offset, oft), + points = mutableStateListOf(offset), strokeColor = Color(strokeColor), strokeWidth = strokeWidth.toFloat(), alpha = pressure, @@ -66,8 +65,8 @@ internal class DrawingManager { } private fun updateCurrentShape(offset: Offset) { -// val idx = _pathList.lastIndex -// _pathList[idx].points.add(offset) + val idx = _pathList.lastIndex + _pathList[idx].points.add(offset) } private fun undoLastShapePoint() { From 7ea2050d09facc29b43e1ba16075bd706b5de998 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 12:27:21 +0300 Subject: [PATCH 3/9] remove is drawing variable --- .../main/java/io/artmaker/composables/ArtMakerDrawScreen.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt index 35b04813..fe33f2c0 100644 --- a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt +++ b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt @@ -109,8 +109,6 @@ internal fun ArtMakerDrawScreen( val graphicsLayer = rememberGraphicsLayer() val snackbarHostState = remember { SnackbarHostState() } - var isDrawing by remember { mutableStateOf(false) } - val writeStorageAccessState = rememberMultiplePermissionsState( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // No permissions are needed on Android 10+ to add files in the shared storage @@ -170,19 +168,16 @@ internal fun ArtMakerDrawScreen( } if (!event.validateEvent(context, state.shouldUseStylusOnly)) return@pointerInteropFilter false - isDrawing = true onDrawEvent(DrawEvent.AddNewShape(offset, pressure)) } MotionEvent.ACTION_MOVE -> { - isDrawing = true val clampedOffset = Offset(x = offset.x, y = clamp(offset.y, 0f, maxDrawingHeight)) onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset)) } MotionEvent.ACTION_CANCEL -> { - isDrawing = false onDrawEvent(DrawEvent.UndoLastShapePoint) } } From 50de1ebe3a73ede882e91ec7fb41f13764473779 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 13:39:34 +0300 Subject: [PATCH 4/9] use average pressure to draw the points --- artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt | 2 +- .../java/io/artmaker/composables/ArtMakerDrawScreen.kt | 4 ++-- .../src/main/java/io/artmaker/export/DrawingManager.kt | 7 ++++--- artmaker/src/main/java/io/artmaker/models/PointsData.kt | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt index 30baa325..042b642c 100644 --- a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt +++ b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.geometry.Offset */ sealed interface DrawEvent { data class AddNewShape(val offset: Offset, val pressure: Float) : DrawEvent - data class UpdateCurrentShape(val offset: Offset) : DrawEvent + data class UpdateCurrentShape(val offset: Offset, val pressure: Float) : DrawEvent data object UndoLastShapePoint : DrawEvent data object Undo : DrawEvent data object Redo : DrawEvent diff --git a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt index fe33f2c0..6d97abc1 100644 --- a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt +++ b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt @@ -174,7 +174,7 @@ internal fun ArtMakerDrawScreen( MotionEvent.ACTION_MOVE -> { val clampedOffset = Offset(x = offset.x, y = clamp(offset.y, 0f, maxDrawingHeight)) - onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset)) + onDrawEvent(DrawEvent.UpdateCurrentShape(clampedOffset, pressure)) } MotionEvent.ACTION_CANCEL -> { @@ -199,8 +199,8 @@ internal fun ArtMakerDrawScreen( points = data.points, pointMode = if (data.points.size == 1) PointMode.Points else PointMode.Polygon, // Draw a point if the shape has only one item otherwise a free flowing shape color = data.strokeColor, + alpha = data.alphas.average().coerceAtLeast(0.0).coerceAtMost(255.0).toFloat(), strokeWidth = data.strokeWidth, - alpha = data.alpha, ) } } diff --git a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt index 4fb5a212..c5c22e44 100644 --- a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt +++ b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt @@ -44,7 +44,7 @@ internal class DrawingManager { when (event) { is DrawEvent.AddNewShape -> addNewShape(event.offset, strokeColor, strokeWidth, event.pressure) DrawEvent.UndoLastShapePoint -> undoLastShapePoint() - is DrawEvent.UpdateCurrentShape -> updateCurrentShape(event.offset) + is DrawEvent.UpdateCurrentShape -> updateCurrentShape(event.offset, event.pressure) DrawEvent.Clear -> clear() DrawEvent.Redo -> redo() DrawEvent.Undo -> undo() @@ -56,7 +56,7 @@ internal class DrawingManager { points = mutableStateListOf(offset), strokeColor = Color(strokeColor), strokeWidth = strokeWidth.toFloat(), - alpha = pressure, + alphas = mutableStateListOf(pressure), ) finalOffset = offset @@ -64,9 +64,10 @@ internal class DrawingManager { _undoRedoState.update { computeUndoRedoState() } } - private fun updateCurrentShape(offset: Offset) { + private fun updateCurrentShape(offset: Offset, pressure: Float) { val idx = _pathList.lastIndex _pathList[idx].points.add(offset) + _pathList[idx].alphas.add(pressure) } private fun undoLastShapePoint() { diff --git a/artmaker/src/main/java/io/artmaker/models/PointsData.kt b/artmaker/src/main/java/io/artmaker/models/PointsData.kt index 4ccaa25b..31f8bcb2 100644 --- a/artmaker/src/main/java/io/artmaker/models/PointsData.kt +++ b/artmaker/src/main/java/io/artmaker/models/PointsData.kt @@ -27,5 +27,5 @@ internal data class PointsData( var points: SnapshotStateList, val strokeWidth: Float = 15f, val strokeColor: Color, - val alpha: Float = 1f, + val alphas: MutableList, ) From 76be00d5283802386e6f2d0d33e6bc8a8c9a6fa6 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 13:49:40 +0300 Subject: [PATCH 5/9] cleanup --- artmaker/src/main/java/io/artmaker/export/DrawingManager.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt index c5c22e44..48a3fd89 100644 --- a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt +++ b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt @@ -38,8 +38,6 @@ internal class DrawingManager { private val _undoRedoState = MutableStateFlow(UndoRedoState()) val undoRedoState: StateFlow = _undoRedoState - private var finalOffset: Offset? = null - fun onDrawEvent(event: DrawEvent, strokeColor: Int, strokeWidth: Int) { when (event) { is DrawEvent.AddNewShape -> addNewShape(event.offset, strokeColor, strokeWidth, event.pressure) @@ -59,7 +57,6 @@ internal class DrawingManager { alphas = mutableStateListOf(pressure), ) - finalOffset = offset _pathList.add(data) _undoRedoState.update { computeUndoRedoState() } } From 6f5d95564412d335135b95c094673583e5f4d5a4 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 14:02:50 +0300 Subject: [PATCH 6/9] add pressure detection setting --- .../src/main/java/io/artmaker/ArtMaker.kt | 2 + .../main/java/io/artmaker/ArtMakerUIState.kt | 1 + .../java/io/artmaker/ArtMakerViewModel.kt | 49 +++++++++++++------ .../src/main/java/io/artmaker/DrawState.kt | 1 + .../io/artmaker/actions/ArtMakerAction.kt | 1 + .../java/io/artmaker/actions/DrawEvent.kt | 4 +- .../composables/ArtMakerDrawScreen.kt | 3 +- .../io/artmaker/composables/StrokeSettings.kt | 24 ++++++++- .../java/io/artmaker/data/PreferenceKeys.kt | 12 ++--- .../java/io/artmaker/models/PointsData.kt | 9 ++++ artmaker/src/main/res/values/strings.xml | 1 + 11 files changed, 81 insertions(+), 26 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/ArtMaker.kt b/artmaker/src/main/java/io/artmaker/ArtMaker.kt index 3b778dde..b2209d65 100644 --- a/artmaker/src/main/java/io/artmaker/ArtMaker.kt +++ b/artmaker/src/main/java/io/artmaker/ArtMaker.kt @@ -126,6 +126,7 @@ fun ArtMaker( backgroundImage = viewModel.backgroundImage.value, isFullScreenMode = isFullScreenEnabled, shouldUseStylusOnly = state.shouldUseStylusOnly, + shouldDetectPressure = state.shouldDetectPressure, canShowEnableStylusDialog = state.canShowEnableStylusDialog, canShowDisableStylusDialog = state.canShowDisableStylusDialog, ), @@ -138,6 +139,7 @@ fun ArtMaker( modifier = Modifier .padding(top = dimensionResource(id = R.dimen.Padding8), end = dimensionResource(id = R.dimen.Padding12), start = dimensionResource(id = R.dimen.Padding12)), shouldUseStylusOnly = state.shouldUseStylusOnly, + shouldDetectPressure = state.shouldDetectPressure, ) } AnimatedVisibility(visible = !isFullScreenEnabled) { diff --git a/artmaker/src/main/java/io/artmaker/ArtMakerUIState.kt b/artmaker/src/main/java/io/artmaker/ArtMakerUIState.kt index 2851ab84..0827cc4f 100644 --- a/artmaker/src/main/java/io/artmaker/ArtMakerUIState.kt +++ b/artmaker/src/main/java/io/artmaker/ArtMakerUIState.kt @@ -29,6 +29,7 @@ data class ArtMakerUIState( val canUndo: Boolean = false, val canClear: Boolean = false, val shouldUseStylusOnly: Boolean = false, + val shouldDetectPressure: Boolean = false, val canShowEnableStylusDialog: Boolean = true, val canShowDisableStylusDialog: Boolean = true, ) diff --git a/artmaker/src/main/java/io/artmaker/ArtMakerViewModel.kt b/artmaker/src/main/java/io/artmaker/ArtMakerViewModel.kt index 9adc60c1..24d2b019 100644 --- a/artmaker/src/main/java/io/artmaker/ArtMakerViewModel.kt +++ b/artmaker/src/main/java/io/artmaker/ArtMakerViewModel.kt @@ -34,7 +34,7 @@ import io.artmaker.actions.DrawEvent import io.artmaker.actions.ExportType import io.artmaker.data.ArtMakerSharedPreferences import io.artmaker.data.PreferenceKeys -import io.artmaker.data.PreferenceKeys.SELECTED_STROKE_WIDTH +import io.artmaker.data.PreferenceKeys.PREF_SELECTED_STROKE_WIDTH import io.artmaker.export.DrawingManager import io.artmaker.models.PointsData import io.artmaker.utils.saveToDisk @@ -55,23 +55,27 @@ internal class ArtMakerViewModel( private var _uiState = MutableStateFlow( value = ArtMakerUIState( strokeColour = preferences.get( - key = PreferenceKeys.SELECTED_STROKE_COLOUR, + key = PreferenceKeys.PREF_SELECTED_STROKE_COLOUR, defaultValue = Color.Red.toArgb(), ), strokeWidth = preferences.get( - key = SELECTED_STROKE_WIDTH, + key = PREF_SELECTED_STROKE_WIDTH, defaultValue = 5, ), shouldUseStylusOnly = preferences.get( - key = PreferenceKeys.USE_STYLUS_ONLY, + key = PreferenceKeys.PREF_USE_STYLUS_ONLY, + false, + ), + shouldDetectPressure = preferences.get( + key = PreferenceKeys.PREF_DETECT_PRESSURE, false, ), canShowEnableStylusDialog = preferences.get( - key = PreferenceKeys.SHOW_ENABLE_STYLUS_DIALOG, + key = PreferenceKeys.PREF_SHOW_ENABLE_STYLUS_DIALOG, true, ), canShowDisableStylusDialog = preferences.get( - key = PreferenceKeys.SHOW_DISABLE_STYLUS_DIALOG, + key = PreferenceKeys.PREF_SHOW_DISABLE_STYLUS_DIALOG, true, ), ), @@ -103,6 +107,7 @@ internal class ArtMakerViewModel( is ArtMakerAction.SelectStrokeColour -> updateStrokeColor(colour = action.color) is ArtMakerAction.SetStrokeWidth -> selectStrokeWidth(strokeWidth = action.strokeWidth) is ArtMakerAction.UpdateSetStylusOnly -> updateStylusSetting(useStylusOnly = action.shouldUseStylusOnly) + is ArtMakerAction.UpdateSetPressureDetection -> updatePressureSetting(detectPressure = action.shouldDetectPressure) is ArtMakerAction.UpdateEnableStylusDialogShow -> updateEnableStylusDialog(canShow = action.canShowEnableStylusDialog) is ArtMakerAction.UpdateDisableStylusDialogShow -> updateDisableStylusDialog(canShow = action.canShowDisableStylusDialog) } @@ -141,13 +146,13 @@ internal class ArtMakerViewModel( private fun updateStrokeColor(colour: Color) { preferences.set( - key = PreferenceKeys.SELECTED_STROKE_COLOUR, + key = PreferenceKeys.PREF_SELECTED_STROKE_COLOUR, value = colour.toArgb(), ) _uiState.update { it.copy( strokeColour = preferences.get( - key = PreferenceKeys.SELECTED_STROKE_COLOUR, + key = PreferenceKeys.PREF_SELECTED_STROKE_COLOUR, defaultValue = 0, ), ) @@ -160,13 +165,13 @@ internal class ArtMakerViewModel( private fun selectStrokeWidth(strokeWidth: Int) { preferences.set( - key = SELECTED_STROKE_WIDTH, + key = PREF_SELECTED_STROKE_WIDTH, value = strokeWidth, ) _uiState.update { it.copy( strokeWidth = preferences.get( - SELECTED_STROKE_WIDTH, + PREF_SELECTED_STROKE_WIDTH, defaultValue = 5, ), ) @@ -174,11 +179,23 @@ internal class ArtMakerViewModel( } private fun updateStylusSetting(useStylusOnly: Boolean) { - preferences.set(PreferenceKeys.USE_STYLUS_ONLY, useStylusOnly) + preferences.set(PreferenceKeys.PREF_USE_STYLUS_ONLY, useStylusOnly) _uiState.update { it.copy( shouldUseStylusOnly = preferences.get( - key = PreferenceKeys.USE_STYLUS_ONLY, + key = PreferenceKeys.PREF_USE_STYLUS_ONLY, + false, + ), + ) + } + } + + private fun updatePressureSetting(detectPressure: Boolean) { + preferences.set(PreferenceKeys.PREF_DETECT_PRESSURE, detectPressure) + _uiState.update { + it.copy( + shouldDetectPressure = preferences.get( + key = PreferenceKeys.PREF_DETECT_PRESSURE, false, ), ) @@ -186,11 +203,11 @@ internal class ArtMakerViewModel( } private fun updateEnableStylusDialog(canShow: Boolean) { - preferences.set(PreferenceKeys.SHOW_ENABLE_STYLUS_DIALOG, canShow) + preferences.set(PreferenceKeys.PREF_SHOW_ENABLE_STYLUS_DIALOG, canShow) _uiState.update { it.copy( canShowEnableStylusDialog = preferences.get( - key = PreferenceKeys.SHOW_ENABLE_STYLUS_DIALOG, + key = PreferenceKeys.PREF_SHOW_ENABLE_STYLUS_DIALOG, true, ), ) @@ -198,11 +215,11 @@ internal class ArtMakerViewModel( } private fun updateDisableStylusDialog(canShow: Boolean) { - preferences.set(PreferenceKeys.SHOW_DISABLE_STYLUS_DIALOG, canShow) + preferences.set(PreferenceKeys.PREF_SHOW_DISABLE_STYLUS_DIALOG, canShow) _uiState.update { it.copy( canShowDisableStylusDialog = preferences.get( - key = PreferenceKeys.SHOW_DISABLE_STYLUS_DIALOG, + key = PreferenceKeys.PREF_SHOW_DISABLE_STYLUS_DIALOG, true, ), ) diff --git a/artmaker/src/main/java/io/artmaker/DrawState.kt b/artmaker/src/main/java/io/artmaker/DrawState.kt index f17eb36f..1d3916da 100644 --- a/artmaker/src/main/java/io/artmaker/DrawState.kt +++ b/artmaker/src/main/java/io/artmaker/DrawState.kt @@ -28,6 +28,7 @@ internal data class DrawState( val shouldTriggerArtExport: Boolean, val isFullScreenMode: Boolean, val shouldUseStylusOnly: Boolean, + val shouldDetectPressure: Boolean, val canShowEnableStylusDialog: Boolean, val canShowDisableStylusDialog: Boolean, ) diff --git a/artmaker/src/main/java/io/artmaker/actions/ArtMakerAction.kt b/artmaker/src/main/java/io/artmaker/actions/ArtMakerAction.kt index 080fdd05..02eef5ca 100644 --- a/artmaker/src/main/java/io/artmaker/actions/ArtMakerAction.kt +++ b/artmaker/src/main/java/io/artmaker/actions/ArtMakerAction.kt @@ -28,6 +28,7 @@ sealed interface ArtMakerAction { data class SelectStrokeColour(val color: Color) : ArtMakerAction data class SetStrokeWidth(val strokeWidth: Int) : ArtMakerAction data class UpdateSetStylusOnly(val shouldUseStylusOnly: Boolean) : ArtMakerAction + data class UpdateSetPressureDetection(val shouldDetectPressure: Boolean) : ArtMakerAction class UpdateEnableStylusDialogShow(val canShowEnableStylusDialog: Boolean) : ArtMakerAction class UpdateDisableStylusDialogShow(val canShowDisableStylusDialog: Boolean) : ArtMakerAction } diff --git a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt index 042b642c..dfe7015d 100644 --- a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt +++ b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt @@ -21,8 +21,8 @@ import androidx.compose.ui.geometry.Offset * Events that happen during drawing */ sealed interface DrawEvent { - data class AddNewShape(val offset: Offset, val pressure: Float) : DrawEvent - data class UpdateCurrentShape(val offset: Offset, val pressure: Float) : DrawEvent + data class AddNewShape(val offset: Offset, val pressure: Float = 1.0f) : DrawEvent + data class UpdateCurrentShape(val offset: Offset, val pressure: Float = 1.0f) : DrawEvent data object UndoLastShapePoint : DrawEvent data object Undo : DrawEvent data object Redo : DrawEvent diff --git a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt index 6d97abc1..6692a5da 100644 --- a/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt +++ b/artmaker/src/main/java/io/artmaker/composables/ArtMakerDrawScreen.kt @@ -68,6 +68,7 @@ import io.artmaker.DrawState import io.artmaker.actions.ArtMakerAction import io.artmaker.actions.DrawEvent import io.artmaker.models.ArtMakerConfiguration +import io.artmaker.models.alpha import io.artmaker.utils.isStylusInput import io.artmaker.utils.validateEvent import io.fbada006.artmaker.R @@ -199,7 +200,7 @@ internal fun ArtMakerDrawScreen( points = data.points, pointMode = if (data.points.size == 1) PointMode.Points else PointMode.Polygon, // Draw a point if the shape has only one item otherwise a free flowing shape color = data.strokeColor, - alpha = data.alphas.average().coerceAtLeast(0.0).coerceAtMost(255.0).toFloat(), + alpha = data.alpha(state.shouldDetectPressure), strokeWidth = data.strokeWidth, ) } diff --git a/artmaker/src/main/java/io/artmaker/composables/StrokeSettings.kt b/artmaker/src/main/java/io/artmaker/composables/StrokeSettings.kt index 2a639e93..d9e7a36a 100644 --- a/artmaker/src/main/java/io/artmaker/composables/StrokeSettings.kt +++ b/artmaker/src/main/java/io/artmaker/composables/StrokeSettings.kt @@ -39,9 +39,17 @@ import io.artmaker.utils.isStylusConnected import io.fbada006.artmaker.R @Composable -fun StrokeSettings(strokeWidth: Int, shouldUseStylusOnly: Boolean, onAction: (ArtMakerAction) -> Unit, configuration: ArtMakerConfiguration, modifier: Modifier = Modifier) { +fun StrokeSettings( + strokeWidth: Int, + shouldUseStylusOnly: Boolean, + shouldDetectPressure: Boolean, + onAction: (ArtMakerAction) -> Unit, + configuration: ArtMakerConfiguration, + modifier: Modifier = Modifier, +) { var sliderPosition by remember { mutableIntStateOf(strokeWidth) } var stylusOnly by remember { mutableStateOf(shouldUseStylusOnly) } + var detectPressure by remember { mutableStateOf(shouldDetectPressure) } Column(modifier = modifier, verticalArrangement = Arrangement.SpaceEvenly) { Slider( @@ -69,6 +77,20 @@ fun StrokeSettings(strokeWidth: Int, shouldUseStylusOnly: Boolean, onAction: (Ar }, ) } + HorizontalDivider() + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(R.string.enable_pressure_detection), + style = MaterialTheme.typography.bodyLarge, + ) + Switch( + checked = detectPressure, + onCheckedChange = { + detectPressure = !detectPressure + onAction(ArtMakerAction.UpdateSetPressureDetection(shouldDetectPressure = detectPressure)) + }, + ) + } } } } diff --git a/artmaker/src/main/java/io/artmaker/data/PreferenceKeys.kt b/artmaker/src/main/java/io/artmaker/data/PreferenceKeys.kt index 0276dc9f..37d90962 100644 --- a/artmaker/src/main/java/io/artmaker/data/PreferenceKeys.kt +++ b/artmaker/src/main/java/io/artmaker/data/PreferenceKeys.kt @@ -16,10 +16,10 @@ package io.artmaker.data object PreferenceKeys { - const val SELECTED_BACKGROUND_COLOUR = "com.artmaker.sharedpreferences.selectedBackgroundColour" - const val SELECTED_STROKE_COLOUR = "com.artmaker.sharedpreferences.selectedStrokeColour" - const val SELECTED_STROKE_WIDTH = "com.artmaker.sharedpreferences.selectedStrokeWidth" - const val USE_STYLUS_ONLY = "com.artmaker.sharedpreferences.useStylusOnly" - const val SHOW_ENABLE_STYLUS_DIALOG = "com.artmaker.sharedpreferences.showEnableStylusDialog" - const val SHOW_DISABLE_STYLUS_DIALOG = "com.artmaker.sharedpreferences.showDisableStylusDialog" + const val PREF_SELECTED_STROKE_COLOUR = "com.artmaker.sharedpreferences.selectedStrokeColour" + const val PREF_SELECTED_STROKE_WIDTH = "com.artmaker.sharedpreferences.selectedStrokeWidth" + const val PREF_USE_STYLUS_ONLY = "com.artmaker.sharedpreferences.useStylusOnly" + const val PREF_DETECT_PRESSURE = "com.artmaker.sharedpreferences.detectDrawingPressure" + const val PREF_SHOW_ENABLE_STYLUS_DIALOG = "com.artmaker.sharedpreferences.showEnableStylusDialog" + const val PREF_SHOW_DISABLE_STYLUS_DIALOG = "com.artmaker.sharedpreferences.showDisableStylusDialog" } diff --git a/artmaker/src/main/java/io/artmaker/models/PointsData.kt b/artmaker/src/main/java/io/artmaker/models/PointsData.kt index 31f8bcb2..aa241d14 100644 --- a/artmaker/src/main/java/io/artmaker/models/PointsData.kt +++ b/artmaker/src/main/java/io/artmaker/models/PointsData.kt @@ -29,3 +29,12 @@ internal data class PointsData( val strokeColor: Color, val alphas: MutableList, ) + +// The alpha will always be 1 during no pressure detection +internal fun PointsData.alpha(detectPressure: Boolean): Float { + return if (detectPressure) { + this.alphas.average().coerceAtLeast(0.0).coerceAtMost(255.0).toFloat() + } else { + 1.0f + } +} diff --git a/artmaker/src/main/res/values/strings.xml b/artmaker/src/main/res/values/strings.xml index 28740454..2f858baf 100644 --- a/artmaker/src/main/res/values/strings.xml +++ b/artmaker/src/main/res/values/strings.xml @@ -27,5 +27,6 @@ We have detected that you are not using your stylus to draw but you have enabled the stylus only input setting. Please disable this using the pencil icon at the bottom of the screen if you wish to use other input types to draw. Do not show again. Use stylus only + Enable pressure detection Got it \ No newline at end of file From f2834d74b0fec83c583dd5ee4d4a1bc6dea85154 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 14:03:40 +0300 Subject: [PATCH 7/9] fix small undo bug --- artmaker/src/main/java/io/artmaker/export/DrawingManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt index 48a3fd89..a8bc9482 100644 --- a/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt +++ b/artmaker/src/main/java/io/artmaker/export/DrawingManager.kt @@ -94,7 +94,7 @@ internal class DrawingManager { return UndoRedoState( canUndo = _pathList.isNotEmpty(), canRedo = undoStack.isNotEmpty(), - canClear = _pathList.isNotEmpty(), + canClear = _pathList.isNotEmpty() || undoStack.isNotEmpty(), ) } } From 41305279047e8a47cb02cee79a3212734306a587 Mon Sep 17 00:00:00 2001 From: Ferdinand Bada Date: Tue, 3 Sep 2024 14:05:31 +0300 Subject: [PATCH 8/9] coerce at least 1.0f for the alpha average --- artmaker/src/main/java/io/artmaker/models/PointsData.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artmaker/src/main/java/io/artmaker/models/PointsData.kt b/artmaker/src/main/java/io/artmaker/models/PointsData.kt index aa241d14..ea8cc9a5 100644 --- a/artmaker/src/main/java/io/artmaker/models/PointsData.kt +++ b/artmaker/src/main/java/io/artmaker/models/PointsData.kt @@ -33,7 +33,7 @@ internal data class PointsData( // The alpha will always be 1 during no pressure detection internal fun PointsData.alpha(detectPressure: Boolean): Float { return if (detectPressure) { - this.alphas.average().coerceAtLeast(0.0).coerceAtMost(255.0).toFloat() + this.alphas.average().coerceAtLeast(0.0).coerceAtMost(1.0).toFloat() } else { 1.0f } From 85158485a8a0721c659e1b9d1ee35a6b9fc4e2b2 Mon Sep 17 00:00:00 2001 From: CalebK Date: Tue, 3 Sep 2024 17:55:49 +0300 Subject: [PATCH 9/9] removed default values on the DrawEvent sealed class --- artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt index dfe7015d..042b642c 100644 --- a/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt +++ b/artmaker/src/main/java/io/artmaker/actions/DrawEvent.kt @@ -21,8 +21,8 @@ import androidx.compose.ui.geometry.Offset * Events that happen during drawing */ sealed interface DrawEvent { - data class AddNewShape(val offset: Offset, val pressure: Float = 1.0f) : DrawEvent - data class UpdateCurrentShape(val offset: Offset, val pressure: Float = 1.0f) : DrawEvent + data class AddNewShape(val offset: Offset, val pressure: Float) : DrawEvent + data class UpdateCurrentShape(val offset: Offset, val pressure: Float) : DrawEvent data object UndoLastShapePoint : DrawEvent data object Undo : DrawEvent data object Redo : DrawEvent