Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[부나] 뷰 챌린지 미션 2단계 제출합니다. #32

Merged
merged 25 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
150aaa4
refactor: PaletteView에서 자식 View를 추가하는 메서드 분리
tmdgh1592 Oct 7, 2023
a268808
refactor: ColorView 별도의 클릭 콜백을 제거하고 ClickListener 사용하도록 변경
tmdgh1592 Oct 7, 2023
5f84342
feat: 도형 목록 뷰를 보여주는 기능 구현
tmdgh1592 Oct 7, 2023
bb05430
feat: 팔레트 모드 선택 뷰 구현
tmdgh1592 Oct 7, 2023
2abb2b3
refactor: PathPainter가 Painter를 구현하도록 변경
tmdgh1592 Oct 7, 2023
8253c03
feat: 사각형을 그리는 기능 구현
tmdgh1592 Oct 7, 2023
cde6d59
refactor: 도형의 로직을PainterHistory로 이동
tmdgh1592 Oct 7, 2023
75af299
refactor: RECTANGLE_PAINT를 DEFAULT_PAINT로 변경
tmdgh1592 Oct 7, 2023
b911f82
feat: 원을 그리는 기능 구현
tmdgh1592 Oct 7, 2023
10ec0d1
feat: 팔레트 취소(undo),재실행(redo) 구현
tmdgh1592 Oct 7, 2023
c0abff7
feat: 캔버스 전체 초기화 기능 구현
tmdgh1592 Oct 8, 2023
d550c72
feat: 지우개 기능 구현
tmdgh1592 Oct 8, 2023
83f99c2
refactor: 패키지 분리
tmdgh1592 Oct 8, 2023
efeed27
fix: BrushPainter의 Paint 변경 안 되는 버그 수정
tmdgh1592 Oct 8, 2023
9b47dc0
fix: Painter의 Paint 변경 안 되는 버그 수정
tmdgh1592 Oct 8, 2023
349e7a3
refactor(PainterHistory): onActionUp() 메서드의 인자 제거
tmdgh1592 Oct 9, 2023
e0745ed
refactor(BrushPainter): Paint 프로퍼티를 private으로 변경
tmdgh1592 Oct 9, 2023
5e375a4
refactor(CirclePainter): 원을 그리는 기능을 drawOval() 메서드를 사용하도록 변경
tmdgh1592 Oct 9, 2023
05c9212
refactor(Painter): changePainter() 메서드를 expression으로 변경
tmdgh1592 Oct 9, 2023
2dc35ca
refactor(PaletteView): 두께, 색상 프로퍼티를 private set으로 변경
tmdgh1592 Oct 9, 2023
72ac21c
fix: Painter 변경시 두께, 색상, 도형 상태가 초기화되는 버그 수정
tmdgh1592 Oct 9, 2023
0a527af
refactor: CirclePainter, RectanglePainter가 ShapePainter를 구현하도록 변경
tmdgh1592 Oct 9, 2023
8a34250
refactor: Painter의 속성들을 PainterState에서 관리하도록 변경
tmdgh1592 Oct 9, 2023
0141913
refactor: 패키지 분리
tmdgh1592 Oct 9, 2023
0a2ae50
refactor(Painter): Painter 팩토리 함수를 동반 객체로 변경
tmdgh1592 Oct 10, 2023
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
66 changes: 60 additions & 6 deletions app/src/main/java/woowacourse/paint/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,37 +1,91 @@
package woowacourse.paint

import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import woowacourse.paint.view.CanvasView
import woowacourse.paint.view.PaletteColor
import woowacourse.paint.view.PaletteView
import androidx.appcompat.widget.AppCompatButton
import woowacourse.paint.view.canvas.CanvasView
import woowacourse.paint.view.palette.color.PaletteColor
import woowacourse.paint.view.palette.PaletteMode
import woowacourse.paint.view.palette.shape.PaletteShape
import woowacourse.paint.view.palette.PaletteView

