Skip to content

Commit

Permalink
Merge pull request #28 from depromeet/feature/#11-group-search
Browse files Browse the repository at this point in the history
  • Loading branch information
Mnseo authored Jan 11, 2024
2 parents 557ad8e + f57cf5a commit ce1abaa
Show file tree
Hide file tree
Showing 34 changed files with 559 additions and 16 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<activity android:name=".presentation.onboarding.OnBoardingActivity"
android:exported="true">
</activity>
<activity android:name=".presentation.group.search.SearchActivity"
android:exported="false" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.teumteum.teumteum.di

import com.teumteum.data.repository.GroupRepositoryImpl
import com.teumteum.data.repository.HomeRepositoryImpl
import com.teumteum.data.repository.SampleRepositoryImpl
import com.teumteum.domain.repository.GroupRepository
import com.teumteum.domain.repository.HomeRepository
import com.teumteum.domain.repository.SampleRepository
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
Expand All @@ -21,4 +24,8 @@ interface RepositoryModule {
@Singleton
@Binds
fun bindHomeRepository(homeRepositoryImpl: HomeRepositoryImpl): HomeRepository

@Singleton
@Binds
fun provideGroupRepository(groupRepositoryImpl: GroupRepositoryImpl): GroupRepository
}
6 changes: 6 additions & 0 deletions app/src/main/java/com/teumteum/teumteum/di/ServiceModule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.teumteum.teumteum.di


