diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 923be03b..29e3426e 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -8,6 +8,7 @@
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 688fb3d8..ea97dc5c 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -15,6 +15,7 @@
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 508ebce1..2ac7f21e 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -79,6 +79,7 @@ android {
dependencies {
implementation(project(":data"))
implementation(project(":domain"))
+ implementation(project(":jj_design"))
implementation("androidx.appcompat:appcompat:1.5.0")
implementation("com.google.android.material:material:1.4.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c56a3e16..a904db29 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -24,6 +24,9 @@
android:theme="@style/Theme.JJBAKSAAOS"
android:usesCleartextTraffic="true"
tools:targetApi="33">
+
diff --git a/app/src/main/java/com/jjbaksa/jjbaksa/ui/DesignComponentSampleActivity.kt b/app/src/main/java/com/jjbaksa/jjbaksa/ui/DesignComponentSampleActivity.kt
new file mode 100644
index 00000000..9fc710a5
--- /dev/null
+++ b/app/src/main/java/com/jjbaksa/jjbaksa/ui/DesignComponentSampleActivity.kt
@@ -0,0 +1,106 @@
+package com.jjbaksa.jjbaksa.ui
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.android.jj_design.utils.button.Add
+import com.android.jj_design.utils.button.Confirm
+import com.android.jj_design.utils.button.Delete
+import com.android.jj_design.utils.button.Follow
+import com.android.jj_design.utils.button.Following
+import com.android.jj_design.utils.button.Minus
+import com.android.jj_design.utils.button.Position
+import com.android.jj_design.utils.button.Requested
+import com.jjbaksa.jjbaksa.R
+import com.jjbaksa.jjbaksa.databinding.ActivityDesignComponentSampleBinding
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+
+class DesignComponentSampleActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityDesignComponentSampleBinding
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityDesignComponentSampleBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ initJjButton()
+ initJjChipButton()
+ initJjTrendButton()
+ initJjMapButton()
+ initJjPlusButton()
+ }
+
+ private fun initJjButton() {
+ CoroutineScope(Dispatchers.Main).launch {
+ while (this.isActive) {
+ binding.jjButton.setErrorBackground()
+ binding.jjButton.text = "오류 버튼"
+ delay(2000)
+ binding.jjButton.isEnabled = true
+ binding.jjButton.text = "활성화 버튼"
+ delay(2000)
+ binding.jjButton.isEnabled = false
+ binding.jjButton.text = "비활성화 버튼"
+ delay(2000)
+ }
+ }
+ }
+
+ private fun initJjChipButton() {
+ CoroutineScope(Dispatchers.Main).launch {
+ while (isActive) {
+ binding.jjChipButton.chipItemType = Delete
+ delay(2000)
+ binding.jjChipButton.chipItemType = Confirm
+ delay(2000)
+ binding.jjChipButton.chipItemType = Requested
+ delay(2000)
+ binding.jjChipButton.chipItemType = Follow
+ delay(2000)
+ binding.jjChipButton.chipItemType = Following
+ delay(2000)
+ }
+ }
+ }
+
+ private fun initJjTrendButton() {
+ CoroutineScope(Dispatchers.Main).launch {
+ while (isActive) {
+ binding.jjTrendButton.isEnabled = true
+ binding.jjTrendButton.text = "#성수동 맛집"
+ delay(2000)
+ binding.jjTrendButton.isEnabled = false
+ binding.jjTrendButton.text = "#카페 마이야르"
+ delay(2000)
+ }
+ }
+ }
+
+ private fun initJjMapButton() {
+ CoroutineScope(Dispatchers.Main).launch {
+ while (isActive) {
+ binding.jjMapButton.setJjMapType(Add)
+ delay(2000)
+ binding.jjMapButton.setJjMapType(Minus)
+ delay(2000)
+ binding.jjMapButton.setJjMapType(Position)
+ delay(2000)
+ }
+ }
+ }
+
+ private fun initJjPlusButton() {
+ CoroutineScope(Dispatchers.Main).launch {
+ while (isActive) {
+ binding.jjPlusButton.iconDrawable = com.android.jj_design.R.drawable.icon_add
+ delay(2000)
+ binding.jjPlusButton.iconDrawable = com.android.jj_design.R.drawable.icon_minus
+ delay(2000)
+ binding.jjPlusButton.iconDrawable = com.android.jj_design.R.drawable.icon_pencil
+ delay(2000)
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_design_component_sample.xml b/app/src/main/res/layout/activity_design_component_sample.xml
new file mode 100644
index 00000000..656719d9
--- /dev/null
+++ b/app/src/main/res/layout/activity_design_component_sample.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/.gitignore b/jj_design/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/jj_design/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/jj_design/README.md b/jj_design/README.md
new file mode 100644
index 00000000..262ffa3e
--- /dev/null
+++ b/jj_design/README.md
@@ -0,0 +1,133 @@
+# JJUPBAK Design System
+## Getting Started
+- [Button](#button)
+ - [JjButton](#jjbutton)
+ - [JjIconButton](#jjiconbutton)
+ - [JjChipButton](#jjchipbutton)
+ - [JjPlusButton](#jjplusbutton)
+ - [JjTrendButton](#jjtrendbutton)
+ - [JjMapButton](#jjmapbutton)
+
+## Button
+! Button Design Component example
+
+![alt text](images/button_test.gif)
+### JjButton
+
+
+- XML Code
+```kotlin
+
+```
+- Programmatically Code
+ - Enabled Button
+ ![alt text](images/jjbutton_enabled.png)
+ ```kotlin
+ binding.jjButton.isEnabled = true
+ ```
+ - Disabled Button
+ ![alt text](images/jjbutton_disabled.png)
+ ```kotlin
+ binding.jjButton.isEnabled = true
+ ```
+ - Error Button
+ ![alt text](images/jjbutton_error.png)
+ ```kotlin
+ binding.jjButton.setErrorBackground()
+ ```
+
+### JjIconButton
+![alt text](images/jjiconbutton.png)
+
+- XML Code
+```kotlin
+
+```
+
+### JjChipButton
+![alt text](images/jjchipbutton.png)
+
+- XML Code
+```kotlin
+
+ // Delete, Confirm, Requested, Follow, Following
+```
+
+- Programmatically Code (use jjChipType)
+ ```kotlin
+ binding.jjChipButton.chipItemType = Delete
+ ```
+
+### JjPlusButton
+![alt text](images/jjplusbutton.png)
+
+- XML Code
+```kotlin
+
+```
+
+- Programmatically Code
+```kotlin
+binding.jjPlusButton.iconDrawable = R.drawable.icon_add
+```
+내부 아이콘을 변경할 수 있음.
+
+### JjTrendButton
+
+- XML Code
+```kotlin
+
+```
+
+- Programmatically Code
+ - Enabled Trend Button
+ ![alt text](images/jjtrendbutton_enabled.png)
+ ```kotlin
+ binding.jjTrendButton.isEnabled = true
+ ```
+
+ - Disabled Trend Button
+ ![alt text](images/jjtrendbutton_disabled.png)
+ ```kotlin
+ binding.jjTrendButton.isEnabled = false
+ ```
+
+
+### JjMapButton
+![alt text](images/jjmapbutton.png)
+
+- XML Code
+```kotlin
+
+ // Add, Minus, Position
+```
+
+- Programmatically Code
+```kotlin
+binding.jjMapButton.setJjMapType(Add) // Minus, Position
+```
\ No newline at end of file
diff --git a/jj_design/build.gradle.kts b/jj_design/build.gradle.kts
new file mode 100644
index 00000000..65db4566
--- /dev/null
+++ b/jj_design/build.gradle.kts
@@ -0,0 +1,44 @@
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "com.android.jj_design"
+ compileSdk = 33
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+dependencies {
+
+ implementation("androidx.core:core-ktx:1.8.0")
+ implementation("androidx.appcompat:appcompat:1.6.1")
+ implementation("com.google.android.material:material:1.8.0")
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ testImplementation("junit:junit:4.13.2")
+ androidTestImplementation("androidx.test.ext:junit:1.1.5")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+}
\ No newline at end of file
diff --git a/jj_design/consumer-rules.pro b/jj_design/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/jj_design/images/button_test.gif b/jj_design/images/button_test.gif
new file mode 100644
index 00000000..a8dcdf6b
Binary files /dev/null and b/jj_design/images/button_test.gif differ
diff --git a/jj_design/images/jjbutton.png b/jj_design/images/jjbutton.png
new file mode 100644
index 00000000..0a92bd91
Binary files /dev/null and b/jj_design/images/jjbutton.png differ
diff --git a/jj_design/images/jjbutton_disabled.png b/jj_design/images/jjbutton_disabled.png
new file mode 100644
index 00000000..d5aa8cf5
Binary files /dev/null and b/jj_design/images/jjbutton_disabled.png differ
diff --git a/jj_design/images/jjbutton_enabled.png b/jj_design/images/jjbutton_enabled.png
new file mode 100644
index 00000000..0f05c7be
Binary files /dev/null and b/jj_design/images/jjbutton_enabled.png differ
diff --git a/jj_design/images/jjbutton_error.png b/jj_design/images/jjbutton_error.png
new file mode 100644
index 00000000..29422741
Binary files /dev/null and b/jj_design/images/jjbutton_error.png differ
diff --git a/jj_design/images/jjchipbutton.png b/jj_design/images/jjchipbutton.png
new file mode 100644
index 00000000..8b056d2b
Binary files /dev/null and b/jj_design/images/jjchipbutton.png differ
diff --git a/jj_design/images/jjiconbutton.png b/jj_design/images/jjiconbutton.png
new file mode 100644
index 00000000..7903c62f
Binary files /dev/null and b/jj_design/images/jjiconbutton.png differ
diff --git a/jj_design/images/jjmapbutton.png b/jj_design/images/jjmapbutton.png
new file mode 100644
index 00000000..30fd9a80
Binary files /dev/null and b/jj_design/images/jjmapbutton.png differ
diff --git a/jj_design/images/jjplusbutton.png b/jj_design/images/jjplusbutton.png
new file mode 100644
index 00000000..f6e5a48f
Binary files /dev/null and b/jj_design/images/jjplusbutton.png differ
diff --git a/jj_design/images/jjtrendbutton_disabled.png b/jj_design/images/jjtrendbutton_disabled.png
new file mode 100644
index 00000000..7cf05489
Binary files /dev/null and b/jj_design/images/jjtrendbutton_disabled.png differ
diff --git a/jj_design/images/jjtrendbutton_enabled.png b/jj_design/images/jjtrendbutton_enabled.png
new file mode 100644
index 00000000..aac390cd
Binary files /dev/null and b/jj_design/images/jjtrendbutton_enabled.png differ
diff --git a/jj_design/proguard-rules.pro b/jj_design/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/jj_design/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/jj_design/src/androidTest/java/com/android/jj_design/ExampleInstrumentedTest.kt b/jj_design/src/androidTest/java/com/android/jj_design/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..59d7fa99
--- /dev/null
+++ b/jj_design/src/androidTest/java/com/android/jj_design/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.android.jj_design
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.android.jj_design.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/jj_design/src/main/AndroidManifest.xml b/jj_design/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..74b7379f
--- /dev/null
+++ b/jj_design/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/java/com/android/jj_design/button/JjButton.kt b/jj_design/src/main/java/com/android/jj_design/button/JjButton.kt
new file mode 100644
index 00000000..784941ef
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/button/JjButton.kt
@@ -0,0 +1,56 @@
+package com.android.jj_design.button
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Gravity
+import androidx.appcompat.widget.AppCompatButton
+import com.android.jj_design.R
+import com.android.jj_design.utils.px
+
+class JjButton @JvmOverloads constructor(
+ context: Context,
+ attributeSet: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : AppCompatButton(context, attributeSet, defStyleAttr) {
+ init {
+ initSetting()
+ context.theme.obtainStyledAttributes(
+ attributeSet, R.styleable.JjButton, defStyleAttr, 0
+ ).apply {
+ this@JjButton.let { btnAttr ->
+ // background
+ btnAttr.setBackgroundResource(R.drawable.jj_button_selector)
+
+ // elevation
+ btnAttr.elevation = ELEVATION.px.toFloat()
+ }
+ recycle()
+ }
+ }
+
+ private fun initSetting() {
+ setTextAppearance(R.style.JJ_TextAppearance_Medium_16) // TextStyle
+ minWidth = MIN_WIDTH.px
+ gravity = Gravity.CENTER
+ setPadding(0, VERTICAL_PADDING.px, 0, VERTICAL_PADDING.px)
+ }
+
+ fun setErrorBackground() {
+ setTextColor(context.getColor(R.color.color_FF7F23))
+ setBackgroundResource(R.drawable.jj_button_rect_solid_ffffff_stroke_ff7f23_radius_100)
+ elevation = 0f
+ }
+
+ override fun setEnabled(enabled: Boolean) {
+ super.setEnabled(enabled)
+ setBackgroundResource(R.drawable.jj_button_selector)
+ setTextColor(context.getColor(R.color.color_white))
+ elevation = ELEVATION.px.toFloat()
+ }
+
+ companion object {
+ private const val MIN_WIDTH = 170
+ private const val VERTICAL_PADDING = 10
+ private const val ELEVATION = 10
+ }
+}
diff --git a/jj_design/src/main/java/com/android/jj_design/button/JjChipButton.kt b/jj_design/src/main/java/com/android/jj_design/button/JjChipButton.kt
new file mode 100644
index 00000000..e320a8a6
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/button/JjChipButton.kt
@@ -0,0 +1,86 @@
+package com.android.jj_design.button
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Gravity
+import androidx.appcompat.widget.AppCompatButton
+import androidx.core.content.ContextCompat
+import com.android.jj_design.R
+import com.android.jj_design.utils.button.Confirm
+import com.android.jj_design.utils.button.Delete
+import com.android.jj_design.utils.button.Follow
+import com.android.jj_design.utils.button.Following
+import com.android.jj_design.utils.button.JjChipType
+import com.android.jj_design.utils.button.Requested
+import com.android.jj_design.utils.px
+import com.android.jj_design.utils.toJjChipType
+
+class JjChipButton @JvmOverloads constructor(
+ context: Context,
+ attributeSet: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : AppCompatButton(context, attributeSet, defStyleAttr) {
+ var chipItemType: JjChipType? = null
+ set(value) {
+ when (value) {
+ Confirm -> {
+ text = value.name
+ setTextColor(ContextCompat.getColor(context, R.color.color_white))
+ setBackgroundResource(R.drawable.jj_small_button_rect_solid_f6bf54)
+ }
+
+ Delete -> {
+ text = value.name
+ setTextColor(ContextCompat.getColor(context, R.color.color_222222))
+ setBackgroundResource(R.drawable.jj_small_button_rect_solid_eeeeee)
+ }
+
+ Follow -> {
+ text = value.name
+ setTextColor(ContextCompat.getColor(context, R.color.color_white))
+ setBackgroundResource(R.drawable.jj_small_button_rect_solid_ff7f23)
+ }
+
+ Following -> {
+ text = value.name
+ setTextColor(ContextCompat.getColor(context, R.color.color_222222))
+ setBackgroundResource(R.drawable.jj_small_button_rect_solid_eeeeee)
+ }
+
+ Requested -> {
+ text = value.name
+ setTextColor(ContextCompat.getColor(context, R.color.color_666666))
+ setBackgroundResource(R.drawable.jj_small_button__rect_solid_ffffff_stroke_222222)
+ }
+
+ else -> Unit
+ }
+ field = value
+ }
+
+ init {
+ initSetting()
+
+ context.theme.obtainStyledAttributes(
+ attributeSet, R.styleable.JjChipButton, 0, 0
+ ).apply {
+ this@JjChipButton.let { smallBtnAttr ->
+ // item type
+ chipItemType = getInt(R.styleable.JjChipButton_jjChipType, 0).toJjChipType
+ }
+ recycle()
+ }
+ }
+
+ private fun initSetting() {
+ setTextAppearance(R.style.JJ_TextAppearance_Medium_12)
+ minWidth = MIN_WIDTH.px
+ gravity = Gravity.CENTER
+ setPadding(0, VERTICAL_PADDING.px, 0, VERTICAL_PADDING.px)
+ }
+
+ companion object {
+ private const val MIN_WIDTH = 64
+ private const val VERTICAL_PADDING = 8
+ }
+}
diff --git a/jj_design/src/main/java/com/android/jj_design/button/JjIconButton.kt b/jj_design/src/main/java/com/android/jj_design/button/JjIconButton.kt
new file mode 100644
index 00000000..3f6014a1
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/button/JjIconButton.kt
@@ -0,0 +1,56 @@
+package com.android.jj_design.button
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.appcompat.widget.AppCompatButton
+import com.android.jj_design.R
+import com.android.jj_design.utils.px
+
+class JjIconButton @JvmOverloads constructor(
+ context: Context,
+ attributeSet: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : AppCompatButton(context, attributeSet, defStyleAttr) {
+ init {
+ initSetting()
+ context.theme.obtainStyledAttributes(
+ attributeSet, R.styleable.JjIconButton, 0, 0
+ ).apply {
+ this@JjIconButton.let { iconBtnAttr ->
+ // text
+ iconBtnAttr.text = getString(R.styleable.JjIconButton_jjIconText)
+ iconBtnAttr.setTextColor(getColor(R.styleable.JjIconButton_jjIconTextColor, 0))
+
+ // icon
+ iconBtnAttr.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ getDrawable(R.styleable.JjIconButton_jjIconDrawableStart), null, null, null
+ )
+ iconBtnAttr.compoundDrawablePadding = DRAWABLE_PADDING.px
+
+ // background
+ iconBtnAttr.setBackgroundResource(R.drawable.jj_button_rect_solid_ffffff_stroke_c4c4c4_radius_100)
+
+ // elevation
+ iconBtnAttr.elevation = ELEVATION.px.toFloat()
+ }
+ recycle()
+ }
+ }
+
+ private fun initSetting() {
+ setPadding(
+ HORIZONTAL_PADDING.px,
+ VERTICAL_PADDING.px,
+ HORIZONTAL_PADDING.px,
+ VERTICAL_PADDING.px
+ )
+ setTextAppearance(R.style.JJ_TextAppearance_Medium_14)
+ }
+
+ companion object {
+ private const val HORIZONTAL_PADDING = 28
+ private const val VERTICAL_PADDING = 10
+ private const val ELEVATION = 10
+ private const val DRAWABLE_PADDING = 8
+ }
+}
\ No newline at end of file
diff --git a/jj_design/src/main/java/com/android/jj_design/button/JjMapButton.kt b/jj_design/src/main/java/com/android/jj_design/button/JjMapButton.kt
new file mode 100644
index 00000000..08c473be
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/button/JjMapButton.kt
@@ -0,0 +1,126 @@
+package com.android.jj_design.button
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import androidx.annotation.ColorRes
+import androidx.annotation.DrawableRes
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.DrawableCompat
+import androidx.core.graphics.drawable.toBitmap
+import com.android.jj_design.R
+import com.android.jj_design.utils.button.Add
+import com.android.jj_design.utils.button.JjMapType
+import com.android.jj_design.utils.button.Minus
+import com.android.jj_design.utils.button.Position
+import com.android.jj_design.utils.px
+import com.android.jj_design.utils.toJjMapType
+
+class JjMapButton @JvmOverloads constructor(
+ context: Context,
+ attributeSet: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : View(context, attributeSet, defStyleAttr) {
+ private val imageButtonPaint = Paint()
+ private var imageBitmap: Bitmap? = null
+
+ init {
+ setLayerType(LAYER_TYPE_SOFTWARE, null)
+ context.theme.obtainStyledAttributes(
+ attributeSet, R.styleable.JjMapButton, 0, 0
+ ).apply {
+ setJjMapType(getInt(R.styleable.JjMapButton_jjMapType, 0).toJjMapType)
+ recycle()
+ }
+ }
+
+ fun setJjMapType(type: JjMapType?) {
+ when (type) {
+ Add -> setJjMapUi(R.color.color_white, R.drawable.icon_add, R.color.color_666666)
+ Minus -> setJjMapUi(R.color.color_white, R.drawable.icon_minus, R.color.color_666666)
+ Position -> setJjMapUi(
+ R.color.color_FF7F23,
+ R.drawable.icon_position,
+ R.color.color_FFFFFF
+ )
+
+ else -> Unit
+ }
+ }
+
+ private fun setJjMapUi(
+ @ColorRes buttonColor: Int,
+ @DrawableRes imageDrawable: Int,
+ @ColorRes imageColor: Int,
+ ) {
+ imageButtonPaint.apply {
+ imageButtonPaint.color = context.getColor(buttonColor)
+ setShadowLayer(
+ IMAGE_SHADOW.px.toFloat() / 2,
+ IMAGE_SHADOW.px.toFloat(),
+ IMAGE_SHADOW.px.toFloat(),
+ Color.LTGRAY
+ )
+ }
+ imageBitmap = ContextCompat.getDrawable(context, imageDrawable).also { icon ->
+ icon?.mutate()
+ }?.also { iconDrawable ->
+ DrawableCompat.setTint(iconDrawable, context.getColor(imageColor))
+ }?.toBitmap(IMAGE_SIZE.px, IMAGE_SIZE.px)
+ invalidate()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ if (measureMode(widthMeasureSpec) && measureMode(heightMeasureSpec)) {
+ setMeasuredDimension(
+ MeasureSpec.getMode(widthMeasureSpec),
+ MeasureSpec.getMode(heightMeasureSpec)
+ )
+ } else {
+ setMeasuredDimension(LAYOUT_SIZE.px + IMAGE_SHADOW.px, LAYOUT_SIZE.px + IMAGE_SHADOW.px)
+ }
+ }
+
+ private fun measureMode(measureSpec: Int): Boolean =
+ MeasureSpec.getMode(measureSpec) == MeasureSpec.EXACTLY
+
+
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+
+ canvas?.drawCircle(
+ POSITION_X.px.toFloat(),
+ POSITION_Y.px.toFloat(),
+ RADIUS.px.toFloat(),
+ imageButtonPaint
+ )
+ imageBitmap?.let {
+ canvas?.drawBitmap(
+ it,
+ IMAGE_POSITION_X.px.toFloat(),
+ IMAGE_POSITION_Y.px.toFloat(),
+ null
+ )
+ }
+ }
+
+ companion object {
+ private const val LAYOUT_SIZE = 64
+ private const val IMAGE_SHADOW = 2
+
+ private const val POSITION_X = LAYOUT_SIZE / 2
+ private const val POSITION_Y = LAYOUT_SIZE / 2
+
+ private const val RADIUS = LAYOUT_SIZE / 2
+
+ private const val IMAGE_SIZE = 44
+ private const val IMAGE_POSITION_X = (LAYOUT_SIZE - IMAGE_SIZE) / 2
+ private const val IMAGE_POSITION_Y = (LAYOUT_SIZE - IMAGE_SIZE) / 2
+ }
+}
diff --git a/jj_design/src/main/java/com/android/jj_design/button/JjPlusButton.kt b/jj_design/src/main/java/com/android/jj_design/button/JjPlusButton.kt
new file mode 100644
index 00000000..ea4ff243
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/button/JjPlusButton.kt
@@ -0,0 +1,89 @@
+package com.android.jj_design.button
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import androidx.annotation.DrawableRes
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.toBitmap
+import com.android.jj_design.R
+import com.android.jj_design.utils.px
+
+class JjPlusButton @JvmOverloads constructor(
+ context: Context,
+ attributeSet: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : View(context, attributeSet, defStyleAttr) {
+ private val plusButtonPaint = Paint()
+ private var plusBitmap: Bitmap?
+
+ var iconDrawable: Int? = null
+ set(@DrawableRes value) {
+ plusBitmap = value?.let {
+ ContextCompat.getDrawable(context, it)
+ ?.toBitmap(PLUS_IMAGE_SIZE.px, PLUS_IMAGE_SIZE.px)
+ }
+ invalidate()
+ field = value
+ }
+
+ init {
+ plusButtonPaint.apply {
+ color = context.getColor(R.color.color_50EEEEEE)
+ }
+ plusBitmap = ContextCompat.getDrawable(context, R.drawable.icon_plus)
+ ?.toBitmap(PLUS_IMAGE_SIZE.px, PLUS_IMAGE_SIZE.px)
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ if (measureMode(widthMeasureSpec) && measureMode(heightMeasureSpec)) {
+ setMeasuredDimension(
+ MeasureSpec.getMode(widthMeasureSpec),
+ MeasureSpec.getMode(heightMeasureSpec)
+ )
+ } else {
+ setMeasuredDimension(LAYOUT_SIZE.px, LAYOUT_SIZE.px)
+ }
+ }
+
+ private fun measureMode(measureSpec: Int): Boolean =
+ MeasureSpec.getMode(measureSpec) == MeasureSpec.EXACTLY
+
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+
+ canvas?.drawCircle(
+ POSITION_X.px.toFloat(),
+ POSITION_Y.px.toFloat(),
+ RADIUS.px.toFloat(),
+ plusButtonPaint
+ )
+
+ plusBitmap?.let {
+ canvas?.drawBitmap(
+ it,
+ PLUS_IMAGE_POSITION_X.px.toFloat(),
+ PLUS_IMAGE_POSITION_Y.px.toFloat(),
+ null
+ )
+ }
+ }
+
+ companion object {
+ private const val LAYOUT_SIZE = 24
+
+ private const val POSITION_X = LAYOUT_SIZE / 2
+ private const val POSITION_Y = LAYOUT_SIZE / 2
+
+ private const val RADIUS = LAYOUT_SIZE / 2
+
+ private const val PLUS_IMAGE_SIZE = 20
+ private const val PLUS_IMAGE_POSITION_X = (LAYOUT_SIZE - PLUS_IMAGE_SIZE) / 2
+ private const val PLUS_IMAGE_POSITION_Y = (LAYOUT_SIZE - PLUS_IMAGE_SIZE) / 2
+ }
+}
\ No newline at end of file
diff --git a/jj_design/src/main/java/com/android/jj_design/button/JjTrendButton.kt b/jj_design/src/main/java/com/android/jj_design/button/JjTrendButton.kt
new file mode 100644
index 00000000..52329d9a
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/button/JjTrendButton.kt
@@ -0,0 +1,44 @@
+package com.android.jj_design.button
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.appcompat.widget.AppCompatButton
+import com.android.jj_design.R
+import com.android.jj_design.utils.px
+
+class JjTrendButton @JvmOverloads constructor(
+ context: Context,
+ attributeSet: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : AppCompatButton(context, attributeSet, defStyleAttr) {
+
+ init {
+ initSetting()
+ }
+
+ private fun initSetting() {
+ setTextAppearance(R.style.JJ_TextAppearance_Medium_12)
+ setPadding(
+ HORIZONTAL_PADDING.px,
+ VERTICAL_PADDING.px,
+ HORIZONTAL_PADDING.px,
+ VERTICAL_PADDING.px
+ )
+ }
+
+ override fun setEnabled(enabled: Boolean) {
+ super.setEnabled(enabled)
+ if (enabled) {
+ setTextColor(context.getColor(R.color.color_FF7F23))
+ setBackgroundResource(R.drawable.jj_button_rect_solid_20f6bf54_stroke_ff7f23_radius_100)
+ } else {
+ setTextColor(context.getColor(R.color.color_C4C4C4))
+ setBackgroundResource(R.drawable.jj_button_rect_solid_ffffff_stroke_c4c4c4_radius_100)
+ }
+ }
+
+ companion object {
+ private const val HORIZONTAL_PADDING = 8
+ private const val VERTICAL_PADDING = 6
+ }
+}
diff --git a/jj_design/src/main/java/com/android/jj_design/utils/CustomViewExtensions.kt b/jj_design/src/main/java/com/android/jj_design/utils/CustomViewExtensions.kt
new file mode 100644
index 00000000..d2257a5d
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/utils/CustomViewExtensions.kt
@@ -0,0 +1,33 @@
+package com.android.jj_design.utils
+
+import android.content.res.Resources
+import com.android.jj_design.utils.button.Add
+import com.android.jj_design.utils.button.Confirm
+import com.android.jj_design.utils.button.Delete
+import com.android.jj_design.utils.button.Follow
+import com.android.jj_design.utils.button.Following
+import com.android.jj_design.utils.button.JjChipType
+import com.android.jj_design.utils.button.JjMapType
+import com.android.jj_design.utils.button.Minus
+import com.android.jj_design.utils.button.Position
+import com.android.jj_design.utils.button.Requested
+
+val Int.px get(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
+
+val Int.toJjChipType
+ get(): JjChipType? = when (this) {
+ 1 -> Delete
+ 2 -> Follow
+ 3 -> Following
+ 4 -> Confirm
+ 5 -> Requested
+ else -> null
+ }
+
+val Int.toJjMapType
+ get(): JjMapType? = when (this) {
+ 1 -> Add
+ 2 -> Minus
+ 3 -> Position
+ else -> null
+ }
\ No newline at end of file
diff --git a/jj_design/src/main/java/com/android/jj_design/utils/DesignConstants.kt b/jj_design/src/main/java/com/android/jj_design/utils/DesignConstants.kt
new file mode 100644
index 00000000..257ddd74
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/utils/DesignConstants.kt
@@ -0,0 +1,9 @@
+package com.android.jj_design.utils
+
+object DesignConstants {
+ const val DELETE = "삭제"
+ const val FOLLOW = "팔로우"
+ const val FOLLOWING = "팔로잉"
+ const val CONFIRM = "확인"
+ const val REQUESTED = "요청됨"
+}
\ No newline at end of file
diff --git a/jj_design/src/main/java/com/android/jj_design/utils/button/JjChipItemType.kt b/jj_design/src/main/java/com/android/jj_design/utils/button/JjChipItemType.kt
new file mode 100644
index 00000000..98e43ab9
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/utils/button/JjChipItemType.kt
@@ -0,0 +1,15 @@
+package com.android.jj_design.utils.button
+
+import com.android.jj_design.utils.DesignConstants.CONFIRM
+import com.android.jj_design.utils.DesignConstants.DELETE
+import com.android.jj_design.utils.DesignConstants.FOLLOW
+import com.android.jj_design.utils.DesignConstants.FOLLOWING
+import com.android.jj_design.utils.DesignConstants.REQUESTED
+
+sealed class JjChipType(val name: String?)
+object Delete : JjChipType(DELETE)
+object Follow : JjChipType(FOLLOW)
+object Following : JjChipType(FOLLOWING)
+object Confirm : JjChipType(CONFIRM)
+object Requested : JjChipType(REQUESTED)
+
diff --git a/jj_design/src/main/java/com/android/jj_design/utils/button/JjMapType.kt b/jj_design/src/main/java/com/android/jj_design/utils/button/JjMapType.kt
new file mode 100644
index 00000000..82c9c1e4
--- /dev/null
+++ b/jj_design/src/main/java/com/android/jj_design/utils/button/JjMapType.kt
@@ -0,0 +1,6 @@
+package com.android.jj_design.utils.button
+
+sealed class JjMapType
+object Add : JjMapType()
+object Minus : JjMapType()
+object Position : JjMapType()
diff --git a/jj_design/src/main/res/drawable/icon_add.xml b/jj_design/src/main/res/drawable/icon_add.xml
new file mode 100644
index 00000000..61f3ca71
--- /dev/null
+++ b/jj_design/src/main/res/drawable/icon_add.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/jj_design/src/main/res/drawable/icon_minus.xml b/jj_design/src/main/res/drawable/icon_minus.xml
new file mode 100644
index 00000000..a6cee466
--- /dev/null
+++ b/jj_design/src/main/res/drawable/icon_minus.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/jj_design/src/main/res/drawable/icon_pencil.xml b/jj_design/src/main/res/drawable/icon_pencil.xml
new file mode 100644
index 00000000..d46ff0f0
--- /dev/null
+++ b/jj_design/src/main/res/drawable/icon_pencil.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/jj_design/src/main/res/drawable/icon_plus.xml b/jj_design/src/main/res/drawable/icon_plus.xml
new file mode 100644
index 00000000..0d32b1e8
--- /dev/null
+++ b/jj_design/src/main/res/drawable/icon_plus.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/jj_design/src/main/res/drawable/icon_position.xml b/jj_design/src/main/res/drawable/icon_position.xml
new file mode 100644
index 00000000..3a35e341
--- /dev/null
+++ b/jj_design/src/main/res/drawable/icon_position.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
diff --git a/jj_design/src/main/res/drawable/jj_button_rect_solid_20f6bf54_stroke_ff7f23_radius_100.xml b/jj_design/src/main/res/drawable/jj_button_rect_solid_20f6bf54_stroke_ff7f23_radius_100.xml
new file mode 100644
index 00000000..62bdd436
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_button_rect_solid_20f6bf54_stroke_ff7f23_radius_100.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_button_rect_solid_c4c4c4_radius_100.xml b/jj_design/src/main/res/drawable/jj_button_rect_solid_c4c4c4_radius_100.xml
new file mode 100644
index 00000000..301f36c0
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_button_rect_solid_c4c4c4_radius_100.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_button_rect_solid_ff7f23_radius_100.xml b/jj_design/src/main/res/drawable/jj_button_rect_solid_ff7f23_radius_100.xml
new file mode 100644
index 00000000..ac4c08d5
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_button_rect_solid_ff7f23_radius_100.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_button_rect_solid_ffffff_stroke_c4c4c4_radius_100.xml b/jj_design/src/main/res/drawable/jj_button_rect_solid_ffffff_stroke_c4c4c4_radius_100.xml
new file mode 100644
index 00000000..35138d11
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_button_rect_solid_ffffff_stroke_c4c4c4_radius_100.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_button_rect_solid_ffffff_stroke_ff7f23_radius_100.xml b/jj_design/src/main/res/drawable/jj_button_rect_solid_ffffff_stroke_ff7f23_radius_100.xml
new file mode 100644
index 00000000..bfc8f120
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_button_rect_solid_ffffff_stroke_ff7f23_radius_100.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_button_selector.xml b/jj_design/src/main/res/drawable/jj_button_selector.xml
new file mode 100644
index 00000000..a8b25e5f
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_button_selector.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_small_button__rect_solid_ffffff_stroke_222222.xml b/jj_design/src/main/res/drawable/jj_small_button__rect_solid_ffffff_stroke_222222.xml
new file mode 100644
index 00000000..e934d8e4
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_small_button__rect_solid_ffffff_stroke_222222.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_small_button_rect_solid_eeeeee.xml b/jj_design/src/main/res/drawable/jj_small_button_rect_solid_eeeeee.xml
new file mode 100644
index 00000000..c779d656
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_small_button_rect_solid_eeeeee.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_small_button_rect_solid_f6bf54.xml b/jj_design/src/main/res/drawable/jj_small_button_rect_solid_f6bf54.xml
new file mode 100644
index 00000000..c6af9ce2
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_small_button_rect_solid_f6bf54.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/drawable/jj_small_button_rect_solid_ff7f23.xml b/jj_design/src/main/res/drawable/jj_small_button_rect_solid_ff7f23.xml
new file mode 100644
index 00000000..ac4c08d5
--- /dev/null
+++ b/jj_design/src/main/res/drawable/jj_small_button_rect_solid_ff7f23.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/font-v26/suit_bold.xml b/jj_design/src/main/res/font-v26/suit_bold.xml
new file mode 100644
index 00000000..38139a6c
--- /dev/null
+++ b/jj_design/src/main/res/font-v26/suit_bold.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/font-v26/suit_medium.xml b/jj_design/src/main/res/font-v26/suit_medium.xml
new file mode 100644
index 00000000..e5a6f272
--- /dev/null
+++ b/jj_design/src/main/res/font-v26/suit_medium.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/font-v26/suit_regular.xml b/jj_design/src/main/res/font-v26/suit_regular.xml
new file mode 100644
index 00000000..e55204d2
--- /dev/null
+++ b/jj_design/src/main/res/font-v26/suit_regular.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/font/suit_bold.xml b/jj_design/src/main/res/font/suit_bold.xml
new file mode 100644
index 00000000..ad42426d
--- /dev/null
+++ b/jj_design/src/main/res/font/suit_bold.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/font/suit_medium.xml b/jj_design/src/main/res/font/suit_medium.xml
new file mode 100644
index 00000000..8a2a6d62
--- /dev/null
+++ b/jj_design/src/main/res/font/suit_medium.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/font/suit_regular.xml b/jj_design/src/main/res/font/suit_regular.xml
new file mode 100644
index 00000000..4127ac2c
--- /dev/null
+++ b/jj_design/src/main/res/font/suit_regular.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/values/attrs.xml b/jj_design/src/main/res/values/attrs.xml
new file mode 100644
index 00000000..74a62feb
--- /dev/null
+++ b/jj_design/src/main/res/values/attrs.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/values/colors.xml b/jj_design/src/main/res/values/colors.xml
new file mode 100644
index 00000000..e34cb153
--- /dev/null
+++ b/jj_design/src/main/res/values/colors.xml
@@ -0,0 +1,21 @@
+
+
+ #FFFFFF
+ #000000
+
+
+ #222222
+ #666666
+ #C4C4C4
+ #EEEEEE
+ #FFFFFF
+
+
+ #F6BF54
+ #FF7F23
+ #C60000
+
+
+ #33F6BF54
+ #80EEEEEE
+
\ No newline at end of file
diff --git a/jj_design/src/main/res/values/typhograpy.xml b/jj_design/src/main/res/values/typhograpy.xml
new file mode 100644
index 00000000..e3981dd4
--- /dev/null
+++ b/jj_design/src/main/res/values/typhograpy.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jj_design/src/test/java/com/android/jj_design/ExampleUnitTest.kt b/jj_design/src/test/java/com/android/jj_design/ExampleUnitTest.kt
new file mode 100644
index 00000000..83a1ac7e
--- /dev/null
+++ b/jj_design/src/test/java/com/android/jj_design/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.android.jj_design
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 945aa54e..3bb00572 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -23,3 +23,4 @@ include(":app")
include(":data")
include(":domain")
include(":image_selector")
+include(":jj_design")