diff --git a/README.md b/README.md index cc0acc5a..9947da23 100644 --- a/README.md +++ b/README.md @@ -1 +1,56 @@ # android-contacts + +- 카카오 테크 캠퍼스 과제(연락처 앱) 수행을 위한 저장소입니다. + +## *Contents* +1. 홈 화면      2. 연락처 추가 화면     3. 취소 / 뒤로가기 팝업 + + + +4. 연락처 목록 화면      5. 연락처 목록 화면(회전) + + + +6. 상세화면1     7. 상세 화면2 + + + +## feature + +### 1단계 - 연락처 추가 + +1. 이름과 전화번호 입력 기능 + - 이름과 전화번호는 필수 값으로 입력하지 않은 경우 토스트 메시지 보여준다. + +2. 전화번호 입력 기능 + - 숫자만 입력 가능 + +3. 더보기 기능 + - 더보기를 눌러 입력 폼을 확장할 수 있다. + - 추가되는 입력 폼 : 생일, 성별, 메모 + +4. 성별 입력 기능 + - 성별을 둘 중 하나를 선택할 수 있다. + +5. 저장 기능 + - 저장 버튼을 누르면 '저장이 완료 되었습니다' 라는 토스트 메시지를 보여준다. + +6. 취소 기능 + - 취소 버튼을 누르면 '취소 되었습니다' 라는 토스트 메시지를 보여준다. + +7. 생일 입력 기능 + - 생일을 달력에서 선택해서 입력할 수 있다. + + +### 2단계 - 연락처 목록 + +1. 연락처 등록 화면 + - 연락처 추가 버튼을 누르면 연락처 추가 화면으로 넘어감 + +2. 연락처를 저장하면 목록에 추가 + - 앱을 다시 실행하면 목록은 비어있음 + - 저장된 연락처가 많을 경우 목록 스크롤 가능 + +3. 연락처 목록의 연락처를 선택하면 상세 화면 출력 + +4. 연락처 작성 중 뒤로가기 / 취소 버튼을 누르면 확인 팝업 출력 \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c5add08f..77d242ff 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,8 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("kotlin-parcelize") + id("org.jlleitschuh.gradle.ktlint") } android { @@ -41,6 +43,7 @@ dependencies { implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.11.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") + implementation("androidx.activity:activity:1.8.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 89dc9d8b..96dc0f90 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,7 +13,10 @@ android:theme="@style/Theme.Contacts" tools:targetApi="31"> + @@ -21,6 +24,9 @@ + - + \ No newline at end of file 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..bdf33ab6 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/contacts/Contact.kt @@ -0,0 +1,14 @@ +package campus.tech.kakao.contacts + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Contact( + val name: String, + val phoneNum: String, + val email: String, + val birthday: String, + val gender: Gender? = null, + val memo: String, +) : Parcelable diff --git a/app/src/main/java/campus/tech/kakao/contacts/DetailActivity.kt b/app/src/main/java/campus/tech/kakao/contacts/DetailActivity.kt new file mode 100644 index 00000000..e0773296 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/contacts/DetailActivity.kt @@ -0,0 +1,107 @@ +package campus.tech.kakao.contacts + +import android.os.Build +import android.os.Bundle +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible + +class DetailActivity : AppCompatActivity() { + private lateinit var detailNameTextView: TextView + private lateinit var detailPhoneNumTextView: TextView + private lateinit var detailEmailTextView: TextView + private lateinit var detailBirthdayTextView: TextView + private lateinit var detailGenderTextView: TextView + private lateinit var detailMemoTextView: TextView + private lateinit var detailEmailLayout: ConstraintLayout + private lateinit var detailBirthdayLayout: ConstraintLayout + private lateinit var detailGenderLayout: ConstraintLayout + private lateinit var detailMemoLayout: ConstraintLayout + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_detail) + + initViews() + setContactDetails() + } + + /** + * 사용할 view들을 초기화하는 함수 + * + * - `detailNameTextView` : 이름을 나타내는 TextView + * - `detailPhoneNumTextView` : 전화번호를 나타내는 TextView + * - `detailEmailTextView` : 메일을 나타내는 TextView + * - `detailBirthdayTextView` : 생일을 나타내는 TextView + * - `detailGenderTextView` : 성별을 나타내는 TextView + * - `detailMemoTextView` : 메모를 나타내는 TextView + * - `detailEmailLayout` : 메일 ConstraintLayout + * - `detailBirthdayLayout` : 생일 ConstraintLayout + * - `detailGenderLayout` : 성별 ConstraintLayout + * - `detailMemoLayout` : 메모 ConstraintLayout + */ + private fun initViews() { + detailNameTextView = findViewById(R.id.detail_name_text_view) + detailPhoneNumTextView = findViewById(R.id.detail_phone_num_text_view) + detailEmailTextView = findViewById(R.id.detail_email_text_view) + detailBirthdayTextView = findViewById(R.id.detail_birthday_text_view) + detailGenderTextView = findViewById(R.id.detail_gender_text_view) + detailMemoTextView = findViewById(R.id.detail_memo_text_view) + + detailEmailLayout = findViewById(R.id.detail_email_layout) + detailBirthdayLayout = findViewById(R.id.detail_birthday_layout) + detailGenderLayout = findViewById(R.id.detail_gender_layout) + detailMemoLayout = findViewById(R.id.detail_memo_layout) + } + + /** + * 전달된 contact 정보를 view와 layout에 설정하는 함수. + */ + private fun setContactDetails() { + val contact: Contact? = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra("contact", Contact::class.java) + } else { + intent.getParcelableExtra("contact") + } + + contact?.let { + setDetailTextViews(it) + setDetailLayoutVisibility(it) + } + } + + /** + * contact 정보로 TextView의 text를 설정하는 함수. + * + * @param contact RegisterActivity로 부터 받은 Contact 객체. + */ + private fun setDetailTextViews(contact: Contact) { + detailNameTextView.text = contact.name + detailPhoneNumTextView.text = contact.phoneNum + detailEmailTextView.text = contact.email ?: "" + detailBirthdayTextView.text = contact.birthday ?: "" + detailGenderTextView.text = + when (contact.gender) { + Gender.FEMALE -> "여성" + Gender.MALE -> "남성" + else -> "" + } + detailMemoTextView.text = contact.memo ?: "" + } + + /** + * contact 정보로 layout의 visibility를 설정하는 함수. + * + * 빈 정보는 보이지 않도록 설정. + * + * @param contact RegisterActivity로 부터 받은 Contact 객체. + */ + private fun setDetailLayoutVisibility(contact: Contact) { + detailEmailLayout.isVisible = contact.email.isNotEmpty() + detailBirthdayLayout.isVisible = contact.birthday.isNotEmpty() + detailGenderLayout.isVisible = contact.gender != null + detailMemoLayout.isVisible = contact.memo.isNotEmpty() + } +} diff --git a/app/src/main/java/campus/tech/kakao/contacts/Gender.kt b/app/src/main/java/campus/tech/kakao/contacts/Gender.kt new file mode 100644 index 00000000..878598e6 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/contacts/Gender.kt @@ -0,0 +1,6 @@ +package campus.tech.kakao.contacts + +enum class Gender { + MALE, + FEMALE, +} 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..a0e2a26a 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,220 @@ package campus.tech.kakao.contacts +import android.app.DatePickerDialog +import android.icu.util.Calendar import android.os.Bundle +import android.view.View +import android.widget.Button +import android.widget.EditText +import android.widget.RadioGroup +import android.widget.TextView +import android.widget.Toast +import androidx.activity.OnBackPressedCallback +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.LinearLayoutCompat +import androidx.constraintlayout.widget.ConstraintLayout class MainActivity : AppCompatActivity() { + private lateinit var nameEditText: EditText + private lateinit var phoneNumEditText: EditText + private lateinit var emailEditText: EditText + private lateinit var birthdayTextView: TextView + private lateinit var genderLayout: ConstraintLayout + private lateinit var memoEditText: EditText + private lateinit var cancelBtn: Button + private lateinit var saveBtn: Button + private lateinit var seeMoreLayout: LinearLayoutCompat + private lateinit var genderRadioGroup: RadioGroup + private var gender: Gender? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + initViews() + setOnClickListeners() + registerOnBackPressedCallback() + } + + /** + * 사용할 view들을 초기화하는 함수. + * - `nameEditText` : 이름 입력폼을 나타내는 EditText + * - `phoneNumEditText` : 전화번호 입력폼을 나타내는 EditText + * - `emailEditText` : 이메일 입력폼을 나타내는 EditText + * - `birthdayTextView` : 생일 입력폼을 나타내는 TextView + * - `genderLayout` : 성별 입력폼을 나타내는 ConstraintLayout + * - `memoEditText` : 메모 력폼을 나타내는 EditText + * - `cancelBtn` : 취소 버튼을 나타내는 Button + * - `saveBtn` : 저장 버튼을 나타내는 Button + * - `seeMoreLayout` : 더보기를 나타내는 LinearLayoutCompat + * - `genderRadioGroup` : 성별 선택을 위한 RadioGroup + */ + private fun initViews() { + nameEditText = findViewById(R.id.name_edit_text) + phoneNumEditText = findViewById(R.id.phone_num_edit_text) + emailEditText = findViewById(R.id.email_edit_text) + birthdayTextView = findViewById(R.id.birthday_text_view) + genderLayout = findViewById(R.id.gender_layout) + memoEditText = findViewById(R.id.memo_edit_text) + cancelBtn = findViewById(R.id.cancel_btn) + saveBtn = findViewById(R.id.save_btn) + seeMoreLayout = findViewById(R.id.see_more_layout) + genderRadioGroup = findViewById(R.id.gender_radio_group) + } + + /** + * 사용할 클릭 리스너들을 설정하는 함수 + */ + private fun setOnClickListeners() { + setOnClickListenerOfSaveBtn() + setOnClickListenerOfCancelBtn() + setOnClickListenerOfSeeMoreLayout() + setOnClickListenerOfGenderRadioGroup() + setOnClickListenerOfBirthdayEditText() + } + + /** + * 취소 버튼에 대한 클릭 리스너를 설정하는 함수. + * + * 취소 버튼을 누르면 확인 팝업 보여줌. + */ + private fun setOnClickListenerOfCancelBtn() { + cancelBtn.setOnClickListener { + showAlertDialog() + } + } + + /** + * 저장 버튼에 대한 클릭 리스너를 설정하는 함수 + * + * 이름 또는 전화번호 입력 폼이 비어있을 경우 Toast 메시지 출력. + * 아닌 경우 입력한 정보를 contact 객체로 담아 결과를 보내고 finish. + * + * - `contact` : 입력한 연락처 정보를 담고 있는 Contact 객체 + * - `name` : 작성한 이름 String + * - `phoneNum` : 작성한 전화 번호 String + */ + private fun setOnClickListenerOfSaveBtn() { + saveBtn.setOnClickListener { + val name = nameEditText.text.toString().trim() + val phoneNum = phoneNumEditText.text.toString().trim() + + when { + name.isEmpty() -> { + Toast.makeText(this, "이름은 필수 값 입니다.", Toast.LENGTH_LONG).show() + } + phoneNum.isEmpty() -> { + Toast.makeText(this, "전화 번호는 필수 값 입니다.", Toast.LENGTH_LONG).show() + } + !phoneNum.matches(Regex("^\\d{10,11}\$")) -> { + Toast.makeText(this, "전화 번호는 10자리 또는 11자리의 숫자만 입력 가능합니다.", Toast.LENGTH_LONG).show() + } + else -> { + val contact = createContact() + intent.putExtra("CONTACT_RESULT", contact) + setResult(RESULT_OK, intent) + finish() + } + } + } + } + + /** + * Contact 객체를 만드는 함수 + * + * @return 입력 폼의 정보를 바탕으로 한 Contact 객체 + */ + private fun createContact(): Contact { + return Contact( + nameEditText.text.toString(), + phoneNumEditText.text.toString(), + emailEditText.text.toString(), + birthdayTextView.text.toString(), + gender, + memoEditText.text.toString(), + ) + } + + /** + * 더보기 layout에 대한 클릭 리스너를 설정하는 함수 + * + * layout을 누르면 더보기 layout은 감추고 추가 입력 폼을 보이게 함. + */ + private fun setOnClickListenerOfSeeMoreLayout() { + seeMoreLayout.setOnClickListener { + seeMoreLayout.visibility = View.GONE + birthdayTextView.visibility = View.VISIBLE + genderLayout.visibility = View.VISIBLE + memoEditText.visibility = View.VISIBLE + } + } + + /** + * genderRadioGroup에 대한 클릭 리스너를 설정하는 함수 + * + * 선택한 성별이 여성이면 1을, 남성이면 2를 gender에 저장. + */ + private fun setOnClickListenerOfGenderRadioGroup() { + genderRadioGroup.setOnCheckedChangeListener { group, checkId -> + gender = + when (checkId) { + R.id.woman_radio_btn -> Gender.FEMALE + R.id.man_radio_btn -> Gender.MALE + else -> null + } + } + } + + /** + * 생일 입력폼에 대한 클릭 리스너를 설정하는 함수 + * + * 클릭 시 캘린더 dialog가 나오고 선택한 날짜가 입력폼에 입력됨. + */ + private fun setOnClickListenerOfBirthdayEditText() { + birthdayTextView.setOnClickListener { + val calendar = Calendar.getInstance() + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val dateListener = + DatePickerDialog.OnDateSetListener { view, year, month, dayOfMonth -> + val formattedDate = "$year.$month.$dayOfMonth" + birthdayTextView.text = formattedDate + } + DatePickerDialog(this, dateListener, year, month, day).show() + } + } + + /** + * 뒤로 가기 버튼을 누르면 확인 팝업을 보여주도록 설정하는 함수 + * + */ + private fun registerOnBackPressedCallback() { + onBackPressedDispatcher.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + showAlertDialog() + } + }, + ) + } + + /** + * 작성 내용 취소 / 뒤로가기 시 확인 팝업을 보여주는 함수. + * + * 나가기를 누르면 액티비티가 종료되고 작성하기를 누르면 다시 작성 가능함. + */ + private fun showAlertDialog() { + AlertDialog.Builder(this).apply { + setMessage("작성 중인 내용이 있습니다. 정말 나가시겠습니까?") + setPositiveButton("나가기") { _, _ -> + finish() + } + setNegativeButton("작성하기", null) + create() + show() + } } } diff --git a/app/src/main/java/campus/tech/kakao/contacts/RegisterActivity.kt b/app/src/main/java/campus/tech/kakao/contacts/RegisterActivity.kt new file mode 100644 index 00000000..a00360a6 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/contacts/RegisterActivity.kt @@ -0,0 +1,218 @@ +package campus.tech.kakao.contacts + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.TextView +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView + +class RegisterActivity : AppCompatActivity() { + lateinit var registerBtnLayout: FrameLayout + lateinit var contactRecyclerView: RecyclerView + lateinit var howToRegisterTextView: TextView + private lateinit var startActivityLauncher: ActivityResultLauncher + private var contactList = ArrayList() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_register) + + initViews() + setOnClickListeners() + setContactRecyclerView() + setStartActivityLauncher() + restoreInstanceState(savedInstanceState) + } + + /** + * 사용할 view들을 초기화하는 함수 + * + * - `registerBtnLayout` : 연락처 등록 버튼을 나타내는 FrameLayout + * - `contactRecyclerView` : 연락처 목록을 나타내는 RecyclerView + * - `howToRegisterTextView` : 연락처 등록 방법 메시지를 나타내는 TextView + */ + private fun initViews() { + registerBtnLayout = findViewById(R.id.register_btn_layout) + contactRecyclerView = findViewById(R.id.contact_recycler_view) + howToRegisterTextView = findViewById(R.id.how_to_register_text_view) + } + + /** + * 사용할 클릭 리스너들을 설정하는 함수 + */ + private fun setOnClickListeners() { + setOnClickListenerOfRegisterBtnLayout() + } + + /** + * 연락처 추가 버튼에 대한 클릭 리스너를 설정하는 함수 + * + * 클릭 시 MainActivity로 넘어가고 Contact 객체를 결과로 받는 것을 기다림. + */ + private fun setOnClickListenerOfRegisterBtnLayout() { + registerBtnLayout.setOnClickListener { + val intent = Intent(this@RegisterActivity, MainActivity::class.java) + startActivityLauncher.launch(intent) + } + } + + /** + * 연락처 리사이클러뷰를 설정하는 함수 + * + * - `contactClickListener` : RecyclerView의 아이템이 클릭될 때 실행될 코드를 포함하는 OnContactClickListener 구현 객체 + * + */ + private fun setContactRecyclerView() { + val contactClickListener = + object : OnContactClickListener { + override fun onContactClicked(position: Int) { + val contact = contactList[position] + val intent = + Intent(this@RegisterActivity, DetailActivity::class.java).apply { + putExtra("contact", contact) + } + startActivity(intent) + } + } + contactRecyclerView.adapter = + ContactRecyclerViewAdapter(contactList, contactClickListener) + contactRecyclerView.layoutManager = LinearLayoutManager(this) + } + + /** + * startActivityLauncher를 설정하는 함수 + * + * result로 contact 객체를 받아와 list에 추가. + * 하나 이상의 contact 객체가 들어오면 등록 안내 textview의 visibility를 gone으로 설정. + */ + @SuppressLint("NotifyDataSetChanged") + private fun setStartActivityLauncher() { + startActivityLauncher = + registerForActivityResult(StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val contact: Contact? = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + result.data?.getParcelableExtra("CONTACT_RESULT", Contact::class.java) + } else { + result.data?.getParcelableExtra("CONTACT_RESULT") + } + contact?.let { + contactList.add(it) + if (howToRegisterTextView.visibility != View.GONE) { + howToRegisterTextView.visibility = View.GONE + } + contactRecyclerView.adapter?.notifyDataSetChanged() + } + } + } + } + + interface OnContactClickListener { + fun onContactClicked(position: Int) + } + + class ContactRecyclerViewAdapter( + private val contactList: ArrayList, + private val contactClickListener: OnContactClickListener, + ) : RecyclerView.Adapter() { + class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + private val lastNameTextView: TextView = itemView.findViewById(R.id.last_name_text_view) + private val nameTextView: TextView = itemView.findViewById(R.id.name_text_view) + + fun bind( + contact: Contact, + clickListener: OnContactClickListener, + ) { + setLastNameText(contact.name[0].toString()) + setNameText(contact.name) + itemView.setOnClickListener { + clickListener.onContactClicked(adapterPosition) + } + } + + private fun setLastNameText(lastName: String) { + lastNameTextView.text = lastName + } + + private fun setNameText(name: String) { + nameTextView.text = name + } + } + + @Override + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int, + ): ViewHolder { + val itemView = + LayoutInflater.from(parent.context) + .inflate(R.layout.contact_item, parent, false) + return ViewHolder(itemView) + } + + @Override + override fun onBindViewHolder( + holder: ViewHolder, + position: Int, + ) { + val contact = contactList[position] + holder.bind(contact, contactClickListener) + } + + @Override + override fun getItemCount(): Int { + return contactList.size + } + } + + /** + * 화면 방향 전환 등으로 인해 Activity의 정보가 사라지지 않도록 저장하는 함수 + * + * @param outState Activity의 현재 상태를 저장하는 Bundle 객체. + */ + @Override + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putParcelableArrayList("contact_list", ArrayList(contactList)) + } + + /** + * 화면 방향 전환 등으로 인해 Activity의 정보가 사라지지 않도록 복원하는 함수 + * + * @param savedInstanceState onSaveInstanceState에서 저장된 데이터를 포함하는 Bundle 객체. + */ + @Override + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + contactList = savedInstanceState.getParcelableArrayList("contact_list")!! + } + + companion object { + const val KEY_CONTACT_LIST = "contact_list" + } + + /** + * 화면 방향 전환 등으로 인해 Activity의 정보가 사라지지 않도록 복원하는 함수 + * + * @param savedInstanceState onSaveInstanceState에서 저장된 데이터를 포함하는 Bundle 객체. + */ + @Override + private fun restoreInstanceState(savedInstanceState: Bundle?) { + if (savedInstanceState != null) { + contactList = savedInstanceState.getParcelableArrayList(KEY_CONTACT_LIST) ?: ArrayList() + setContactRecyclerView() + if (contactList.isNotEmpty()) { + howToRegisterTextView.visibility = View.GONE + } + } + } +} diff --git a/app/src/main/res/drawable/add.xml b/app/src/main/res/drawable/add.xml new file mode 100644 index 00000000..9f83b8fb --- /dev/null +++ b/app/src/main/res/drawable/add.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/arrow_down.xml b/app/src/main/res/drawable/arrow_down.xml new file mode 100644 index 00000000..1a69b23f --- /dev/null +++ b/app/src/main/res/drawable/arrow_down.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/base_profile_image.xml b/app/src/main/res/drawable/base_profile_image.xml new file mode 100644 index 00000000..f4cc4181 --- /dev/null +++ b/app/src/main/res/drawable/base_profile_image.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/circle_orange.xml b/app/src/main/res/drawable/circle_orange.xml new file mode 100644 index 00000000..8b4e72cc --- /dev/null +++ b/app/src/main/res/drawable/circle_orange.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_box_add.xml b/app/src/main/res/drawable/round_box_add.xml new file mode 100644 index 00000000..912b211d --- /dev/null +++ b/app/src/main/res/drawable/round_box_add.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/round_box_contract_item.xml b/app/src/main/res/drawable/round_box_contract_item.xml new file mode 100644 index 00000000..e01cd52c --- /dev/null +++ b/app/src/main/res/drawable/round_box_contract_item.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml new file mode 100644 index 00000000..bee10ef4 --- /dev/null +++ b/app/src/main/res/layout/activity_detail.xml @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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..0fc9eaef 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -7,13 +7,199 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_register.xml b/app/src/main/res/layout/activity_register.xml new file mode 100644 index 00000000..ece77b63 --- /dev/null +++ b/app/src/main/res/layout/activity_register.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + \ 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..3bbecdde --- /dev/null +++ b/app/src/main/res/layout/contact_item.xml @@ -0,0 +1,43 @@ + + + + + + + + + \ 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..bd15f047 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,9 @@ #FF000000 #FFFFFFFF + #E6F3F6 + #EEC346 + #E9A23C + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a805abf4..3dfdb1ed 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,16 @@ Contacts + 이름 + 전화번호 + 취소 + 저장 + 생일 + 메일 + 성별 + 메모 + 더보기 + 여성 + 남성 + 오른쪽 + 버튼을 클릭하여\n연락처를 등록해보세요. + \ No newline at end of file diff --git a/img/cancelEvent.png b/img/cancelEvent.png new file mode 100644 index 00000000..47bfa594 Binary files /dev/null and b/img/cancelEvent.png differ diff --git a/img/contactList.png b/img/contactList.png new file mode 100644 index 00000000..7549dd1c Binary files /dev/null and b/img/contactList.png differ diff --git a/img/detailActivity.png b/img/detailActivity.png new file mode 100644 index 00000000..33f525d0 Binary files /dev/null and b/img/detailActivity.png differ diff --git a/img/detailActivity2.png b/img/detailActivity2.png new file mode 100644 index 00000000..6e77106c Binary files /dev/null and b/img/detailActivity2.png differ diff --git a/img/listRotation.png b/img/listRotation.png new file mode 100644 index 00000000..85796859 Binary files /dev/null and b/img/listRotation.png differ diff --git a/img/mainActivity.png b/img/mainActivity.png new file mode 100644 index 00000000..2f6bb794 Binary files /dev/null and b/img/mainActivity.png differ diff --git a/img/registerActivity.png b/img/registerActivity.png new file mode 100644 index 00000000..f3289906 Binary files /dev/null and b/img/registerActivity.png differ