import com.teumteum.data.service.GroupService
import com.teumteum.data.service.HomeService
import com.teumteum.data.service.SampleService
import dagger.Module
Expand All @@ -22,4 +23,9 @@ object ServiceModule {
@Provides
fun provideHomeService(teumteumRetrofit: Retrofit) =
teumteumRetrofit.create(HomeService::class.java)

@Singleton
@Provides
fun provideGroupService(retrofit: Retrofit) =
retrofit.create(GroupService::class.java)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.teumteum.teumteum.presentation.group
import android.os.Bundle
import android.widget.Toast
import com.teumteum.base.BindingActivity
import com.teumteum.domain.entity.Group
import com.teumteum.domain.entity.Meeting
import com.teumteum.teumteum.R
import com.teumteum.teumteum.databinding.ActivityGroupListBinding

Expand All @@ -26,12 +26,12 @@ class GroupListActivity : BindingActivity<ActivityGroupListBinding>(R.layout.act
binding.rvGroupList.adapter = adapter
adapter.setItems(
listOf(
Group(1L, "모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"),
Group(2L, "모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"),
Group(3L, "모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"),
Group(4L, "모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"),
Group(5L, "모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"),
Group(6L, "모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"),
Meeting(1L, 1L,"모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"),
Meeting(2L, 2L,"모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"),
Meeting(3L, 3L,"모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"),
Meeting(4L, 4L,"모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"),
Meeting(5L, 5L,"모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"),
Meeting(6L, 6L,"모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"),
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package com.teumteum.teumteum.presentation.group
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.teumteum.domain.entity.Group
import com.teumteum.domain.entity.Meeting
import com.teumteum.teumteum.databinding.ItemGroupListBinding

class GroupListAdapter(private val itemClick: (Group) -> (Unit)) :
class GroupListAdapter(private val itemClick: (Meeting) -> (Unit)) :
RecyclerView.Adapter<GroupListAdapter.GroupListViewHolder>() {
private val groupList = mutableListOf<Group>()
private val groupList = mutableListOf<Meeting>()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroupListViewHolder {
val binding = ItemGroupListBinding.inflate(
Expand All @@ -25,17 +25,17 @@ class GroupListAdapter(private val itemClick: (Group) -> (Unit)) :

override fun getItemCount(): Int = groupList.size

fun setItems(newItems: List<Group>) {
fun setItems(newItems: List<Meeting>) {
groupList.clear()
groupList.addAll(newItems)
notifyDataSetChanged()
}

class GroupListViewHolder(
private val binding: ItemGroupListBinding,
private val itemClick: (Group) -> (Unit)
private val itemClick: (Meeting) -> (Unit)
) : RecyclerView.ViewHolder(binding.root) {
fun onBind(item: Group) {
fun onBind(item: Meeting) {
binding.tvGroupName.text = item.name
binding.tvTitleBadge.text = item.topic
binding.tvDate.text = item.date
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.teumteum.teumteum.presentation.group.search

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.teumteum.teumteum.databinding.ItemKeywordListBinding

class KeywordAdapter(private val itemClick: (String) -> (Unit)) :
RecyclerView.Adapter<KeywordAdapter.KeywordAdapter>() {
private val keywordList = mutableListOf<String>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KeywordAdapter {
val binding = ItemKeywordListBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false,
)
return KeywordAdapter(binding, itemClick)
}

override fun onBindViewHolder(holder: KeywordAdapter, position: Int) {
holder.onBind(keywordList[position])
}

override fun getItemCount(): Int = keywordList.size

fun setItems(newItems: List<String>) {
keywordList.clear()
keywordList.addAll(newItems)
notifyDataSetChanged()
}

class KeywordAdapter(
private val binding: ItemKeywordListBinding,
private val itemClick: (String) -> (Unit)
): RecyclerView.ViewHolder(binding.root) {
fun onBind(keyword: String) {
binding.tvKeyword.text = keyword

binding.root.setOnClickListener {
itemClick(keyword)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.teumteum.teumteum.presentation.group.search

import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.teumteum.base.BindingActivity
import com.teumteum.base.util.extension.hideKeyboard
import com.teumteum.base.util.extension.toast
import com.teumteum.teumteum.R
import com.teumteum.teumteum.databinding.ActivitySearchBinding
import com.teumteum.teumteum.presentation.group.GroupListAdapter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

@AndroidEntryPoint
class SearchActivity : BindingActivity<ActivitySearchBinding>(R.layout.activity_search) {
private val viewModel by viewModels<SearchViewModel>()
private lateinit var keywordAdapter: KeywordAdapter
private lateinit var groupListAdapter: GroupListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding.viewModel = viewModel
initView()
initEvent()
observe()
}

private fun initView() {
initKeywordAdapter()
initGroupListAdapter()
}

private fun initKeywordAdapter() {
keywordAdapter = KeywordAdapter {
binding.etSearch.setText(it)
viewModel.initCurrentPage(it)
hideKeyboard(binding.root)
}
binding.rvRecommendKeyword.adapter = keywordAdapter
keywordAdapter.setItems(viewModel.keywordList)
}

private fun initGroupListAdapter() {
groupListAdapter = GroupListAdapter {
//TODO 그룹 상세보기로 이동하는 로직 들어가야 함
}
binding.rvGroupList.adapter = groupListAdapter
}

private fun initEvent() {
binding.ivSearch.setOnClickListener {
if (viewModel.isInputBlank) {
toast(getString(R.string.group_search_empty_keyword))
} else {
viewModel.initCurrentPage()
hideKeyboard(binding.root)
}
}

binding.ivClear.setOnClickListener {
binding.etSearch.text.clear()
}

binding.etSearch.setOnFocusChangeListener { _, hasFocus ->
binding.ivClear.isVisible = (hasFocus)
}
}

private fun observe() {
viewModel.searchData.flowWithLifecycle(lifecycle)
.onEach {
binding.clRecommendKeyword.isVisible = it is SearchUiState.Init
binding.rvGroupList.isGone = it is SearchUiState.Init || it is SearchUiState.Empty
binding.clEmpty.isVisible = it is SearchUiState.Empty
when (it) {
is SearchUiState.Success -> {
groupListAdapter.setItems(it.data)
}

is SearchUiState.Empty -> {
binding.tvEmptyGroupTitle.text =
getString(R.string.group_search_keyword, it.keyword)
}

else -> {}
}
}.launchIn(lifecycleScope)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.teumteum.teumteum.presentation.group.search

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.teumteum.domain.entity.Meeting
import com.teumteum.domain.repository.GroupRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SearchViewModel @Inject constructor(
private val repository: GroupRepository
) : ViewModel() {
val etSearch = MutableStateFlow("")

val isInputBlank
get() = etSearch.value.isBlank()

private var currentPage = 0

val keywordList =
listOf<String>("스터디", "독서", "외주", "모여서 각자 일하기", "커리어", "직무 고민", "사이드 프로젝트", "N잡")

private val _searchData = MutableStateFlow<SearchUiState>(SearchUiState.Init)
val searchData: StateFlow<SearchUiState> = _searchData

fun initCurrentPage(keyword: String? = null) {
currentPage = 0
getSearchGroup(keyword)
}

fun getSearchGroup(keyword: String? = null) {
viewModelScope.launch {
repository.getSearchGroup(currentPage++, keyword ?: etSearch.value)
.onSuccess {
if (it.isEmpty()) {
_searchData.value = SearchUiState.Empty(keyword ?: etSearch.value)
} else {
_searchData.value = SearchUiState.Success(it)
}
}.onFailure {
_searchData.value = SearchUiState.Failure("실패")
}
}
}
}

sealed interface SearchUiState {
object Init : SearchUiState
data class Empty(val keyword: String) : SearchUiState
data class Success(val data: List<Meeting>) : SearchUiState
data class Failure(val msg: String) : SearchUiState
}
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/shape_outline_level3_200dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1dp" android:color="@color/outline_level03" />
<corners android:radius="200dp" />
</shape>
Loading

0 comments on commit ce1abaa

Please sign in to comment.