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

[feat] 핑글 개최 프로세스 - 장소 선택 뷰 구현 #37

Merged
merged 37 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3417f13
[fix] #15 전체 배경색 수정
HAJIEUN02 Jan 2, 2024
5c8f7dd
[feat] #15 개최 프로세스 초기뷰 구현
HAJIEUN02 Jan 2, 2024
053a598
[feat] #15 개최 프로세스 검색 결과 리사이클러뷰 아이템 뷰 구현
HAJIEUN02 Jan 2, 2024
68a8e56
[chore] #15 전체 배경색 수정
HAJIEUN02 Jan 2, 2024
08c53af
[feat] #15 개최 프로세스 초기뷰 구현
HAJIEUN02 Jan 2, 2024
dfb7a0f
[feat] #15 개최 프로세스 검색 결과 리사이클러뷰 아이템 뷰 구현
HAJIEUN02 Jan 2, 2024
815c1e2
Merge remote-tracking branch 'origin/feat-plan-location' into feat-pl…
HAJIEUN02 Jan 2, 2024
36332af
[chore] #15 개최 프로세스 초기뷰 데이터바인딩 레이아웃 추가
HAJIEUN02 Jan 2, 2024
d975e51
[chore] #15 개최 프로세스 초기뷰 0dp로 수정
HAJIEUN02 Jan 2, 2024
c598133
[mod] #15 개최 프로세스 초기뷰 제약 수정 및 EditText 커스텀
HAJIEUN02 Jan 2, 2024
ba4dc80
[feat] #15 장소 검색 결과 리사이클러뷰 구현
HAJIEUN02 Jan 2, 2024
bdcee6c
[feat] #15 테스트 위한 액티비티 구현
HAJIEUN02 Jan 2, 2024
1a8b49a
[chore] #15 EditText 입력 시 cursor 색상 적용
HAJIEUN02 Jan 2, 2024
312d332
[chore] #15 리사이클러뷰 마지막 item 안 보이는 문제 해결
HAJIEUN02 Jan 3, 2024
288e043
Merge branch 'develop' into feat-plan-location
HAJIEUN02 Jan 3, 2024
aac44a1
[fix] #15 BindingAdapter 머지 중 오류 해결
HAJIEUN02 Jan 3, 2024
8f9356b
[feat] #15 RecyclerView Item에 Databinding 적용
HAJIEUN02 Jan 4, 2024
c484743
[chore] #15 develop merge 중 로컬에서 발생한 오류 해결
HAJIEUN02 Jan 4, 2024
e7c3b1b
[fix] #15 ListAdapter로 업그레이드
HAJIEUN02 Jan 5, 2024
417be24
[add] #15 PlanLocationviewModel에 가짜데이터 추가, PlanLocationEntity 정의
HAJIEUN02 Jan 5, 2024
1ef9e9c
Merge branch 'develop' into feat-plan-location
HAJIEUN02 Jan 6, 2024
0de4aa0
Merge branch 'develop' into feat-plan-location
HAJIEUN02 Jan 6, 2024
c5fda8a
[chore] #37 planLocation 뷰 구현 파일 main > plan으로 폴더 이동
HAJIEUN02 Jan 6, 2024
7665ea7
[chore] #37 planLocationModel->planLocationEntity로 변경
HAJIEUN02 Jan 6, 2024
8516f45
[mod] #37 ListAdapter 단일선택 로직 수정
HAJIEUN02 Jan 6, 2024
baa55ae
[mod] #37 ListAdapter 단일선택 로직 구현 완료
HAJIEUN02 Jan 6, 2024
67eb4ee
[add] #37 fragment_plan_location.xml id값 추가
HAJIEUN02 Jan 6, 2024
ec2721f
[mod] #37 ViewModel과 StateFlow를 활용한 로직으로 수정
HAJIEUN02 Jan 6, 2024
cae1696
[feat] #37 addListeners 구현 - 검색 결과에 따라 empty뷰/검색결과 뷰 visible 처리
HAJIEUN02 Jan 6, 2024
5e3b28c
[feat] #37 리사이클러뷰 아이템 구분선 구현
HAJIEUN02 Jan 6, 2024
a8005a7
Merge branch 'develop' into feat-plan-location
HAJIEUN02 Jan 7, 2024
9163fd6
[chore] #15 themes, PingleChip 되돌리기
HAJIEUN02 Jan 7, 2024
a845dbe
[mod] #15 엔터키 누를 시 검색 결과 출력
HAJIEUN02 Jan 7, 2024
3b80cab
[chore] #15 1차 코드리뷰 반영
HAJIEUN02 Jan 7, 2024
e9d9591
[chore] #15 planLocation 패키지 생성 및 이동
HAJIEUN02 Jan 7, 2024
cdadf8f
Merge branch 'develop' into feat-plan-location
HAJIEUN02 Jan 7, 2024
15e0cae
[chore] #15 ktlint 적용
HAJIEUN02 Jan 7, 2024
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
9 changes: 8 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Copy link
Collaborator

