diff --git a/.github/workflows/AOS-ktlint.yml b/.github/workflows/AOS-ktlint.yml index f415e836..116d2197 100644 --- a/.github/workflows/AOS-ktlint.yml +++ b/.github/workflows/AOS-ktlint.yml @@ -18,6 +18,14 @@ jobs: with: java-version: '17' distribution: 'adopt' - + - name: Create Properties File + env: + RELEASE_KEYSTORE: ${{ secrets.KEY_STORE_BASE_64 }} + KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }} + LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }} + run: | + echo "$RELEASE_KEYSTORE" | base64 -d > AOS/app/release.keystore + echo "$KEYSTORE_PROPERTIES" > AOS/keystore.properties + echo "$LOCAL_PROPERTIES" > AOS/local.properties - name: Run ktlint run: cd AOS && chmod +x ./gradlew &&./gradlew ktlintCheck diff --git a/AOS/app/build.gradle.kts b/AOS/app/build.gradle.kts index e4975705..5e20a49e 100644 --- a/AOS/app/build.gradle.kts +++ b/AOS/app/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -12,6 +14,8 @@ android { namespace = "boostcamp.and07.mindsync" compileSdk = 34 + val properties = Properties() + properties.load(project.rootProject.file("local.properties").inputStream()) val url = properties["BASE_URL"] ?: "" val googleServerClientId = properties["GOOGLE_SERVER_CLIENT_ID"] ?: "" val kakaoClientId = properties["KAKAO_CLIENT_ID"] ?: "" diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/data/model/Node.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/data/model/Node.kt index 9976500b..c3629788 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/data/model/Node.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/data/model/Node.kt @@ -2,6 +2,8 @@ package boostcamp.and07.mindsync.data.model import boostcamp.and07.mindsync.ui.util.Dp import kotlinx.serialization.Serializable +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract @Serializable sealed class Node( @@ -15,6 +17,15 @@ sealed class Node( horizontalSpacing: Dp, totalHeight: Dp, ): Node + + @OptIn(ExperimentalContracts::class) + fun isRectangle(): Boolean { + contract { + returns(true) implies (this@Node is RectangleNode) + returns(false) implies (this@Node is CircleNode) + } + return this is RectangleNode + } } data class CircleNode( diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapBindingAdapter.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapBindingAdapter.kt index b4a91c4b..c7ff8969 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapBindingAdapter.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapBindingAdapter.kt @@ -2,16 +2,12 @@ package boostcamp.and07.mindsync.ui.mindmap import android.widget.ImageButton import androidx.databinding.BindingAdapter -import boostcamp.and07.mindsync.data.model.CircleNode import boostcamp.and07.mindsync.data.model.Node -import boostcamp.and07.mindsync.data.model.RectangleNode @BindingAdapter("app:removeBtn") fun ImageButton.setEnabled(selectedNode: Node?) { - this.isEnabled = - when (selectedNode) { - is CircleNode -> false - is RectangleNode -> true - else -> false - } + if (selectedNode != null) { + this.isEnabled = + selectedNode.isRectangle() + } } diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapFragment.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapFragment.kt index 8022a300..aaf87bf0 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapFragment.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/mindmap/MindMapFragment.kt @@ -7,9 +7,7 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.navArgs import boostcamp.and07.mindsync.R import boostcamp.and07.mindsync.data.crdt.OperationType -import boostcamp.and07.mindsync.data.model.CircleNode import boostcamp.and07.mindsync.data.model.Node -import boostcamp.and07.mindsync.data.model.RectangleNode import boostcamp.and07.mindsync.data.model.Tree import boostcamp.and07.mindsync.data.util.NodeGenerator import boostcamp.and07.mindsync.databinding.FragmentMindMapBinding @@ -98,14 +96,18 @@ class MindMapFragment : editDescriptionDialog.setSubmitListener { description -> when (operationType) { OperationType.ADD -> { - mindMapViewModel.addNode(selectedNode, NodeGenerator.makeNode(description, selectedNode.id)) + mindMapViewModel.addNode( + selectedNode, + NodeGenerator.makeNode(description, selectedNode.id), + ) } OperationType.UPDATE -> { val newNode = - when (selectedNode) { - is CircleNode -> selectedNode.copy(description = description) - is RectangleNode -> selectedNode.copy(description = description) + if (selectedNode.isRectangle()) { + selectedNode.copy(description = description) + } else { + selectedNode.copy(description = description) } mindMapViewModel.updateNode(newNode) } diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/util/DensityUtils.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/util/DensityUtils.kt index adda668c..f6ed962f 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/util/DensityUtils.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/util/DensityUtils.kt @@ -4,8 +4,9 @@ import android.content.Context import android.util.TypedValue import kotlinx.serialization.Serializable +@JvmInline @Serializable -data class Dp(val dpVal: Float) { +value class Dp(val dpVal: Float) { operator fun plus(dpValue: Dp): Dp { return Dp(dpVal + dpValue.dpVal) } @@ -67,7 +68,8 @@ data class Dp(val dpVal: Float) { } } -data class Px(val pxVal: Float) { +@JvmInline +value class Px(val pxVal: Float) { operator fun plus(pxValue: Px): Px { return Px(pxVal + pxValue.pxVal) } diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/LineView.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/LineView.kt index 507d2a32..e332083b 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/LineView.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/LineView.kt @@ -7,9 +7,7 @@ import android.graphics.Paint import android.graphics.Path import android.util.AttributeSet import android.view.View -import boostcamp.and07.mindsync.data.model.CircleNode import boostcamp.and07.mindsync.data.model.Node -import boostcamp.and07.mindsync.data.model.RectangleNode import boostcamp.and07.mindsync.data.model.Tree import boostcamp.and07.mindsync.ui.util.toPx import boostcamp.and07.mindsync.ui.view.model.DrawInfo @@ -98,9 +96,10 @@ class LineView constructor( ): Float { val nodeCenterX = node.path.centerX.toPx(context) val widthOffset = - when (node) { - is CircleNode -> node.path.radius.toPx(context) - is RectangleNode -> node.path.width.toPx(context) / 2 + if (node.isRectangle()) { + node.path.width.toPx(context) / 2 + } else { + node.path.radius.toPx(context) } return if (isStart) nodeCenterX + widthOffset else nodeCenterX - widthOffset } diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/NodeView.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/NodeView.kt index 5b0ffbb2..89205db0 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/NodeView.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/NodeView.kt @@ -138,11 +138,12 @@ class NodeView( dy: Float, ) { mindMapContainer.selectNode?.let { selectedNode -> - if (selectedNode is CircleNode) return - traverseMovedNode(tree.getRootNode(), selectedNode, dx, dy) + if (selectedNode.isRectangle()) { + traverseMovedNode(tree.getRootNode(), selectedNode, dx, dy) - mindMapContainer.update(tree) - rightLayoutManager.arrangeNode(tree, selectedNode as RectangleNode) + mindMapContainer.update(tree) + rightLayoutManager.arrangeNode(tree, selectedNode) + } } lineView.updateTree(tree) invalidate() @@ -200,16 +201,15 @@ class NodeView( private fun drawAttachedNode(canvas: Canvas) { attachedNode?.let { attachedNode -> - val height = - when (attachedNode) { - is RectangleNode -> attachedNode.path.height - is CircleNode -> attachedNode.path.radius + Dp(ATTACH_CIRCLE_NODE_RANGE_VALUE) - } - val width = - when (attachedNode) { - is RectangleNode -> attachedNode.path.width - is CircleNode -> attachedNode.path.radius + Dp(ATTACH_CIRCLE_NODE_RANGE_VALUE) - } + val height: Dp + val width: Dp + if (attachedNode.isRectangle()) { + height = attachedNode.path.height + width = attachedNode.path.width + } else { + height = attachedNode.path.radius + Dp(ATTACH_CIRCLE_NODE_RANGE_VALUE) + width = height + } val radius = maxOf(height.toPx(context), width.toPx(context)) canvas.drawCircle( attachedNode.path.centerX.toPx(context), @@ -225,27 +225,23 @@ class NodeView( canvas: Canvas, node: Node, ) { - when (node) { - is CircleNode -> { - canvas.drawCircle( - node.path.centerX.toPx(context), - node.path.centerY.toPx(context), - node.path.radius.toPx(context), - drawInfo.strokePaint, - ) - } - - is RectangleNode -> { - canvas.drawRoundRect( - node.path.leftX().toPx(context), - node.path.topY().toPx(context), - node.path.rightX().toPx(context), - node.path.bottomY().toPx(context), - Dp(ROUNDED_CORNER_RADIUS).toPx(context), - Dp(ROUNDED_CORNER_RADIUS).toPx(context), - drawInfo.strokePaint, - ) - } + if (node.isRectangle()) { + canvas.drawRoundRect( + node.path.leftX().toPx(context), + node.path.topY().toPx(context), + node.path.rightX().toPx(context), + node.path.bottomY().toPx(context), + Dp(ROUNDED_CORNER_RADIUS).toPx(context), + Dp(ROUNDED_CORNER_RADIUS).toPx(context), + drawInfo.strokePaint, + ) + } else { + canvas.drawCircle( + node.path.centerX.toPx(context), + node.path.centerY.toPx(context), + node.path.radius.toPx(context), + drawInfo.strokePaint, + ) } } @@ -254,24 +250,17 @@ class NodeView( x: Float, y: Float, ): Boolean { - when (node) { - is CircleNode -> { - if (x in (node.path.centerX - node.path.radius).toPx(context)..(node.path.centerX + node.path.radius).toPx(context) && - y in (node.path.centerY - node.path.radius).toPx(context)..(node.path.centerY + node.path.radius).toPx(context) - ) { - return true - } - } - - is RectangleNode -> { - if (x in node.path.leftX().toPx(context)..node.path.rightX().toPx(context) && + if (node.isRectangle()) { + return ( + x in node.path.leftX().toPx(context)..node.path.rightX().toPx(context) && y in node.path.topY().toPx(context)..node.path.bottomY().toPx(context) - ) { - return true - } - } + ) + } else { + return ( + x in (node.path.centerX - node.path.radius).toPx(context)..(node.path.centerX + node.path.radius).toPx(context) && + y in (node.path.centerY - node.path.radius).toPx(context)..(node.path.centerY + node.path.radius).toPx(context) + ) } - return false } private fun drawNode( @@ -279,9 +268,10 @@ class NodeView( node: Node, depth: Int, ) { - when (node) { - is CircleNode -> drawCircleNode(canvas, node) - is RectangleNode -> drawRectangleNode(canvas, node, depth) + if (node.isRectangle()) { + drawRectangleNode(canvas, node, depth) + } else { + drawCircleNode(canvas, node) } drawText(canvas, node) } @@ -321,55 +311,56 @@ class NodeView( ) { val lines = node.description.split("\n") val bounds = Rect() - when (node) { - is CircleNode -> { - drawInfo.textPaint.color = Color.WHITE - if (lines.size > 1) { - var y = - node.path.centerY.toPx(context) - node.path.radius.toPx(context) + drawInfo.padding.toPx(context) - for (line in lines) { - drawInfo.textPaint.getTextBounds(line, 0, line.length, bounds) - canvas.drawText( - line, - node.path.centerX.toPx(context), - y + bounds.height(), - drawInfo.textPaint, - ) - y += bounds.height() + drawInfo.lineHeight.dpVal - } - } else { + if (node.isRectangle()) { + drawInfo.textPaint.color = Color.BLACK + if (lines.size > 1) { + var y = + node.path.centerY.toPx(context) - node.path.height.toPx(context) / 2 + drawInfo.padding.toPx( + context, + ) / 2 + for (line in lines) { + drawInfo.textPaint.getTextBounds(line, 0, line.length, bounds) canvas.drawText( - node.description, + line, node.path.centerX.toPx(context), - node.path.centerY.toPx(context) + drawInfo.lineHeight.dpVal / 2, + y + bounds.height(), drawInfo.textPaint, ) + y += bounds.height() + drawInfo.lineHeight.dpVal } + } else { + canvas.drawText( + node.description, + node.path.centerX.toPx(context), + node.path.centerY.toPx(context) + drawInfo.lineHeight.dpVal / 2, + drawInfo.textPaint, + ) } - - is RectangleNode -> { - drawInfo.textPaint.color = Color.BLACK - if (lines.size > 1) { - var y = - node.path.centerY.toPx(context) - node.path.height.toPx(context) / 2 + drawInfo.padding.toPx(context) / 2 - for (line in lines) { - drawInfo.textPaint.getTextBounds(line, 0, line.length, bounds) - canvas.drawText( - line, - node.path.centerX.toPx(context), - y + bounds.height(), - drawInfo.textPaint, + } else { + drawInfo.textPaint.color = Color.WHITE + if (lines.size > 1) { + var y = + node.path.centerY.toPx(context) - node.path.radius.toPx(context) + + drawInfo.padding.toPx( + context, ) - y += bounds.height() + drawInfo.lineHeight.dpVal - } - } else { + for (line in lines) { + drawInfo.textPaint.getTextBounds(line, 0, line.length, bounds) canvas.drawText( - node.description, + line, node.path.centerX.toPx(context), - node.path.centerY.toPx(context) + drawInfo.lineHeight.dpVal / 2, + y + bounds.height(), drawInfo.textPaint, ) + y += bounds.height() + drawInfo.lineHeight.dpVal } + } else { + canvas.drawText( + node.description, + node.path.centerX.toPx(context), + node.path.centerY.toPx(context) + drawInfo.lineHeight.dpVal / 2, + drawInfo.textPaint, + ) } } } diff --git a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/layout/MindMapRightLayoutManager.kt b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/layout/MindMapRightLayoutManager.kt index ccbefd6a..e21efc4d 100644 --- a/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/layout/MindMapRightLayoutManager.kt +++ b/AOS/app/src/main/java/boostcamp/and07/mindsync/ui/view/layout/MindMapRightLayoutManager.kt @@ -35,9 +35,10 @@ class MindMapRightLayoutManager { val childHeightSum = measureChildHeight(currentNode, tree) val nodeWidth = - when (currentNode) { - is RectangleNode -> currentNode.path.width - is CircleNode -> currentNode.path.radius + if (currentNode.isRectangle()) { + currentNode.path.width + } else { + currentNode.path.radius } val criteriaX = currentNode.path.centerX + nodeWidth / 2 + horizontalSpacing @@ -50,21 +51,18 @@ class MindMapRightLayoutManager { val newY = startY + (childHeight / 2) startX = - when (child) { - is CircleNode -> criteriaX + (child.path.radius / 2) - is RectangleNode -> criteriaX + (child.path.width / 2) + if (child.isRectangle()) { + criteriaX + (child.path.width / 2) + } else { + criteriaX + (child.path.radius / 2) } val newChild = - when (child) { - is CircleNode -> { - val newPath = child.path.copy(centerX = startX, centerY = newY) - child.copy(path = newPath) - } - - is RectangleNode -> { - val newPath = child.path.copy(centerX = startX, centerY = newY) - child.copy(path = newPath) - } + if (child.isRectangle()) { + val newPath = child.path.copy(centerX = startX, centerY = newY) + child.copy(path = newPath) + } else { + val newPath = child.path.copy(centerX = startX, centerY = newY) + child.copy(path = newPath) } tree.setNode(childId, newChild)