Skip to content

Commit

Permalink
Merge pull request #17 from SSU-Plector/feat/#12-projects-ui
Browse files Browse the repository at this point in the history
[Feat/#12_projects_UI] 프로젝트 검색 페이지 ui 구현
  • Loading branch information
kangyuri1114 authored Mar 31, 2024
2 parents 8b73f51 + de22647 commit c144222
Show file tree
Hide file tree
Showing 21 changed files with 524 additions and 54 deletions.
4 changes: 2 additions & 2 deletions core/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ dependencies {
implementation(project(":core:designsystem"))

AndroidXDependencies.run {
implementation(hilt)
implementation(security)
implementation(coreKtx)
implementation(appCompat)
implementation(pagingRuntime)
}

KotlinDependencies.run {
Expand Down
38 changes: 38 additions & 0 deletions core/common/src/main/java/com/zucchini/view/ViewExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.zucchini.view

import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView

class ItemDiffCallback<T : Any>(
val onItemsTheSame: (T, T) -> Boolean,
val onContentsTheSame: (T, T) -> Boolean,
) : DiffUtil.ItemCallback<T>() {
override fun areItemsTheSame(
oldItem: T,
newItem: T,
): Boolean = onItemsTheSame(oldItem, newItem)

override fun areContentsTheSame(
oldItem: T,
newItem: T,
): Boolean = onContentsTheSame(oldItem, newItem)
}

class HorizontalSpaceItemDecoration(private val horizontalSpaceHeight: Int) :
RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State,
) {
val position = parent.getChildAdapterPosition(view)

// 첫 번째와 마지막 아이템을 제외한 경우에만 마진 적용
if (position != 0) {
outRect.left = horizontalSpaceHeight
}
}
}
2 changes: 2 additions & 0 deletions core/designsystem/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<color name="olive_gray">#9F9592</color>
<color name="olive_light_gray">#EDE4E1</color>
<color name="gray1">#C1C1C1</color>
<color name="gray2">#A3A3A3</color>

<!-- Other Colors -->
<color name="olive_pink">#FFE5DD</color>
</resources>
3 changes: 3 additions & 0 deletions domain/src/main/java/com/zucchini/domain/model/Keyword.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.zucchini.domain.model

data class Keyword(val keyword: String = "")
18 changes: 18 additions & 0 deletions domain/src/main/java/com/zucchini/domain/model/KeywordList.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.zucchini.domain.model

object KeywordList {
val searchKeyword = listOf(
"서비스",
"보안",
"네트워크",
"데이터 분석",
"인공지능",
"임베디드",
"IoT",
"게임",
"자율주행",
"클라우드",
"빅데이터",
"블록체인",
)
}
9 changes: 9 additions & 0 deletions domain/src/main/java/com/zucchini/domain/model/ProjectInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.zucchini.domain.model

data class ProjectInfo(
val image: Int? = null,
val name: String = "",
val description: String = "",
val sorted: String = "",
val clicked: Int = 0,
)
4 changes: 2 additions & 2 deletions feature/projects/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ dependencies {
implementation(pagingRuntime)
implementation(workManager)
implementation(hiltWorkManager)
implementation(navigationFragment)
implementation(navigationUi)
}

KaptDependencies.run {
Expand All @@ -73,8 +75,6 @@ dependencies {
}

implementation(MaterialDesignDependencies.materialDesign)
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")

TestDependencies.run {
testImplementation(jUnit)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.zucchini.projects

import com.zucchini.domain.model.ProjectInfo
import com.zucchini.feature.projects.R

object ProjectDummyList {
val projectDummyList = listOf(
ProjectInfo(
image = R.drawable.devinfo_navi_24,
name = "프로젝트1",
description = "프로젝트1 설명",
sorted = "서비스",
clicked = 0,
),
ProjectInfo(
image = R.drawable.devinfo_navi_24,
name = "프로젝트2",
description = "프로젝트2 설명",
sorted = "임베디드",
clicked = 0,
),
ProjectInfo(
image = null,
name = "프로젝트3",
description = "프로젝트3 설명",
sorted = "IoT",
clicked = 0,
),
ProjectInfo(
image = R.drawable.devinfo_navi_24,
name = "프로젝트4",
description = "프로젝트4 설명",
sorted = "빅데이터",
clicked = 0,
),
ProjectInfo(
image = null,
name = "프로젝트5",
description = "프로젝트5 설명",
sorted = "빅데이터",
clicked = 0,
),
ProjectInfo(
image = null,
name = "프로젝트6",
description = "프로젝트6 설명",
sorted = "빅데이터",
clicked = 2,
),
ProjectInfo(
image = null,
name = "프로젝트7",
description = "프로젝트7 설명",
sorted = "빅데이터",
clicked = 22,
),
ProjectInfo(
image = null,
name = "프로젝트8",
description = "프로젝트8 설명",
sorted = "빅데이터",
clicked = 23,
),
ProjectInfo(
image = null,
name = "프로젝트9",
description = "프로젝트9 설명",
sorted = "빅데이터",
clicked = 2345,
),
ProjectInfo(
image = null,
name = "프로젝트10",
description = "프로젝트10 설명",
sorted = "빅데이터",
clicked = 123,
),
)
}
Original file line number Diff line number Diff line change
@@ -1,60 +1,50 @@
package com.zucchini.projects

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.zucchini.feature.projects.R

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.zucchini.domain.model.Keyword
import com.zucchini.domain.model.KeywordList
import com.zucchini.feature.projects.databinding.FragmentProjectsBinding
import com.zucchini.projects.adapter.ProjectsAdapter
import com.zucchini.projects.adapter.SearchKeywordAdapter

/**
* A simple [Fragment] subclass.
* Use the [ProjectsFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class ProjectsFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentProjectsBinding? = null
private val binding: FragmentProjectsBinding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentProjectsBinding.inflate(inflater, container, false)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
initKeywordAdapter()
initProjectsAdapter()

return binding.root
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_projects, container, false)
private fun initProjectsAdapter() {
val projectsAdapter = ProjectsAdapter()
binding.rvProjects.layoutManager = LinearLayoutManager(context)
binding.rvProjects.adapter = projectsAdapter
projectsAdapter.submitList(ProjectDummyList.projectDummyList)
}

private fun initKeywordAdapter() {
val searchKeywordAdapter = SearchKeywordAdapter()
binding.rvSearchKeyword.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
binding.rvSearchKeyword.adapter = searchKeywordAdapter
searchKeywordAdapter.submitList(KeywordList.searchKeyword.map { Keyword(it) })
}

companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ProjectsFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
ProjectsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.zucchini.projects.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.zucchini.feature.projects.R
import com.zucchini.feature.projects.databinding.ItemProjectsBinding
import com.zucchini.domain.model.ProjectInfo
import com.zucchini.view.ItemDiffCallback

class ProjectsAdapter : ListAdapter<ProjectInfo, ProjectsAdapter.ProjectsViewHolder>(
ItemDiffCallback<ProjectInfo>(
onItemsTheSame = { old, new -> old == new },
onContentsTheSame = { old, new -> old == new },
),
) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): ProjectsViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemProjectsBinding.inflate(inflater, parent, false)
return ProjectsViewHolder(binding)
}

override fun onBindViewHolder(holder: ProjectsViewHolder, position: Int) {
holder.bind(getItem(position))
}

inner class ProjectsViewHolder(private val binding: ItemProjectsBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(projectInfo: ProjectInfo) {
binding.ivProjectProfile.setImageResource(
projectInfo.image ?: R.drawable.project_profile_default,
)
binding.tvProjectName.text = projectInfo.name
binding.tvProjectDescription.text = projectInfo.description
binding.tvProjectSorted.text = projectInfo.sorted
binding.tvProjectClicked.text = "조회수 +${projectInfo.clicked}"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.zucchini.projects.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.zucchini.feature.projects.databinding.ItemSearchKeywordBinding
import com.zucchini.view.ItemDiffCallback
import com.zucchini.domain.model.Keyword

class SearchKeywordAdapter : ListAdapter<Keyword, SearchKeywordAdapter.SearchKeywordViewHolder>(
ItemDiffCallback<Keyword>(
onItemsTheSame = { old, new -> old == new },
onContentsTheSame = { old, new -> old == new },
),
) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): SearchKeywordViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemSearchKeywordBinding.inflate(inflater, parent, false)
return SearchKeywordViewHolder(binding)
}

override fun onBindViewHolder(holder: SearchKeywordViewHolder, position: Int) {
holder.bind(getItem(position))
}

inner class SearchKeywordViewHolder(private val binding: ItemSearchKeywordBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(keyword: Keyword) {
binding.tvSearchKeyword.text = keyword.keyword
}
}
}
5 changes: 5 additions & 0 deletions feature/projects/src/main/res/drawable/arrow_down_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#373130"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="49dp"
android:height="27dp"
android:viewportWidth="49"
android:viewportHeight="27">
<path
android:pathData="M7,0L42,0A7,7 0,0 1,49 7L49,20A7,7 0,0 1,42 27L7,27A7,7 0,0 1,0 20L0,7A7,7 0,0 1,7 0z"
android:fillColor="#EDE4E1"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="49dp"
android:height="27dp"
android:viewportWidth="49"
android:viewportHeight="27">
<path
android:pathData="M7,0L42,0A7,7 0,0 1,49 7L49,20A7,7 0,0 1,42 27L7,27A7,7 0,0 1,0 20L0,7A7,7 0,0 1,7 0z"
android:fillColor="@color/olive_pink"/>
</vector>
Loading

0 comments on commit c144222

Please sign in to comment.