class MainActivity : AppCompatActivity() {
private val canvasView: CanvasView by lazy { findViewById(R.id.canvas_view) }
private val paletteView: PaletteView by lazy { findViewById(R.id.palette_view) }
private val paletteModeView: LinearLayout by lazy { findViewById(R.id.palette_mode_view) }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

setupCanvasView()
setupPaletteView()
setupPaletteModeView()
}

private fun setupCanvasView() {
canvasView.setPaintThickness(paletteView.selectedPaintThickness)
canvasView.setPaintColor(paletteView.selectedPaintColor)
canvasView.setPaletteColor(paletteView.selectedPaletteColor)
}

private fun setupPaletteView() {
paletteView.setOnPropertyChangeListener(object : PaletteView.OnPaintPropertyChangeListener {
override fun onColorSelected(paintColor: PaletteColor) {
canvasView.setPaintColor(paintColor)
override fun onColorSelected(paletteColor: PaletteColor) {
canvasView.setPaletteColor(paletteColor)
}

override fun onShapeSelected(paletteShape: PaletteShape) {
canvasView.setPaletteShape(paletteShape)
}

override fun onStrokeThicknessChanged(paintThickness: Float) {
canvasView.setPaintThickness(paintThickness)
}
})
paletteView.changePaletteMode(PaletteMode.BRUSH)
}

private fun setupPaletteModeView() {
PaletteMode.values().forEach { paletteMode ->
val modeButton = createModeButton(paletteMode) { newPaletteMode ->
paletteView.changePaletteMode(newPaletteMode)
canvasView.changePaletteMode(newPaletteMode)
}

paletteModeView.addView(modeButton)
modeButton.layoutParams = (modeButton.layoutParams as LinearLayout.LayoutParams).apply {
weight = 1F
marginStart = 10
marginEnd = 10
}
}
}

private fun createModeButton(
mode: PaletteMode,
onClick: (PaletteMode) -> Unit,
): AppCompatButton = AppCompatButton(this).apply {
text = mode.modeName
textSize = 20F
setTextColor(getColor(R.color.white))
setBackgroundColor(getColor(R.color.purple_500))
setOnClickListener { onClick(mode) }
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.undo -> canvasView.undo()
R.id.redo -> canvasView.redo()
R.id.reset -> canvasView.reset()
}
return true
}
}
19 changes: 19 additions & 0 deletions app/src/main/java/woowacourse/paint/common/PaintExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package woowacourse.paint.common

import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import woowacourse.paint.view.palette.color.PaletteColor

fun Paint.softPainter(
paletteColor: PaletteColor = PaletteColor.RED,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

팔레트 색상이나 굵기가 유지되면 사용자 입장에서 더 자연스러울 것 같아요! 현재는 지우개나 브러시를 선택했을 때 슬라이더 위치와 실제 그려지는 두께가 다르고, 버튼을 누를 때마다 색상이 빨간색으로 초기화되어 불편합니다.
이건 요구사항은 아니니까 자유롭게 반영해주세요! (어디에 코멘트 다는게 좋을지 모르겠어서 아무데나 남깁니다..ㅋㅋ)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아무래도 Painter의 changePainter() 메서드에서 매번 새로운 Painter를 반환해주니 생기는 문제인 것 같습니다 🥲
현재 PainterHistory에서 두께, 도형, 색상에 대한 상태를 가지고 있도록 하였고, 브러시 변경시 Painter.changePainter()의 인자로 이전의 상태를 전달하도록 변경하였습니다.

paintStyle: Paint.Style = Paint.Style.STROKE,
porterDuffMode: PorterDuff.Mode = PorterDuff.Mode.SRC_OVER,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PorterDuff.Mode.SRC_OVER 는 어떤 옵션인가요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 그려져 있는 리소스 위에 작성하겠다는 의미입니다 : )

): Paint = apply {
isAntiAlias = true
style = paintStyle
strokeJoin = Paint.Join.ROUND
strokeCap = Paint.Cap.ROUND
color = paletteColor.color
xfermode = PorterDuffXfermode(porterDuffMode)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package woowacourse.paint.view
package woowacourse.paint.common

import android.content.Context
import com.google.android.material.slider.RangeSlider
Expand Down
42 changes: 0 additions & 42 deletions app/src/main/java/woowacourse/paint/view/CanvasView.kt

This file was deleted.

49 changes: 0 additions & 49 deletions app/src/main/java/woowacourse/paint/view/PaletteView.kt

This file was deleted.

17 changes: 0 additions & 17 deletions app/src/main/java/woowacourse/paint/view/PathPainterHistory.kt

This file was deleted.

71 changes: 71 additions & 0 deletions app/src/main/java/woowacourse/paint/view/canvas/CanvasView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package woowacourse.paint.view.canvas

import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import woowacourse.paint.view.canvas.paintHistory.PainterHistory
import woowacourse.paint.view.palette.color.PaletteColor
import woowacourse.paint.view.palette.PaletteMode
import woowacourse.paint.view.palette.shape.PaletteShape

class CanvasView : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

private val painterHistory = PainterHistory()

init {
setLayerType(LAYER_TYPE_HARDWARE, null)
}

override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
painterHistory.draw(canvas)
}

