diff --git a/README.md b/README.md
index cc0acc5a..5a9dde07 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,41 @@
# android-contacts
+# 1단계 - 연락처 추가
+## 기능 요구사항
+간단한 연락처를 구현한다.
+- 연락처를 추가한다.
+
+
+
+- 이름과 전화번호는 필수 값이다.
+ - 입력하지 않으면 토스트 메시지를 보여준다.
+- 전화번호 입력은 숫자만 가능하다.
+- 더보기를 눌러 입력 폼을 확장할 수 있다.
+
+
+ - 생일, 성별, 메모 입력 폼이 등장한다.
+
+
+
+ - 성별을 둘 중 하나를 선택할 수 있다.
+- 저장 버튼을 누르면 '저장이 완료 되었습니다' 라는 토스트 메시지를 보여준다.
+- 취소 버튼을 누르면 '취소 되었습니다' 라는 토스트 메시지를 보여준다.
+
+# 2단계 - 연락처 목록
+## 기능 요구사항
+간단한 연락처를 구현한다.
+
+
+
+- 연락처 등록 화면을 구현한다.
+- 연락처를 저장하면 목록에 추가된다.
+
+
+
+ 저장된 연락처가 많을 경우 목록은 스크롤 되어야 한다.
+
+
+
+- 추가된 연락처를 선택하여 상세 화면을 볼 수 있다.
+-
+- 연락처 작성 중 뒤로가기 버튼을 누르면 확인 팝업이 나타난다.
+- 추가된 연락처는 앱을 다시 실행하면 유지되지 않는다.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c5add08f..cd416f47 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
+ id ("org.jetbrains.kotlin.kapt")
}
android {
@@ -33,6 +34,9 @@ android {
kotlinOptions {
jvmTarget = "17"
}
+ buildFeatures {
+ viewBinding = true
+ }
}
dependencies {
@@ -41,7 +45,18 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
- testImplementation("junit:junit:4.13.2")
+ implementation("androidx.activity:activity:1.9.0")
+ implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
+ implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
+ testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+
+ val room_version = "2.6.1"
+
+ implementation("androidx.room:room-runtime:$room_version")
+ annotationProcessor("androidx.room:room-compiler:$room_version")
+
+ // To use Kotlin annotation processing tool (kapt)
+ kapt("androidx.room:room-compiler:$room_version")
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89dc9d8b..5d8f4158 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,8 +12,21 @@
android:supportsRtl="true"
android:theme="@style/Theme.Contacts"
tools:targetApi="31">
+
+
+
+
+
+
+
+
@@ -23,4 +36,4 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/contacts/AddContactActivity.kt b/app/src/main/java/campus/tech/kakao/contacts/AddContactActivity.kt
new file mode 100644
index 00000000..bb08eb5c
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/contacts/AddContactActivity.kt
@@ -0,0 +1,178 @@
+package campus.tech.kakao.contacts
+
+import android.app.DatePickerDialog
+import android.os.Bundle
+import android.util.Log
+import android.view.KeyEvent
+import android.view.View
+import android.widget.EditText
+import android.widget.RadioButton
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.room.Room
+import campus.tech.kakao.contacts.Contact.Companion.MIGRATION_1_2
+import campus.tech.kakao.contacts.Contact.Companion.MIGRATION_2_3
+import java.util.Calendar
+
+class AddContactActivity : AppCompatActivity() {
+ // Declare UI elements
+ private lateinit var name: EditText
+ private lateinit var phone: EditText
+ private lateinit var mail: EditText
+ private lateinit var birth: TextView
+ private var sex:String? = null
+ private lateinit var female: RadioButton
+ private lateinit var male: RadioButton
+ private lateinit var memo: EditText
+ private lateinit var save: TextView
+ private lateinit var cancel: TextView
+ private lateinit var moreText: TextView
+ private lateinit var birthSexMemo: View
+
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_addcontact)
+ setupUI()
+ birth.setOnClickListener {
+ showDatePickerDialog()
+ }
+ // 더보기 버튼 클릭 시
+ moreText.setOnClickListener {
+ if (moreText.visibility == View.VISIBLE) {
+ moreText.visibility = View.GONE
+ birthSexMemo.visibility = View.VISIBLE
+ } else {
+ moreText.visibility = View.VISIBLE
+ birthSexMemo.visibility = View.GONE
+ }
+ }
+ // Initialize database
+ val database = Room.databaseBuilder(
+ applicationContext,
+ ContactDatabase::class.java, "database-name"
+ ).addMigrations(MIGRATION_1_2, MIGRATION_2_3).allowMainThreadQueries().build()
+
+ // 저장 버튼 클릭 시
+ save.setOnClickListener {
+ if (name.text.isEmpty()) {
+ Toast.makeText(this, "이름은 필수 값입니다", Toast.LENGTH_SHORT).show()
+ }
+ else if (phone.text.isEmpty()) {
+ Toast.makeText(this, "전화 번호는 필수 값입니다", Toast.LENGTH_SHORT).show()
+ }
+ else{
+ if (female.isChecked) {
+ sex = "여자"
+ }
+ else if (male.isChecked) {
+ sex = "남자"
+ }
+ // Insert data into database
+ val contact = Contact(
+ name.text.toString(),
+ phone.text.toString(),
+ mail.text.toString(),
+ birth.text.toString(),
+ sex,
+ memo.text.toString()
+ )
+ database.contactDao().insert(contact)
+ Toast.makeText(this, "저장이 완료 되었습니다", Toast.LENGTH_SHORT).show()
+ finish()
+ }
+
+ }
+ // 연락처 데이터 로그에 표시
+ fun loadAllData(){
+ if (database.contactDao() == null){
+ Log.d("contacttest", "null")
+ }
+ else{
+ val list = database.contactDao().getAll()
+ list.forEach {
+ Log.d("contacttest", ""+it.id+", "+it.name+", "+it.phone+", "+it.email+", "+it.birth+", "+it.sex+", "+it.memo)
+ }
+ }
+ }
+ //취소 버튼 클릭 시
+ cancel.setOnClickListener {
+ Toast.makeText(this, "취소 되었습니다", Toast.LENGTH_SHORT).show()
+ loadAllData()
+ finish()
+ }
+
+
+
+
+ }
+
+ private fun setupUI() {
+ name = findViewById(R.id.name)
+ phone = findViewById(R.id.phone)
+ mail = findViewById(R.id.mail)
+ birth = findViewById(R.id.birth)
+ female = findViewById(R.id.female)
+ male = findViewById(R.id.male)
+ memo = findViewById(R.id.memo)
+ save = findViewById(R.id.save)
+ cancel = findViewById(R.id.cancel)
+ birthSexMemo = findViewById(R.id.birthSexMemo)
+ moreText = findViewById(R.id.moreText)
+ }
+
+ // 생일 선택 팝업창
+ fun showDatePickerDialog() {
+ val calendar = Calendar.getInstance()
+ val datePicker = DatePickerDialog(
+ this, {DatePicker, year:Int, month:Int, dayOfMonth:Int ->
+ //월과 일 포맷을 00으로 설정
+ var Month = "${month + 1}"
+ if (month < 9) {
+ Month = "0${Month}"
+ }
+ var Day = "${dayOfMonth}"
+ if (dayOfMonth < 10) {
+ Day = "0${Day}"
+ }
+ birth.text = "${year}.${Month}.${Day}"
+ }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH))
+ datePicker.show()
+ }
+ //팝업창 설정
+ fun popupMessage(){
+ //팝업 UI 설정
+ val popupView = layoutInflater.inflate(R.layout.popup_message, null)
+ val write = popupView.findViewById(R.id.write)
+ val exit = popupView.findViewById(R.id.exit)
+
+ val popupBuilder = AlertDialog.Builder(this).setView(popupView)
+ val popupWindow = popupBuilder.show()
+ //작성하기 버튼 클릭 시 팝업창 닫기
+ write.setOnClickListener {
+ popupWindow.dismiss()
+ }
+ //나가기 버튼 클릭 시 연락처 목록으로 이동
+ exit.setOnClickListener {
+ finish()
+ }
+ }
+
+ //뒤로 가기 버튼 클릭 시
+ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
+ //뒤로 가기 버튼 클릭하고 나머지 텍스트가 있을 경우
+ if (keyCode == KeyEvent.KEYCODE_BACK
+ && (name.text.isNotEmpty() || phone.text.isNotEmpty()
+ || mail.text.isNotEmpty() || birth.text.isNotEmpty()
+ || (female.isChecked || male.isChecked) || memo.text.isNotEmpty())) {
+ popupMessage()
+ return true
+ }
+ else if (keyCode == KeyEvent.KEYCODE_BACK){
+ finish()
+ }
+ return false
+ }
+}
diff --git a/app/src/main/java/campus/tech/kakao/contacts/Contact.kt b/app/src/main/java/campus/tech/kakao/contacts/Contact.kt
new file mode 100644
index 00000000..f67db21c
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/contacts/Contact.kt
@@ -0,0 +1,71 @@
+package campus.tech.kakao.contacts
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+@Entity
+class Contact (
+ @PrimaryKey(autoGenerate = true) val id: Int,
+ @ColumnInfo(name = "name") val name: String,
+ @ColumnInfo(name = "phone") val phone: String,
+ @ColumnInfo(name = "email") val email: String?,
+ @ColumnInfo(name = "birth") val birth: String?,
+ @ColumnInfo(name = "sex") val sex: String?,
+ @ColumnInfo(name = "memo") val memo: String?
+){
+ constructor(name: String, phone: String, email: String?, birth: String?, sex: String?, memo: String?):
+ this(0, name, phone, email, birth, sex, memo)
+
+ companion object {
+ // 테이블 변경 사항
+ val MIGRATION_1_2 = object : Migration(1, 2) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL(
+ "CREATE TABLE new_Contact (" +
+ "id INTEGER PRIMARY KEY NOT NULL, " +
+ "name TEXT NOT NULL, " +
+ "phone INTEGER NOT NULL, " +
+ "email TEXT, " +
+ "birth TEXT, " +
+ "sex TEXT, " +
+ "memo TEXT)"
+ )
+ // 데이터 복사
+ database.execSQL(
+ "INSERT INTO new_Contact (id, name, phone, email, birth, sex, memo) " +
+ "SELECT id, name, CAST(phone AS INTEGER), email, birth, sex, memo FROM Contact")
+ // 이전 테이블 제거
+ database.execSQL("DROP TABLE Contact")
+
+ // 새 테이블 이름 바꾸기
+ database.execSQL("ALTER TABLE new_Contact RENAME TO Contact")
+ }
+ }
+ val MIGRATION_2_3 = object : Migration(2, 3) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL(
+ "CREATE TABLE new_Contact (" +
+ "id INTEGER PRIMARY KEY NOT NULL, " +
+ "name TEXT NOT NULL, " +
+ "phone TEXT NOT NULL, " +
+ "email TEXT, " +
+ "birth TEXT, " +
+ "sex TEXT, " +
+ "memo TEXT)"
+ )
+ // 데이터 복사
+ database.execSQL(
+ "INSERT INTO new_Contact (id, name, phone, email, birth, sex, memo) " +
+ "SELECT id, name, CAST(phone AS TEXT), email, birth, sex, memo FROM Contact")
+ // 이전 테이블 제거
+ database.execSQL("DROP TABLE Contact")
+
+ // 새 테이블 이름 바꾸기
+ database.execSQL("ALTER TABLE new_Contact RENAME TO Contact")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/contacts/ContactDao.kt b/app/src/main/java/campus/tech/kakao/contacts/ContactDao.kt
new file mode 100644
index 00000000..944ecf69
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/contacts/ContactDao.kt
@@ -0,0 +1,26 @@
+package campus.tech.kakao.contacts
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy.Companion.REPLACE
+import androidx.room.Query
+
+@Dao
+interface ContactDao {
+ @Insert(onConflict = REPLACE)
+ fun insert(contact: Contact)
+
+ @Query("SELECT * FROM Contact")
+ fun getAll(): List
+
+ @Query("SELECT * FROM Contact WHERE id = :id")
+ fun getById(id: Int): Contact
+
+ @Query("DELETE FROM Contact WHERE id = :id")
+ fun deleteById(id: Int)
+
+ @Query("DELETE FROM Contact")
+ fun deleteAll()
+
+}
+
diff --git a/app/src/main/java/campus/tech/kakao/contacts/ContactDatabase.kt b/app/src/main/java/campus/tech/kakao/contacts/ContactDatabase.kt
new file mode 100644
index 00000000..83eded81
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/contacts/ContactDatabase.kt
@@ -0,0 +1,11 @@
+package campus.tech.kakao.contacts
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+@Database(entities = [Contact::class], version = 3)
+abstract class ContactDatabase: RoomDatabase() {
+ abstract fun contactDao(): ContactDao
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/contacts/ContactDetail.kt b/app/src/main/java/campus/tech/kakao/contacts/ContactDetail.kt
new file mode 100644
index 00000000..10d5f90c
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/contacts/ContactDetail.kt
@@ -0,0 +1,73 @@
+package campus.tech.kakao.contacts
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.room.Room
+
+class ContactDetail : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ //UI 선언
+ setContentView(R.layout.activity_contact_detail)
+ val name = findViewById(R.id.name)
+ val phone = findViewById(R.id.phone)
+ val email = findViewById(R.id.mail)
+ val emailLayout = findViewById(R.id.mailLayout)
+ val birth = findViewById(R.id.birth)
+ val birthLayout = findViewById(R.id.birthLayout)
+ val sex = findViewById(R.id.sex)
+ val sexLayout = findViewById(R.id.sexLayout)
+ val memo = findViewById(R.id.memo)
+ val memoLayout = findViewById(R.id.memoLayout)
+
+ //데이터베이스 선언
+ val database = Room.databaseBuilder(
+ applicationContext,
+ ContactDatabase::class.java, "database-name"
+ ).addMigrations(Contact.MIGRATION_1_2, Contact.MIGRATION_2_3).allowMainThreadQueries().build()
+ //인텐트를 통해 ID 받기
+ val intent = intent
+ val id = intent.extras?.getInt("contact-id")
+ Log.d("contacttest", "id : "+id)
+
+ //ID에 해당하는 데이터 불러오기
+ if (id != null) {
+ val contact = database.contactDao().getById(id)
+ if (contact != null) {
+ Log.d("contacttest", "detail : "+contact.id+", "+contact.name+", "+contact.phone+", "+contact.email+", "+contact.birth+", "+contact.sex+", "+contact.memo)
+ if (contact.name != null && contact.name.isNotEmpty()) {
+ name.text = contact.name
+ }
+ if (contact.phone != null && contact.phone.isNotEmpty()) {
+ phone.text = contact.phone
+ }
+ if (contact.email!=null && contact.email.isNotEmpty()) {
+ email.text = contact.email
+ emailLayout.visibility = View.VISIBLE
+ }
+ if (contact.birth != null && contact.birth.isNotEmpty()) {
+ birth.text = contact.birth
+ birthLayout.visibility = View.VISIBLE
+ }
+ if (contact.sex != null && contact.sex.isNotEmpty()) {
+ sex.text = contact.sex
+ sexLayout.visibility = View.VISIBLE
+ }
+ if (contact.memo != null && contact.memo.isNotEmpty()) {
+ memo.text = contact.memo
+ memoLayout.visibility = View.VISIBLE
+ }
+ }
+ else{
+ Log.d("contacttest", "contact is null")
+ }
+ }
+ else{
+ Log.d("contacttest", "id("+id+") is null")
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/contacts/MainActivity.kt b/app/src/main/java/campus/tech/kakao/contacts/MainActivity.kt
index 7aae79fe..8d96e702 100644
--- a/app/src/main/java/campus/tech/kakao/contacts/MainActivity.kt
+++ b/app/src/main/java/campus/tech/kakao/contacts/MainActivity.kt
@@ -1,11 +1,70 @@
package campus.tech.kakao.contacts
+import android.content.Intent
import android.os.Bundle
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.room.Room
+import campus.tech.kakao.contacts.Contact.Companion.MIGRATION_1_2
+import campus.tech.kakao.contacts.Contact.Companion.MIGRATION_2_3
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+
class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- }
-}
+
+ private lateinit var addButton: FloatingActionButton
+ private lateinit var guidePhrase: TextView
+
+ lateinit var database: ContactDatabase
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ guidePhrase = findViewById(R.id.guidePhrase)
+
+ // Initialize database
+ database = Room.databaseBuilder(
+ applicationContext,
+ ContactDatabase::class.java, "database-name"
+ ).addMigrations(MIGRATION_1_2, MIGRATION_2_3).allowMainThreadQueries().build()
+
+ database.contactDao().deleteAll()
+
+ //연락처 추가 버튼
+ addButton = findViewById(R.id.addButton)
+ addButton.setOnClickListener {
+ startActivity(
+ Intent(this, AddContactActivity::class.java)
+ )
+ }
+
+ }
+ //연락처 추가 후 연락처 목록 갱신
+ override fun onResume() {
+ super.onResume()
+ val contactList = database.contactDao().getAll()
+ if (contactList.isNotEmpty()) {
+ guidePhrase.visibility = View.GONE
+ }
+ else{
+ guidePhrase.visibility = View.VISIBLE
+ }
+ val recyclerView = findViewById(R.id.recyclerView)
+ recyclerView.adapter = RecyclerViewAdapter(
+ contactList, LayoutInflater.from(this), this)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ }
+ //뒤로 가기 버튼 클릭 시 연락처 초기화
+ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ database.contactDao().deleteAll()
+ }
+ return super.onKeyDown(keyCode, event)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/contacts/RecyclerViewAdapter.kt b/app/src/main/java/campus/tech/kakao/contacts/RecyclerViewAdapter.kt
new file mode 100644
index 00000000..b228285a
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/contacts/RecyclerViewAdapter.kt
@@ -0,0 +1,56 @@
+package campus.tech.kakao.contacts
+
+import android.content.Context
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import androidx.core.content.ContextCompat.startActivity
+import androidx.recyclerview.widget.RecyclerView
+
+class RecyclerViewAdapter(
+ val contact_list: List,
+ val inflater: LayoutInflater,
+ val context: Context
+) : RecyclerView.Adapter(){
+
+ inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){
+ val name_first: TextView
+ val name:TextView
+ init {
+ name_first = itemView.findViewById(R.id.nameFirst)
+ name = itemView.findViewById(R.id.name)
+ //클릭 리스너 생성
+ itemView.setOnClickListener {
+ val position = adapterPosition
+ //adapterPosition을 통해 포지션을 받음.
+ val contact = contact_list.get(position)
+// Toast.makeText(context, ""+contact.name+" "+contact.phone, Toast.LENGTH_SHORT).show()
+ val intent = Intent(context, ContactDetail::class.java)
+ //인텐트에 id 넘겨줌
+ intent.putExtra("contact-id", contact.id)
+ startActivity(context, intent, null)
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val view = inflater.inflate(R.layout.contact_item, parent, false)
+ return ViewHolder(view)
+ }
+
+ //데이터를 아이템뷰의 뷰컴포넌트와 바인딩함.
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val name_first_word = contact_list.get(position).name[0]
+ holder.name_first.text = name_first_word.toString()
+ holder.name.text = contact_list.get(position).name
+ }
+
+ override fun getItemCount(): Int {
+ return contact_list.size
+ }
+}
+
+
diff --git a/app/src/main/res/drawable/contact_item_background.xml b/app/src/main/res/drawable/contact_item_background.xml
new file mode 100644
index 00000000..ca270c44
--- /dev/null
+++ b/app/src/main/res/drawable/contact_item_background.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/face.png b/app/src/main/res/drawable/face.png
new file mode 100644
index 00000000..4831c1b6
Binary files /dev/null and b/app/src/main/res/drawable/face.png differ
diff --git a/app/src/main/res/drawable/name_first_background.xml b/app/src/main/res/drawable/name_first_background.xml
new file mode 100644
index 00000000..883f15c2
--- /dev/null
+++ b/app/src/main/res/drawable/name_first_background.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/text_background.xml b/app/src/main/res/drawable/text_background.xml
new file mode 100644
index 00000000..45d451ec
--- /dev/null
+++ b/app/src/main/res/drawable/text_background.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_addcontact.xml b/app/src/main/res/layout/activity_addcontact.xml
new file mode 100644
index 00000000..8d86a552
--- /dev/null
+++ b/app/src/main/res/layout/activity_addcontact.xml
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_contact_detail.xml b/app/src/main/res/layout/activity_contact_detail.xml
new file mode 100644
index 00000000..ff828e32
--- /dev/null
+++ b/app/src/main/res/layout/activity_contact_detail.xml
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 24d17df2..92d36233 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,19 +1,34 @@
-
+
+
+ android:text="오른쪽 + 버튼을 클릭하여\n연락처를 등록해보세요."
+ android:layout_gravity="center"
+ android:visibility="visible"/>
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/contact_item.xml b/app/src/main/res/layout/contact_item.xml
new file mode 100644
index 00000000..d3ca95fd
--- /dev/null
+++ b/app/src/main/res/layout/contact_item.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/popup_message.xml b/app/src/main/res/layout/popup_message.xml
new file mode 100644
index 00000000..d8a6330e
--- /dev/null
+++ b/app/src/main/res/layout/popup_message.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 00000000..f549c698
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml
new file mode 100644
index 00000000..22d7f004
--- /dev/null
+++ b/app/src/main/res/values-land/dimens.xml
@@ -0,0 +1,3 @@
+
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-v23/themes.xml b/app/src/main/res/values-v23/themes.xml
new file mode 100644
index 00000000..b1fed486
--- /dev/null
+++ b/app/src/main/res/values-v23/themes.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml
new file mode 100644
index 00000000..d73f4a35
--- /dev/null
+++ b/app/src/main/res/values-w1240dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 200dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml
new file mode 100644
index 00000000..22d7f004
--- /dev/null
+++ b/app/src/main/res/values-w600dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 768b058a..54652950 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -2,4 +2,6 @@
#FF000000
#FFFFFFFF
+ #DFF3F6
+ #FEC008
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..125df871
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+
+ 16dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a805abf4..daae0dd0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,45 @@
Contacts
+
+ First Fragment
+ Second Fragment
+ Next
+ Previous
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris
+ volutpat, dolor id interdum ullamcorper, risus dolor egestas lectus, sit amet mattis purus
+ dui nec risus. Maecenas non sodales nisi, vel dictum dolor. Class aptent taciti sociosqu ad
+ litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse blandit eleifend
+ diam, vel rutrum tellus vulputate quis. Aliquam eget libero aliquet, imperdiet nisl a,
+ ornare ex. Sed rhoncus est ut libero porta lobortis. Fusce in dictum tellus.\n\n
+ Suspendisse interdum ornare ante. Aliquam nec cursus lorem. Morbi id magna felis. Vivamus
+ egestas, est a condimentum egestas, turpis nisl iaculis ipsum, in dictum tellus dolor sed
+ neque. Morbi tellus erat, dapibus ut sem a, iaculis tincidunt dui. Interdum et malesuada
+ fames ac ante ipsum primis in faucibus. Curabitur et eros porttitor, ultricies urna vitae,
+ molestie nibh. Phasellus at commodo eros, non aliquet metus. Sed maximus nisl nec dolor
+ bibendum, vel congue leo egestas.\n\n
+ Sed interdum tortor nibh, in sagittis risus mollis quis. Curabitur mi odio, condimentum sit
+ amet auctor at, mollis non turpis. Nullam pretium libero vestibulum, finibus orci vel,
+ molestie quam. Fusce blandit tincidunt nulla, quis sollicitudin libero facilisis et. Integer
+ interdum nunc ligula, et fermentum metus hendrerit id. Vestibulum lectus felis, dictum at
+ lacinia sit amet, tristique id quam. Cras eu consequat dui. Suspendisse sodales nunc ligula,
+ in lobortis sem porta sed. Integer id ultrices magna, in luctus elit. Sed a pellentesque
+ est.\n\n
+ Aenean nunc velit, lacinia sed dolor sed, ultrices viverra nulla. Etiam a venenatis nibh.
+ Morbi laoreet, tortor sed facilisis varius, nibh orci rhoncus nulla, id elementum leo dui
+ non lorem. Nam mollis ipsum quis auctor varius. Quisque elementum eu libero sed commodo. In
+ eros nisl, imperdiet vel imperdiet et, scelerisque a mauris. Pellentesque varius ex nunc,
+ quis imperdiet eros placerat ac. Duis finibus orci et est auctor tincidunt. Sed non viverra
+ ipsum. Nunc quis augue egestas, cursus lorem at, molestie sem. Morbi a consectetur ipsum, a
+ placerat diam. Etiam vulputate dignissim convallis. Integer faucibus mauris sit amet finibus
+ convallis.\n\n
+ Phasellus in aliquet mi. Pellentesque habitant morbi tristique senectus et netus et
+ malesuada fames ac turpis egestas. In volutpat arcu ut felis sagittis, in finibus massa
+ gravida. Pellentesque id tellus orci. Integer dictum, lorem sed efficitur ullamcorper,
+ libero justo consectetur ipsum, in mollis nisl ex sed nisl. Donec maximus ullamcorper
+ sodales. Praesent bibendum rhoncus tellus nec feugiat. In a ornare nulla. Donec rhoncus
+ libero vel nunc consequat, quis tincidunt nisl eleifend. Cras bibendum enim a justo luctus
+ vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim.
+
\ No newline at end of file
diff --git "a/\353\215\224\353\263\264\352\270\260 \354\204\240\355\203\235 \354\213\234.png" "b/\353\215\224\353\263\264\352\270\260 \354\204\240\355\203\235 \354\213\234.png"
new file mode 100644
index 00000000..8f3bf677
Binary files /dev/null and "b/\353\215\224\353\263\264\352\270\260 \354\204\240\355\203\235 \354\213\234.png" differ
diff --git "a/\353\246\254\354\202\254\354\235\264\355\201\264\353\237\254\353\267\260.png" "b/\353\246\254\354\202\254\354\235\264\355\201\264\353\237\254\353\267\260.png"
new file mode 100644
index 00000000..b263498a
Binary files /dev/null and "b/\353\246\254\354\202\254\354\235\264\355\201\264\353\237\254\353\267\260.png" differ
diff --git "a/\354\203\235\354\235\274 \354\236\205\353\240\245 \354\213\234.png" "b/\354\203\235\354\235\274 \354\236\205\353\240\245 \354\213\234.png"
new file mode 100644
index 00000000..c3695cc5
Binary files /dev/null and "b/\354\203\235\354\235\274 \354\236\205\353\240\245 \354\213\234.png" differ
diff --git "a/\354\240\200\354\236\245 \355\233\204 \353\252\250\354\212\265.png" "b/\354\240\200\354\236\245 \355\233\204 \353\252\250\354\212\265.png"
new file mode 100644
index 00000000..5e6f4670
Binary files /dev/null and "b/\354\240\200\354\236\245 \355\233\204 \353\252\250\354\212\265.png" differ
diff --git "a/\354\240\200\354\236\245\353\220\234 \354\240\225\353\263\264.png" "b/\354\240\200\354\236\245\353\220\234 \354\240\225\353\263\264.png"
new file mode 100644
index 00000000..1c92de0c
Binary files /dev/null and "b/\354\240\200\354\236\245\353\220\234 \354\240\225\353\263\264.png" differ
diff --git "a/\354\264\210\352\270\260 \355\231\224\353\251\264.png" "b/\354\264\210\352\270\260 \355\231\224\353\251\264.png"
new file mode 100644
index 00000000..e9d97057
Binary files /dev/null and "b/\354\264\210\352\270\260 \355\231\224\353\251\264.png" differ
diff --git "a/\354\266\224\352\260\200 \355\231\224\353\251\264.png" "b/\354\266\224\352\260\200 \355\231\224\353\251\264.png"
new file mode 100644
index 00000000..4af452e2
Binary files /dev/null and "b/\354\266\224\352\260\200 \355\231\224\353\251\264.png" differ