Skip to content

Commit

Permalink
[MERGE] : #135 -> main
Browse files Browse the repository at this point in the history
[FEAT/#135] 유저 리뷰 기능 구현 완료
  • Loading branch information
kkk5474096 authored Feb 13, 2024
2 parents 5c0a34f + 39a88ed commit da12778
Show file tree
Hide file tree
Showing 43 changed files with 1,081 additions and 319 deletions.
13 changes: 9 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@
</intent-filter>
</service>

<activity
android:name=".presentation.familiar.FamiliarDialogActivity"
android:exported="false" />
<activity
android:name=".presentation.MainActivity"
android:exported="true" />
Expand Down Expand Up @@ -105,10 +102,18 @@
<activity
android:name=".presentation.group.join.JoinFriendListActivity"
android:exported="false" />
<activity
android:name=".presentation.group.review.ReviewActivity"
android:exported="false" />
<activity
android:name=".presentation.group.review.ReviewOnboardingActivity"
android:exported="false" />
<activity
android:name=".presentation.group.review.ReviewFinishActivity"
android:exported="false" />
<activity
android:name=".presentation.notification.AlertsListActivity"
android:exported="false" />

<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/teum_notification_channel_id" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ import androidx.navigation.ui.setupWithNavController
import com.teumteum.base.BindingActivity
import com.teumteum.base.util.extension.boolExtra
import com.teumteum.base.util.extension.intExtra
import com.teumteum.base.util.extension.longExtra
import com.teumteum.base.util.extension.stringExtra
import com.teumteum.domain.entity.Message
import com.teumteum.teumteum.R
import com.teumteum.teumteum.databinding.ActivityMainBinding
import com.teumteum.teumteum.presentation.group.review.ReviewOnboardingActivity
import com.teumteum.teumteum.presentation.home.HomeFragmentDirections
import com.teumteum.teumteum.presentation.signin.SignInViewModel
import dagger.hilt.android.AndroidEntryPoint
Expand All @@ -27,6 +30,8 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
private val id by intExtra()
private var isGroup: Boolean = false
private val isFromAlarm by boolExtra()
private val meetingId by longExtra()
private val title by stringExtra()

private val viewModel by viewModels<SignInViewModel>()

Expand All @@ -42,7 +47,9 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main

if (id != -1) { moveRecommendDetail() }
if(isGroup) { moveWebView() }

if (meetingId != -1L && title != null) {
moveReviewOnboardingActivity()
}

if (isFromAlarm) {
val message = intent.getSerializableExtra(MESSAGE) as Message
Expand Down Expand Up @@ -81,6 +88,10 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
navHostFragment.navController.navigate(action)
}

private fun moveReviewOnboardingActivity() {
startActivity(ReviewOnboardingActivity.getIntent(this, meetingId, title!!))
}

fun returnGroupDetail(fullAddress:String) {
val returnIntent = Intent().apply {
putExtra("address", fullAddress)
Expand Down Expand Up @@ -154,7 +165,10 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
putExtra("id", id)
putExtra(IS_FROM_ALARM, isFromAlarm)
}

fun getIntent(context: Context, meetingId: Long, title: String) = Intent(context, MainActivity::class.java).apply {
putExtra("meetingId", meetingId)
putExtra("title", title)
}
private const val IS_FROM_ALARM = "isFromAlarm"
private const val MESSAGE = "message"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.teumteum.teumteum.presentation.group.review

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.fragment.app.commit
import com.teumteum.base.BindingActivity
import com.teumteum.base.component.appbar.AppBarLayout
import com.teumteum.base.component.appbar.AppBarMenu
import com.teumteum.base.databinding.LayoutCommonAppbarBinding
import com.teumteum.base.util.extension.longExtra
import com.teumteum.teumteum.R
import com.teumteum.teumteum.databinding.ActivityReviewBinding
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class ReviewActivity : BindingActivity<ActivityReviewBinding>(R.layout.activity_review),
AppBarLayout {
private val viewModel by viewModels<ReviewViewModel>()
private val meetingId by longExtra()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

viewModel.meetingId = meetingId
initAppBarLayout()
initView()
}

override val appBarBinding: LayoutCommonAppbarBinding
get() = binding.appBar

override fun initAppBarLayout() {
setAppBarHeight(48)

addMenuToLeft(
AppBarMenu.IconStyle(
resourceId = R.drawable.ic_close,
useRippleEffect = false,
clickEvent = {
ReviewInfoDialog().show(supportFragmentManager, "dialog")
}
)
)
}

private fun initView() {
supportFragmentManager.commit {
replace(R.id.fragment_container, ReviewFriendSelectFragment())
}
}

fun nextFriendDetailFragment() {
if (viewModel.currentFriendIndex >= viewModel.selectFriendList.size) return
with(viewModel.selectFriendList[viewModel.currentFriendIndex++]) {
val fragment = ReviewFriendDetailFragment.newInstance(id, characterId, name, job)

supportFragmentManager.commit {
replace(R.id.fragment_container, fragment)
}
}
}

companion object {
fun getIntent(context: Context, meetingId: Long) =
Intent(context, ReviewActivity::class.java).apply {
putExtra("meetingId", meetingId)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.teumteum.teumteum.presentation.group.review

import android.content.Intent
import android.os.Bundle
import com.teumteum.base.BindingActivity
import com.teumteum.base.component.appbar.AppBarLayout
import com.teumteum.base.component.appbar.AppBarMenu
import com.teumteum.base.databinding.LayoutCommonAppbarBinding
import com.teumteum.base.util.extension.setOnSingleClickListener
import com.teumteum.teumteum.R
import com.teumteum.teumteum.databinding.ActivityReviewFinishBinding
import com.teumteum.teumteum.presentation.MainActivity

class ReviewFinishActivity :
BindingActivity<ActivityReviewFinishBinding>(R.layout.activity_review_finish), AppBarLayout {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initAppBarLayout()
initEvent()
}

override val appBarBinding: LayoutCommonAppbarBinding
get() = binding.appBar

override fun initAppBarLayout() {
setAppBarHeight(48)

addMenuToLeft(
AppBarMenu.IconStyle(
resourceId = R.drawable.ic_arrow_left_l,
useRippleEffect = false,
clickEvent = {
goToMainActivity()
}
)
)
}

private fun initEvent() {
binding.btnHome.setOnSingleClickListener {
goToMainActivity()
}
}

private fun goToMainActivity() {
Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(this)
}
openActivitySlideAnimation()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.teumteum.teumteum.presentation.group.review

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.teumteum.base.BindingFragment
import com.teumteum.base.util.extension.defaultToast
import com.teumteum.base.util.extension.longArgs
import com.teumteum.base.util.extension.setOnSingleClickListener
import com.teumteum.base.util.extension.stringArgs
import com.teumteum.domain.entity.ReviewFriend
import com.teumteum.teumteum.R
import com.teumteum.teumteum.databinding.FragmentReviewFriendDetailBinding
import com.teumteum.teumteum.util.ResMapper
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

class ReviewFriendDetailFragment :
BindingFragment<FragmentReviewFriendDetailBinding>(R.layout.fragment_review_friend_detail) {
private val viewModel by activityViewModels<ReviewViewModel>()
private val id by longArgs()
private val characterId by longArgs()
private val name by stringArgs()
private val job by stringArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

initView()
initClick()
observe()
}

private fun initView() {
with(binding) {
tvTitle.text = getString(R.string.review_select_friend_title, name)
tvName.text = name
tvCompany.text = job
ivUserIcon.setImageResource(ResMapper.getCharacterDrawableById(characterId.toInt()))
}

binding.btnReview.text =
"리뷰 남기기 (${viewModel.currentFriendIndex}/${viewModel.selectFriendList.size}}"
}

private fun initClick() {
val friendDetail = ReviewFriend(id, characterId, name, job)
binding.btnReview.setOnSingleClickListener {
if (viewModel.currentFriendIndex < viewModel.selectFriendList.size) {
viewModel.addSelectDetailFriendList(friendDetail)
(requireActivity() as? ReviewActivity)?.nextFriendDetailFragment()
} else {
viewModel.postRegisterReview()
}
}

binding.clBad.setOnSingleClickListener {
setSelectReview(it.id)
friendDetail.review = "별로에요"
}

binding.clBest.setOnSingleClickListener {
setSelectReview(it.id)
friendDetail.review = "최고에요"
}

binding.clGood.setOnSingleClickListener {
setSelectReview(it.id)
friendDetail.review = "좋아요"
}
}

private fun observe() {
viewModel.reviewState.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach {
when (it) {
is ReviewUiState.Success -> {
startActivity(Intent(requireActivity(), ReviewFinishActivity::class.java))
}

is ReviewUiState.Failure -> {
requireActivity().defaultToast(it.msg)
}

else -> {}
}

}.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun setSelectReview(viewId: Int) {
with(binding) {
tvBad.isSelected = viewId == clBad.id
ivBad.isSelected = viewId == clBad.id
tvBest.isSelected = viewId == clBest.id
ivBest.isSelected = viewId == clBest.id
tvGood.isSelected = viewId == clGood.id
ivGood.isSelected = viewId == clGood.id

btnReview.isEnabled = true
}
}

companion object {
fun newInstance(id: Long, characterId: Long, name: String, job: String) =
ReviewFriendDetailFragment().apply {
arguments = Bundle().apply {
putLong("id", id)
putLong("characterId", characterId)
putString("name", name)
putString("job", job)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.teumteum.teumteum.presentation.group.review

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.teumteum.base.util.extension.setOnSingleClickListener
import com.teumteum.domain.entity.ReviewFriend
import com.teumteum.teumteum.databinding.ItemReviewUserBinding
import com.teumteum.teumteum.util.ResMapper
import com.teumteum.teumteum.util.callback.ItemDiffCallback

class ReviewFriendListAdapter(private val itemClick: (ReviewFriend) -> (Unit)) :
ListAdapter<ReviewFriend, ReviewFriendListAdapter.ReviewFriendViewHolder>(
DIFF_UTIL
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReviewFriendViewHolder {
val binding = ItemReviewUserBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ReviewFriendViewHolder(binding, itemClick)
}

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

class ReviewFriendViewHolder(
private val binding: ItemReviewUserBinding,
private val itemClick: (ReviewFriend) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
fun onBind(item: ReviewFriend) {
binding.tvName.text = item.name
binding.tvCompany.text = item.job
binding.ivSelected.isSelected = item.isSelected
binding.ivUserIcon.setImageResource(ResMapper.getCharacterDrawableById(item.characterId.toInt()))

binding.root.setOnSingleClickListener {
itemClick(item)
}
}
}

companion object {
val DIFF_UTIL = ItemDiffCallback<ReviewFriend>(
onItemsTheSame = { old, new -> old.id == new.id },
onContentsTheSame = { old, new -> old.isSelected == new.isSelected },
)

}
}
Loading

0 comments on commit da12778

Please sign in to comment.