override fun onTouchEvent(event: MotionEvent): Boolean {
val pointX = event.x
val pointY = event.y

when (event.action) {
MotionEvent.ACTION_DOWN -> painterHistory.onActionDown(pointX, pointY)
MotionEvent.ACTION_MOVE -> painterHistory.onActionMove(pointX, pointY)
MotionEvent.ACTION_UP -> painterHistory.onActionUp(pointX, pointY)
}
invalidate()
return true
}

fun setPaletteColor(paletteColor: PaletteColor) {
painterHistory.setPaletteColor(paletteColor)
}

fun setPaintThickness(painterThickness: Float) {
painterHistory.setPaintThickness(painterThickness)
}

fun setPaletteShape(paletteShape: PaletteShape) {
painterHistory.setPaletteShape(paletteShape)
}

fun changePaletteMode(paletteMode: PaletteMode) {
painterHistory.changePaletteMode(paletteMode)
}

fun undo() {
painterHistory.undo()
invalidate()
}

fun redo() {
painterHistory.redo()
invalidate()
}

fun reset() {
painterHistory.clear()
invalidate()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package woowacourse.paint.view.canvas.paintHistory

import android.graphics.Canvas
import woowacourse.paint.view.canvas.painter.BrushPainter
import woowacourse.paint.view.canvas.painter.Painter
import woowacourse.paint.view.palette.color.PaletteColor
import woowacourse.paint.view.palette.PaletteMode
import woowacourse.paint.view.palette.shape.PaletteShape

class PainterHistory(
private val undoes: ArrayList<Painter> = ArrayList(),
private val redoes: ArrayList<Painter> = ArrayList(),
private var currentPainter: Painter = BrushPainter(),
) {
fun draw(canvas: Canvas) {
undoes.forEach { painter -> painter.draw(canvas) }
}

fun setPaletteColor(paletteColor: PaletteColor) {
currentPainter = currentPainter.setPaletteColor(paletteColor)
}

fun setPaintThickness(painterThickness: Float) {
currentPainter = currentPainter.setThickness(painterThickness)
}

fun setPaletteShape(paletteShape: PaletteShape) {
currentPainter = currentPainter.changePainter(PaletteMode.SHAPE, paletteShape)
}

fun changePaletteMode(paletteMode: PaletteMode) {
currentPainter = currentPainter.changePainter(paletteMode)
}

fun onActionDown(x: Float, y: Float) {
undoes.add(currentPainter)
currentPainter.onActionDown(x, y)
}

fun onActionMove(x: Float, y: Float) {
currentPainter.onActionMove(x, y)
}

fun onActionUp(x: Float, y: Float) {
currentPainter = currentPainter.extract()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인자가 사용되지 않아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

언젠가 onActionUp 되었을 때 좌표가 필요한 경우가 있을 것 같아서 지우지 않았는데,
생각해보니 필요한 시점에 추가하는 게 낫겠네요 👍


fun undo() {
val redo = undoes.removeLastOrNull() ?: return
redoes.add(redo)
}

fun redo() {
val undo = redoes.removeLastOrNull() ?: return
undoes.add(undo)
}

fun clear() {
undoes.clear()
redoes.clear()
}
}
Loading