Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import androidx.ink.strokes.ImmutableStrokeInputBatch
import androidx.ink.strokes.Stroke
import androidx.test.core.app.ApplicationProvider
import com.example.cahier.core.ui.Converters
import com.example.cahier.developer.brushdesigner.data.CustomBrushDao
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package com.example.cahier.developer.brushdesigner.viewmodel
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.cahier.core.data.CustomBrushDao
import com.example.cahier.core.ui.CahierTextureBitmapStore
import com.example.cahier.developer.brushdesigner.data.BrushDesignerRepository
import com.example.cahier.developer.brushdesigner.data.CustomBrushDao
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import kotlinx.coroutines.Dispatchers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.ink.brush.StockBrushes
import androidx.ink.storage.encode
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.cahier.core.data.AUTOSAVE_KEY
import com.example.cahier.core.ui.CahierTextureBitmapStore
import com.example.cahier.developer.brushdesigner.data.FakeCustomBrushDao
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -88,7 +89,7 @@ class BrushGraphRepositoryTest {
val savedEntity = fakeDao.getAutoSaveBrush().first()
assertNotNull(savedEntity)
assertEquals(
com.example.cahier.developer.brushdesigner.data.AUTOSAVE_KEY,
AUTOSAVE_KEY,
savedEntity!!.name
)
assertTrue(savedEntity.brushBytes.isNotEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package com.example.cahier.developer.brushgraph.viewmodel
import androidx.ink.storage.encode
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.example.cahier.core.data.CustomBrushEntity
import com.example.cahier.core.ui.CahierTextureBitmapStore
import com.example.cahier.developer.brushdesigner.data.CustomBrushEntity
import com.example.cahier.developer.brushdesigner.data.FakeCustomBrushDao
import com.example.cahier.developer.brushgraph.data.BrushGraph
import com.example.cahier.developer.brushgraph.data.DefaultBrushGraphRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
*/

package com.example.cahier.developer.brushdesigner.data
package com.example.cahier.core.data

import androidx.room.Dao
import androidx.room.Insert
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
/*
* Copyright 2025 Google LLC. All rights reserved.
*
* * Copyright 2025 Google LLC. All rights reserved.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.cahier.developer.brushdesigner.data
package com.example.cahier.core.data

import androidx.room.ColumnInfo
import androidx.room.Entity
Expand All @@ -25,7 +23,7 @@ import androidx.room.PrimaryKey
@Entity(tableName = "custom_brushes")
data class CustomBrushEntity(
@PrimaryKey val name: String,
@ColumnInfo(typeAffinity = ColumnInfo.BLOB) val brushBytes: ByteArray
@ColumnInfo(typeAffinity = ColumnInfo.BLOB) val brushBytes: ByteArray,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
Expand All @@ -44,4 +42,4 @@ data class CustomBrushEntity(
result = 31 * result + brushBytes.contentHashCode()
return result
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.example.cahier.core.ui.Converters
import com.example.cahier.developer.brushdesigner.data.CustomBrushDao
import com.example.cahier.developer.brushdesigner.data.CustomBrushEntity

@Database(
entities = [Note::class, CustomBrushEntity::class],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import androidx.ink.storage.decode
import androidx.ink.strokes.Stroke
import com.example.cahier.core.ui.CahierTextureBitmapStore
import com.example.cahier.core.ui.Converters
import com.example.cahier.developer.brushdesigner.data.CustomBrushDao
import com.example.cahier.features.drawing.CustomBrushes
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.json.Json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ package com.example.cahier.core.di
import android.content.Context
import androidx.room.Room
import coil3.ImageLoader
import com.example.cahier.core.data.CustomBrushDao
import com.example.cahier.core.data.MIGRATION_7_8
import com.example.cahier.core.data.MIGRATION_8_9
import com.example.cahier.core.data.NoteDatabase
import com.example.cahier.core.data.NotesRepository
import com.example.cahier.core.data.OfflineNotesRepository
import com.example.cahier.core.ui.CahierTextureBitmapStore
import com.example.cahier.core.utils.FileHelper
import com.example.cahier.developer.brushdesigner.data.CustomBrushDao
import com.example.cahier.developer.brushgraph.data.BrushGraphRepository
import com.example.cahier.developer.brushgraph.data.DefaultBrushGraphRepository
import dagger.Module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import androidx.ink.brush.StockBrushes
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.example.cahier.R
import com.example.cahier.developer.brushdesigner.viewmodel.BrushDesignerViewModel
import com.example.cahier.developer.brushgraph.ui.BrushSliderControl
import ink.proto.BrushTip as ProtoBrushTip

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ import androidx.compose.ui.window.PopupProperties
import androidx.ink.brush.BrushFamily
import androidx.ink.brush.StockBrushes
import com.example.cahier.R
import com.example.cahier.core.data.CustomBrushEntity
import com.example.cahier.core.ui.LocalTextureStore
import com.example.cahier.developer.brushdesigner.data.CustomBrushEntity
import com.example.cahier.features.drawing.CustomBrushes

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.example.cahier.R
import com.example.cahier.developer.brushgraph.ui.EnumDropdown
import com.example.cahier.developer.brushgraph.ui.NumericField
import com.example.cahier.developer.brushgraph.ui.NumericLimits
import ink.proto.BrushBehavior
import ink.proto.CubicBezierEasingFunction
import ink.proto.LinearEasingFunction
import ink.proto.StepsEasingFunction
import ink.proto.PredefinedEasingFunction as ProtoPredefinedEasingFunction

/**
Expand All @@ -38,7 +44,7 @@ import ink.proto.PredefinedEasingFunction as ProtoPredefinedEasingFunction
internal fun NodeEditor(
node: BrushBehavior.Node,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
when (node.nodeCase) {
BrushBehavior.Node.NodeCase.SOURCE_NODE ->
Expand Down Expand Up @@ -76,11 +82,14 @@ internal fun NodeEditor(
internal fun SourceNodeEditor(
source: BrushBehavior.SourceNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_source), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_source),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

val sources = BrushBehavior.Source.entries.filter {
it != BrushBehavior.Source.SOURCE_UNSPECIFIED
Expand Down Expand Up @@ -147,11 +156,14 @@ internal fun SourceNodeEditor(
internal fun ResponseNodeEditor(
response: BrushBehavior.ResponseNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_response_curve), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_response_curve),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

MathCurvePreview(
responseNode = response,
Expand All @@ -161,10 +173,13 @@ internal fun ResponseNodeEditor(
val currentType = when (response.responseCurveCase) {
BrushBehavior.ResponseNode.ResponseCurveCase.CUBIC_BEZIER_RESPONSE_CURVE ->
ResponseCurveType.CubicBezier

BrushBehavior.ResponseNode.ResponseCurveCase.LINEAR_RESPONSE_CURVE ->
ResponseCurveType.Linear

BrushBehavior.ResponseNode.ResponseCurveCase.STEPS_RESPONSE_CURVE ->
ResponseCurveType.Steps

else -> ResponseCurveType.Predefined
}

Expand All @@ -180,18 +195,21 @@ internal fun ResponseNodeEditor(
newResponseBuilder.setPredefinedResponseCurve(
ProtoPredefinedEasingFunction.PREDEFINED_EASING_EASE
)

ResponseCurveType.CubicBezier ->
newResponseBuilder.setCubicBezierResponseCurve(
ink.proto.CubicBezierEasingFunction.newBuilder()
CubicBezierEasingFunction.newBuilder()
.setX1(0.25f).setY1(0.1f).setX2(0.25f).setY2(1f)
)

ResponseCurveType.Linear ->
newResponseBuilder.setLinearResponseCurve(
ink.proto.LinearEasingFunction.newBuilder()
LinearEasingFunction.newBuilder()
)

ResponseCurveType.Steps ->
newResponseBuilder.setStepsResponseCurve(
ink.proto.StepsEasingFunction.newBuilder().setStepCount(4)
StepsEasingFunction.newBuilder().setStepCount(4)
)
}
onNodeChanged(
Expand Down Expand Up @@ -307,11 +325,14 @@ internal fun ResponseNodeEditor(
internal fun DampingNodeEditor(
damping: BrushBehavior.DampingNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_damping), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_damping),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

EnumDropdown(
label = stringResource(R.string.brush_designer_node_damping_source),
Expand Down Expand Up @@ -348,7 +369,7 @@ internal fun DampingNodeEditor(
internal fun NoiseNodeEditor(
noise: BrushBehavior.NoiseNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(
Expand Down Expand Up @@ -405,11 +426,14 @@ internal fun NoiseNodeEditor(
internal fun TargetNodeEditor(
target: BrushBehavior.TargetNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_target), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_target),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

EnumDropdown(
label = stringResource(R.string.brush_designer_node_target_output),
Expand Down Expand Up @@ -459,11 +483,14 @@ internal fun TargetNodeEditor(
internal fun ConstantNodeEditor(
constant: BrushBehavior.ConstantNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_constant_value), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_constant_value),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

NumericField(
title = stringResource(R.string.brush_designer_node_value),
Expand All @@ -484,11 +511,14 @@ internal fun ConstantNodeEditor(
internal fun BinaryOpNodeEditor(
binaryOp: BrushBehavior.BinaryOpNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_binary_operation), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_binary_operation),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

EnumDropdown(
label = stringResource(R.string.brush_designer_node_operation),
Expand All @@ -512,11 +542,14 @@ internal fun BinaryOpNodeEditor(
internal fun InterpolationNodeEditor(
interpolation: BrushBehavior.InterpolationNode,
onNodeChanged: (BrushBehavior.Node) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(stringResource(R.string.brush_designer_node_interpolation), style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary)
Text(
stringResource(R.string.brush_designer_node_interpolation),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.secondary
)

EnumDropdown(
label = stringResource(R.string.brush_designer_node_interpolation),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.example.cahier.R
import com.example.cahier.core.ui.LocalTextureStore
import com.example.cahier.developer.brushgraph.ui.EnumDropdown
import com.example.cahier.developer.brushgraph.ui.NumericField
import com.example.cahier.developer.brushgraph.ui.NumericLimits
import ink.proto.BrushFamily as ProtoBrushFamily
import ink.proto.BrushPaint as ProtoBrushPaint
import ink.proto.Color as ProtoColor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import com.example.cahier.core.ui.theme.BrushBlue
import com.example.cahier.core.ui.theme.BrushGreen
import com.example.cahier.core.ui.theme.BrushRed
import com.example.cahier.core.ui.theme.BrushYellow
import com.example.cahier.developer.brushgraph.ui.CustomColorPickerDialog
import ink.proto.BrushFamily as ProtoBrushFamily

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.ink.brush.Brush
import com.example.cahier.R
import com.example.cahier.developer.brushgraph.ui.NumericField
import com.example.cahier.developer.brushgraph.ui.NumericLimits
import ink.proto.BrushTip as ProtoBrushTip

/**
* Tab 0: Tip geometry controls — scale (with lock toggle), corner rounding,
* slant, rotation, pinch, and particle (stamp) settings.
*
* Uses [NumericField] for professional ±button input with degree/percent
* Uses [com.example.cahier.developer.brushgraph.ui.NumericField] for professional ±button input with degree/percent
* unit conversions and click-to-edit exact-value entry.
*
* Stateless: receives data and callbacks, does not access ViewModel.
Expand Down
Loading
Loading