Choose a reason for hiding this comment

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

domain 레이어에 적어주면 됩니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.pingle.presentation.model

data class PlanLocationModel(
val location: String,
val address: String,
val x: Double,
val y: Double,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.sopt.pingle.presentation.ui.plan

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.sopt.pingle.R
import org.sopt.pingle.databinding.ActivityPlanLocationBinding

class PlanLocationActivity : AppCompatActivity() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

바인딩 액티비티 사용해주세요. 그리고 나중에 다은이 피알 머지되면 다은이가 만든 액티비티 사용해주세용

private lateinit var binding: ActivityPlanLocationBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPlanLocationBinding.inflate(layoutInflater)
setContentView(binding.root)

supportFragmentManager.beginTransaction()
.add(R.id.fragment_test, PlanLocationFragment())
.commit()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.sopt.pingle.presentation.ui.plan

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.sopt.pingle.databinding.ItemPlanLocationBinding
import org.sopt.pingle.presentation.model.PlanLocationModel

class PlanLocationAdapter :
ListAdapter<PlanLocationModel, PlanLocationAdapter.PlanLocationViewHolder>(
PlanLocationDiffCallback(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

확장함수로 DiffCallback 만들어 두었으니 그거 사용하시면 됩니다. 따로 만들 필요 없어요.

) {
private var planLocationList: List<PlanLocationModel> = emptyList()
Copy link
Collaborator

Choose a reason for hiding this comment

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

listAdapter로 만들면 따로 만들어줄 필요 없어요

private var selectedPosition: Int = -1
private lateinit var itemClickListener: ItemClickListener

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlanLocationViewHolder =
PlanLocationViewHolder(
ItemPlanLocationBinding.inflate(LayoutInflater.from(parent.context), parent, false),
)

override fun onBindViewHolder(holder: PlanLocationViewHolder, position: Int) {
holder.onBind(getItem(position), position)
}

inner class PlanLocationViewHolder(
private val binding: ItemPlanLocationBinding,
) :
RecyclerView.ViewHolder(binding.root) {

fun onBind(item: PlanLocationModel, position: Int) {
binding.planLocationItem = item
val planLocationItem = binding.planLocationItem
planLocationItem?.isSelected = position == selectedPosition

binding.root.setOnClickListener {
selectedPosition = position
itemClickListener.onClick(it, item)
}
}
}

interface ItemClickListener {
fun onClick(view: View, item: PlanLocationModel)
}

fun setItemClickListener(itemClickListener: ItemClickListener) {
this.itemClickListener = itemClickListener
}
}

/*fun moveItem(fromPosition: Int, toPosition: Int) {
val newList = currentList.toMutableList()
Collections.swap(newList, fromPosition, toPosition)
submitList(newList)
}

fun removeItem(position: Int) {
val newList = currentList.toMutableList()
newList.removeAt(position)
submitList(newList)
}*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sopt.pingle.presentation.ui.plan

import androidx.recyclerview.widget.DiffUtil
import org.sopt.pingle.presentation.model.PlanLocationModel

class PlanLocationDiffCallback : DiffUtil.ItemCallback<PlanLocationModel>() {

// Referential equality를 갖는지 판정
override fun areItemsTheSame(oldItem: PlanLocationModel, newItem: PlanLocationModel): Boolean {
return oldItem === newItem
}

// Structural equality를 갖는지 판정
override fun areContentsTheSame(
oldItem: PlanLocationModel,
newItem: PlanLocationModel,
): Boolean {
return oldItem == newItem
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.sopt.pingle.presentation.ui.plan

import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.DividerItemDecoration
import org.sopt.pingle.R
import org.sopt.pingle.databinding.FragmentPlanLocationBinding
import org.sopt.pingle.presentation.model.PlanLocationModel
import org.sopt.pingle.util.base.BindingFragment

class PlanLocationFragment :
BindingFragment<FragmentPlanLocationBinding>(R.layout.fragment_plan_location) {
private val planLocationViewModel by viewModels<PlanLocationViewModel>()
private val planLocationAdapter: PlanLocationAdapter by lazy {
PlanLocationAdapter()
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initLayout()
}

private fun initLayout() {
binding.rvPlanLocationList.apply {
addItemDecoration(
DividerItemDecoration(
requireContext(),
DividerItemDecoration.HORIZONTAL,
),
)
this.layoutManager = layoutManager
adapter = planLocationAdapter
}

planLocationAdapter.submitList(planLocationViewModel.mockPlanLocationList)
planLocationAdapter.setItemClickListener(object : PlanLocationAdapter.ItemClickListener {
override fun onClick(view: View, item: PlanLocationModel) {
// TODO click
}
})
}

override fun onDestroyView() {
super.onDestroyView()
binding.rvPlanLocationList.adapter = null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.sopt.pingle.presentation.ui.plan

/*import android.view.View
import android.widget.AdapterView
import androidx.recyclerview.widget.RecyclerView
import org.sopt.pingle.R
import org.sopt.pingle.databinding.ItemPlanLocationBinding
import org.sopt.pingle.presentation.model.PlanLocationModel

interface ItemClickListener {
fun onClick(view: View, item: PlanLocationModel)
}
class PlanLocationViewHolder(
private val binding: ItemPlanLocationBinding,
private var selectedPosition: Int,
private var itemClickListener: ItemClickListener
) :
RecyclerView.ViewHolder(binding.root) {

fun onBind(item: PlanLocationModel, position: Int, selectedPosition: Int) {
binding.planLocationItem = item

binding.root.setOnClickListener {
binding.imvPlanLocationCheck.setImageResource(R.drawable.ic_all_check_selected_24)
binding.imvPlanLocationCheck.isSelected = position == selectedPosition

binding.imvPlanLocationCheck.setOnClickListener {
this.selectedPosition = position
itemClickListener.onClick(it, item)
}
}

*//*if (selectedPosition == this.adapterPosition) {
planLocationList[adapterPosition].isSelected = true
binding.imvPlanLocationCheck.setImageResource(R.drawable.ic_all_check_selected_24)
} else {
planLocationList[adapterPosition].isSelected = false
binding.imvPlanLocationCheck.setImageResource(R.drawable.ic_all_check_default_24)
}

if (onItemClickListener != null) {
binding.root.setOnClickListener {
onItemClickListener?.onItemClick(item, adapterPosition)
if (selectedPosition != adapterPosition) {
val previousSelectedPosition = selectedPosition
selectedPosition = adapterPosition
adapter.updateItem(previousSelectedPosition)
adapter.updateItem(selectedPosition)
}
}
}*//*
}
}*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.sopt.pingle.presentation.ui.plan

import androidx.lifecycle.ViewModel
import org.sopt.pingle.presentation.model.PlanLocationModel

class PlanLocationViewModel : ViewModel() {
val mockPlanLocationList = listOf<PlanLocationModel>(
PlanLocationModel(
location = "하얀집",
address = "서울 중구 퇴계로6길 12",
x = 123.5,
y = 56.7,
),
PlanLocationModel(
location = "하얀집2호점",
address = "서울 중구 퇴계로6길 12",
x = 123.5,
y = 56.7,
),
PlanLocationModel(
location = "하얀집3호점",
address = "서울 중구 퇴계로6길 12",
x = 123.5,
y = 56.7,
),
PlanLocationModel(
location = "하얀집 싫어싫어싫어",
address = "서울 중구 퇴계로6길 12",
x = 123.5,
y = 56.7,
),
PlanLocationModel(
location = "하얀집 좋아좋아좋아",
address = "서울 중구 퇴계로6길 12",
x = 123.5,
y = 56.7,
),
PlanLocationModel(
location = "하얀집웅시러",
address = "서울 중구 퇴계로6길 12",
x = 123.5,
y = 56.7,
),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sopt.pingle.presentation.ui.plan

import androidx.lifecycle.ViewModel
import org.sopt.pingle.presentation.model.PlanModel

class PlanViewModel : ViewModel() {
val mockPlanList = listOf<PlanModel>(
PlanModel(
category = "others",
name = "개빡세게 공부",
date = "2024년 1월 18일",
startAt = "오후 05:00",
endAt = "오후 10:00",
x = 15.8,
y = 192.4,
address = "서울 중구 퇴계로6길 12",
location = "하얀집",
),
)
}
14 changes: 14 additions & 0 deletions app/src/main/java/org/sopt/pingle/util/base/BindingAdapter.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sopt.pingle.util.base

import android.view.View
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.databinding.BindingAdapter
Expand All @@ -9,3 +10,16 @@ fun setImageResource(imageView: ImageView, resId: Int) {
val drawable = ContextCompat.getDrawable(imageView.context, resId)
imageView.setImageDrawable(drawable)
}

@BindingAdapter("visibility")
fun View.setVisibility(isVisible: Boolean?) {
if (isVisible == null) {
return
}
this.visibility =
if (isVisible) {
View.VISIBLE
} else {
View.INVISIBLE
}
}
18 changes: 9 additions & 9 deletions app/src/main/java/org/sopt/pingle/util/component/PingleChip.kt
Copy link
Collaborator

Choose a reason for hiding this comment

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

변경하신 이유가 있나요,,?? 없다면 되돌려 주세요 ㅜㅜ

Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ import org.sopt.pingle.presentation.type.CategoryType
class PingleChip @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.style.Theme_Pingle_Chip_All
defStyleAttr: Int = R.style.Theme_Pingle_Chip,
) : Chip(context, attrs, defStyleAttr) {

private fun setColorStateList(
context: Context,
activatedColorRes: Int,
inactivatedColorRes: Int
inactivatedColorRes: Int,
) =
ColorStateList(
arrayOf(
intArrayOf(android.R.attr.state_checked),
intArrayOf(-android.R.attr.state_checked)
intArrayOf(-android.R.attr.state_checked),
),
intArrayOf(
ContextCompat.getColor(context, activatedColorRes),
ContextCompat.getColor(context, inactivatedColorRes)
)
ContextCompat.getColor(context, inactivatedColorRes),
),
)

fun setChipCategoryType(categoryType: CategoryType) {
Expand All @@ -41,19 +41,19 @@ class PingleChip @JvmOverloads constructor(
chipStrokeColor = setColorStateList(
context = context,
activatedColorRes = categoryType.activatedOutLinedColor,
inactivatedColorRes = inactivatedOutlinedColor
inactivatedColorRes = inactivatedOutlinedColor,
)
chipBackgroundColor = setColorStateList(
context = context,
activatedColorRes = categoryType.backgroundChipColor,
inactivatedColorRes = inactivatedChipColor
inactivatedColorRes = inactivatedChipColor,
)
setTextColor(
setColorStateList(
context = context,
activatedColorRes = categoryType.textColor,
inactivatedColorRes = inactivatedTextColor
)
inactivatedColorRes = inactivatedTextColor,
),
)
}
}
Loading