Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 2 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
*.iml
.gradle
.idea
gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
android:name=".presentation.view.detail.DetailActivity"
android:exported="false" />
<activity
android:name=".presentation.MainActivity"
android:name=".presentation.view.test.TestActivity"
android:exported="true"
android:theme="@style/Theme.GroupFinder">
<intent-filter>
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/kr/cosine/groupfinder/data/mapper/PostMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kr.cosine.groupfinder.data.mapper

import kr.cosine.groupfinder.data.model.PostModel
import kr.cosine.groupfinder.domain.model.PostEntity

fun PostEntity.toPostResponse(): PostModel {
return PostModel(
uniqueId = uniqueId.toString(),
mode = mode.name,
title = title,
body = body,
id = id,
tags = tags,
laneMap = laneMap.mapKeys { it.key.name },
time = time
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ data class PostModel(

fun PostModel.getTotalPeopleCount(): Int = laneMap.size

fun PostModel.getAvaliablePeopleCount(): Int {
fun PostModel.getJoinedPeopleCount(): Int {
return laneMap.values.count { it != null }
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kr.cosine.groupfinder.domain.extension

import kr.cosine.groupfinder.domain.model.PostEntity

fun PostEntity.getTotalPeopleCount(): Int = laneMap.size

fun PostEntity.getJoinedPeopleCount(): Int {
return laneMap.values.count { it != null }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.cosine.groupfinder.domain.mapper

import kr.cosine.groupfinder.data.model.PostModel
import kr.cosine.groupfinder.domain.model.PostEntity
import kr.cosine.groupfinder.enums.Lane
import kr.cosine.groupfinder.enums.Mode
import java.util.UUID

fun PostModel.toEntity(): PostEntity {
return PostEntity(
uniqueId = UUID.fromString(uniqueId),
mode = Mode.valueOf(mode),
title = title,
body = body,
id = id,
tags = tags,
laneMap = laneMap.mapKeys { Lane.valueOf(it.key) }.toSortedMap(compareBy { it.ordinal }),
time = time
)
}
17 changes: 17 additions & 0 deletions app/src/main/java/kr/cosine/groupfinder/domain/model/PostEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kr.cosine.groupfinder.domain.model

import com.google.firebase.Timestamp
import kr.cosine.groupfinder.enums.Lane
import kr.cosine.groupfinder.enums.Mode
import java.util.UUID

data class PostEntity(
val uniqueId: UUID,
val mode: Mode,
val title: String,
val body: String,
val id: String,
val tags: List<String>,
val laneMap: Map<Lane, String?>,
val time: Timestamp
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package kr.cosine.groupfinder.domain.usecase

import dagger.hilt.android.scopes.ViewModelScoped
import kr.cosine.groupfinder.data.model.PostModel
import kr.cosine.groupfinder.domain.extension.getJoinedPeopleCount
import kr.cosine.groupfinder.domain.extension.getTotalPeopleCount
import kr.cosine.groupfinder.domain.mapper.toEntity
import kr.cosine.groupfinder.domain.model.PostEntity
import kr.cosine.groupfinder.domain.repository.PostRepository
import kr.cosine.groupfinder.enums.Mode
import javax.inject.Inject

@ViewModelScoped
class GroupUseCase @Inject constructor(
private val postRepository: PostRepository
) {

suspend operator fun invoke(mode: Mode?, tags: List<String>): Result<List<PostEntity>> {
return runCatching {
var posts = postRepository.getPosts(tags).map(PostModel::toEntity)
if (mode != null) {
posts = posts.filter {
it.mode == mode
}
}
posts.sortedWith(
compareBy<PostEntity> {
it.getJoinedPeopleCount() == it.getTotalPeopleCount()
}.thenByDescending {
it.time
}
)
}
}
}
20 changes: 14 additions & 6 deletions app/src/main/java/kr/cosine/groupfinder/enums/Lane.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package kr.cosine.groupfinder.enums

import kr.cosine.groupfinder.R

enum class Lane(
val displayName: String
val displayName: String,
val drawableId: Int,
val emptyDrawableId: Int
) {
TOP("탑"),
JUNGLE("정글"),
MID("미드"),
AD("원딜"),
SUPPORT("서포터");
TOP("탑", R.drawable.ic_lane_top, R.drawable.ic_lane_empty_top),
JUNGLE("정글", R.drawable.ic_lane_jungle, R.drawable.ic_lane_empty_jungle),
MID("미드", R.drawable.ic_lane_mid, R.drawable.ic_lane_empty_mid),
AD("원딜", R.drawable.ic_lane_ad, R.drawable.ic_lane_empty_ad),
SUPPORT("서포터", R.drawable.ic_lane_spt, R.drawable.ic_lane_empty_spt);

fun getDrawableIdByOwner(hasOwner: Boolean): Int {
return if (hasOwner) drawableId else emptyDrawableId
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package kr.cosine.groupfinder.presentation.view.list

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kr.cosine.groupfinder.databinding.FragmentGroupBinding
import kr.cosine.groupfinder.enums.Mode
import kr.cosine.groupfinder.presentation.view.list.adapter.GroupAdpater
import kr.cosine.groupfinder.presentation.view.list.adapter.SearchTagAdpater
import kr.cosine.groupfinder.presentation.view.list.adapter.decoration.impl.GroupTagItemDecoration
import kr.cosine.groupfinder.presentation.view.list.event.TagEvent
import kr.cosine.groupfinder.presentation.view.list.model.GroupViewModel
import kr.cosine.groupfinder.presentation.view.list.model.TagViewModel
import kr.cosine.groupfinder.presentation.view.list.state.GroupUiState

@AndroidEntryPoint
class GroupFragment(
private val mode: Mode? = null
) : Fragment() {

private var _binding: FragmentGroupBinding? = null
private val binding: FragmentGroupBinding get() = _binding!!

private val groupViewModel by viewModels<GroupViewModel>()
private val tagViewModel by activityViewModels<TagViewModel>()

private lateinit var groupAdpater: GroupAdpater
private lateinit var searchTagAdpater: SearchTagAdpater

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentGroupBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
registerNavigationButton()
registerGroupRecyclerView()
registerTagRecyclerView()
registerSearchBarButton()
registerWriteButton()
registerGroupViewModelEvent()
registerTagViewModel()
}

private fun registerNavigationButton() {
binding.navigationImageButton.setOnClickListener {

}
}

private fun registerGroupRecyclerView() = with(binding.groupRecyclerView) {
adapter = GroupAdpater(context) { post ->

}.apply {
groupAdpater = this
}
}

private fun registerTagRecyclerView() = with(binding.tagRecyclerView) {
adapter = SearchTagAdpater(tagViewModel::removeTag).apply {
searchTagAdpater = this
}
addItemDecoration(GroupTagItemDecoration)
}

private fun registerSearchBarButton() = with(binding) {
clearTagImageButton.setOnClickListener {
tagViewModel.clearTag()
}
showAllTagImageButton.setOnClickListener {

}
searchImageButton.setOnClickListener {
val tags = tagViewModel.tags
if (tags.isEmpty()) return@setOnClickListener
groupViewModel.onSearch(mode, tags)
}
}

private fun registerWriteButton() {
binding.writeImageButton.setOnClickListener {

}
}

private fun registerGroupViewModelEvent() = with(binding) {
groupViewModel.onSearch(mode, emptyList())
viewLifecycleOwner.lifecycleScope.launch {
groupViewModel.uiState.flowWithLifecycle(lifecycle).collectLatest { uiState ->
val isLoading = uiState is GroupUiState.Loading
val isNotice = uiState is GroupUiState.Notice

searchProgressBar.isVisible = isLoading
searchResultNoticeTextView.isVisible = isNotice
groupRecyclerView.isVisible = !isLoading

searchImageButton.isEnabled = !isLoading
clearTagImageButton.isEnabled = !isLoading
showAllTagImageButton.isEnabled = !isLoading

when (uiState) {
is GroupUiState.Result -> groupAdpater.setPosts(uiState.posts)
is GroupUiState.Notice -> {
if (uiState is GroupUiState.ResultEmpty) {
groupAdpater.clearPosts()
}
searchResultNoticeTextView.text = uiState.message
}
else -> {}
}
}
}
}

private fun registerTagViewModel() {
viewLifecycleOwner.lifecycleScope.launch {
tagViewModel.event.flowWithLifecycle(lifecycle).collectLatest { event ->
when (event) {
is TagEvent.SetTag -> searchTagAdpater.setTags(event.tags)
is TagEvent.AddTag -> searchTagAdpater.addTag(event.tag)
is TagEvent.RemoveTag -> searchTagAdpater.removeTag(event.position)
}
}
}
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

This file was deleted.

Loading