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] 나의 단체 뷰 구현 #201

Merged
merged 24 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c06dc52
[add] #194 String 리소스 추가
HAJIEUN02 Feb 22, 2024
fc7ae00
[add] #194 이미지 리소스 추가
HAJIEUN02 Feb 22, 2024
5d57c48
[add] #194 이미지 리소스 추가
HAJIEUN02 Feb 24, 2024
edb4951
[add] #194 String 리소스 추가
HAJIEUN02 Feb 24, 2024
7ddaad9
[feat] #194 나의 단체 뷰 : UI 구현
HAJIEUN02 Feb 24, 2024
d364248
[feat] #194 나의 단체 뷰 : Dto, Entity 추가 및 pref에 저장
HAJIEUN02 Feb 24, 2024
6707090
[feat] #194 나의 단체 뷰 : 나의 단체 리사이클러뷰 구현
HAJIEUN02 Feb 24, 2024
d3dce46
[feat] #194 나의 단체 뷰 : 초대코드 복사 기능 구현
HAJIEUN02 Feb 24, 2024
8cb2205
[feat] #194 나의 단체 뷰 : 현재 단체 단체장 여부 visibility 설정
HAJIEUN02 Feb 24, 2024
c293513
[feat] #194 나의 단체 뷰 : 현재 단체 공유하기 구현
HAJIEUN02 Feb 24, 2024
acb6eb3
[chore] #194 ktlintFormat 적용
HAJIEUN02 Feb 24, 2024
fda97c8
[chore] #194 activity_my_group.xml 데이터바인딩으로 변경
HAJIEUN02 Feb 25, 2024
1efd17e
[feat] #194 단체 변경 로직 구현
HAJIEUN02 Feb 25, 2024
c22fe8c
Merge branch 'develop' into feat-my-group
HAJIEUN02 Feb 25, 2024
46574d2
[chore] #194 conflict 해결 및 ktlintFormat 적용
HAJIEUN02 Feb 25, 2024
2715e79
Merge branch 'develop' into feat-my-group
HAJIEUN02 Feb 26, 2024
74cfc62
[chore] #194 나의 단체 뷰 : chip style 적용
HAJIEUN02 Feb 26, 2024
7d16745
[feat] #194 나의 단체 뷰 : 복사하기, 공유하기 확장함수 구현
HAJIEUN02 Feb 28, 2024
51dec5d
[feat] #194 나의 단체 뷰 : 나의 단체 뷰 모달 구현
HAJIEUN02 Feb 28, 2024
c36b0d9
[chore] #194 나의 단체 뷰 : 코드리뷰 반영
HAJIEUN02 Feb 29, 2024
45319c2
[chore] #194 나의 단체 뷰 : ktlintFormat 적용
HAJIEUN02 Feb 29, 2024
62b6a15
[chore] #194 나의 단체 뷰 : 코드리뷰 반영
HAJIEUN02 Mar 1, 2024
9924c7c
[chore] #194 나의 단체 뷰 : 코드리뷰 반영
HAJIEUN02 Mar 1, 2024
46cd733
[chore] #194 더보기 뷰 : 단체명 갱신
HAJIEUN02 Mar 1, 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
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ interface PingleLocalDataSource {
var refreshToken: String
var groupId: Int
var groupName: String
var meetingCount: String
var participantCount: String
var isOwner: Boolean
var groupKeyword: String
var code: String
fun clear(): Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,26 @@ class PingleLocalDataSourceImpl @Inject constructor(
get() = pref.getString(GROUP_NAME, "") ?: ""
set(value) = pref.edit { putString(GROUP_NAME, value) }

override var meetingCount: String
Copy link
Collaborator

Choose a reason for hiding this comment

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

오옹,, 이 정보 서버에서 아무것도 안내려주는건가요..? 어느 api에서도,,?

Copy link
Collaborator

Choose a reason for hiding this comment

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

서버에서 내려주는 값이 있고 그거 사용할 수 있다면 너무 많은 정보를 로컬에 저장해놓는건 핸드폰 기종에 따라 약간 무리일수도 ~~

Copy link
Collaborator

Choose a reason for hiding this comment

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

이거 단체 디테일 조회 API 있어서 그거 사용하면 될 듯 합니다 ~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

api 연동하면서 로직도 수정하겠습니다! localStorage에는 정말 필요한 정보만 집어넣어두는 걸로 할게욥!!

get() = pref.getString(MEETING_COUNT, "") ?: ""
set(value) = pref.edit { putString(MEETING_COUNT, value) }

override var participantCount: String
get() = pref.getString(PARTICIPANTS_COUNT, "") ?: ""
set(value) = pref.edit { putString(PARTICIPANTS_COUNT, value) }

override var groupKeyword: String
get() = pref.getString(GROUP_KEYWORD, "") ?: ""
set(value) = pref.edit { putString(GROUP_KEYWORD, value) }

override var isOwner: Boolean
get() = pref.getBoolean(IS_OWNER, false)
set(value) = pref.edit { putBoolean(IS_OWNER, value) }

override var code: String
get() = pref.getString(GROUP_CODE, "") ?: ""
set(value) = pref.edit { putString(GROUP_CODE, value) }

override fun clear() {
pref.edit {
clear()
Expand All @@ -69,5 +89,10 @@ class PingleLocalDataSourceImpl @Inject constructor(
const val REFRESH_TOKEN = "RefreshToken"
const val GROUP_ID = "GroupId"
const val GROUP_NAME = "GroupName"
const val MEETING_COUNT = "MeetingCount"
const val PARTICIPANTS_COUNT = "ParticipantsCount"
const val GROUP_KEYWORD = "GroupKeyWord"
const val IS_OWNER = "IsOwner"
const val GROUP_CODE = "GroupCode"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.sopt.pingle.data.model.remote.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.sopt.pingle.domain.model.MyGroupEntity

@Serializable
data class ResponseMyGroupDto(
@SerialName("id")
val id: Int,
@SerialName("keyword")
val keyword: String,
@SerialName("name")
val name: String,
@SerialName("meetingCount")
val meetingCount: Int,
@SerialName("participantCount")
val participantCount: Int,
@SerialName("isOwner")
val isOwner: Boolean,
@SerialName("code")
val code: String
) {
fun toResponseMyGroupEntity() = MyGroupEntity(
id = id,
keyword = keyword,
name = name,
meetingCount = meetingCount.toString(),
participantCount = participantCount.toString(),
isOwner = isOwner,
code = code
)
}
11 changes: 11 additions & 0 deletions app/src/main/java/org/sopt/pingle/domain/model/MyGroupEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sopt.pingle.domain.model

data class MyGroupEntity(
var id: Int,
val keyword: String,
val name: String,
val meetingCount: String,
val participantCount: String,
val isOwner: Boolean,
val code: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ class JoinViewModel @Inject constructor(
runCatching {
getJoinGroupInfoUseCase(teamId = teamId).collect { joinGroupInfo ->
_joinGroupInfoState.value = UiState.Success(joinGroupInfo)
with(localStorage) {
meetingCount = joinGroupInfo.meetingCount.toString()
participantCount = joinGroupInfo.participantCount.toString()
}
}
}.onFailure {
_joinGroupInfoState.value = UiState.Error(it.message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ class MoreFragment : BindingFragment<FragmentMoreBinding>(R.layout.fragment_more
collectData()
}

override fun onResume() {
super.onResume()
binding.tvMoreMyGroupContent.text = moreViewModel.getGroupName()
}

private fun initLayout() {
with(binding) {
tvMoreVersionDetail.text = BuildConfig.VERSION_NAME
Expand Down Expand Up @@ -69,55 +74,58 @@ class MoreFragment : BindingFragment<FragmentMoreBinding>(R.layout.fragment_more
}

private fun collectData() {
moreViewModel.logoutState.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { logoutState ->
when (logoutState) {
is UiState.Success -> {
moveToSign()
}

is UiState.Error -> {
Timber.d(FAILURE_LOGOUT)
}
moreViewModel.logoutState.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach { logoutState ->
when (logoutState) {
is UiState.Success -> {
moveToSign()
}

else -> {}
}
}.launchIn(viewLifecycleOwner.lifecycleScope)
is UiState.Error -> {
Timber.d(FAILURE_LOGOUT)
}

moreViewModel.withDrawState.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { withDrawState ->
when (withDrawState) {
is UiState.Success -> {
kakaoAuthService.withdrawKakao()
moveToSign()
else -> {}
}
}.launchIn(viewLifecycleOwner.lifecycleScope)

moreViewModel.withDrawState.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach { withDrawState ->
when (withDrawState) {
is UiState.Success -> {
kakaoAuthService.withdrawKakao()
moveToSign()
}

is UiState.Error -> {
when (withDrawState.message) {
FAILURE_OWNER -> {
PingleSnackbar.makeSnackbar(
requireView(),
stringOf(R.string.more_snackbar_failure),
SNACKBAR_BOTTOM_MARGIN,
SnackbarType.WARNING
)
is UiState.Error -> {
when (withDrawState.message) {
FAILURE_OWNER -> {
PingleSnackbar.makeSnackbar(
requireView(),
stringOf(R.string.more_snackbar_failure),
SNACKBAR_BOTTOM_MARGIN,
SnackbarType.WARNING
)
}

else -> Timber.d("$FAILURE_LOGOUT : ${withDrawState.message}")
}

else -> Timber.d("$FAILURE_LOGOUT : ${withDrawState.message}")
}

else -> {}
}
}.launchIn(viewLifecycleOwner.lifecycleScope)

else -> {}
}
}.launchIn(viewLifecycleOwner.lifecycleScope)
moreViewModel.userInfoState.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach { userInfoState ->
when (userInfoState) {
is UiState.Success -> {
binding.tvMoreNickname.text = userInfoState.data.name
}

moreViewModel.userInfoState.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { userInfoState ->
when (userInfoState) {
is UiState.Success -> {
binding.tvMoreNickname.text = userInfoState.data.name
else -> Unit
}

else -> Unit
}
}.launchIn(viewLifecycleOwner.lifecycleScope)
}.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun moveToSign() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,141 @@
package org.sopt.pingle.presentation.ui.mygroup

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.activity.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.sopt.pingle.R
import org.sopt.pingle.databinding.ActivityMyGroupBinding
import org.sopt.pingle.domain.model.MyGroupEntity
import org.sopt.pingle.presentation.type.SnackbarType
import org.sopt.pingle.presentation.ui.onboarding.OnBoardingActivity
import org.sopt.pingle.util.base.BindingActivity
import org.sopt.pingle.util.component.PingleSnackbar
import org.sopt.pingle.util.context.PINGLE_PLAY_STORE_LINK
import org.sopt.pingle.util.context.PINGLE_SHARE_CODE
import org.sopt.pingle.util.context.copyGroupCode
import org.sopt.pingle.util.context.sharePingle
import org.sopt.pingle.util.context.stringOf
import timber.log.Timber

@AndroidEntryPoint
class MyGroupActivity : BindingActivity<ActivityMyGroupBinding>(R.layout.activity_my_group) {

private val viewModel by viewModels<MyGroupViewModel>()
private lateinit var adapter: MyGroupAdapter

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

binding.myGroupviewModel = viewModel

initLayout()
addListeners()
collectData()
}

override fun onDestroy() {
binding.rvMyGroupSelected.adapter = null
super.onDestroy()
}

private fun initLayout() {
viewModel.getGroupList()
binding.toolbarMyGroup.text = stringOf(R.string.my_group_title)

runCatching {
adapter = MyGroupAdapter(this@MyGroupActivity::showChangeGroupModal)
binding.rvMyGroupSelected.adapter = adapter
adapter.submitList(viewModel.filteredGroupList.value)
}.onFailure { throwable -> Timber.e(throwable.message) }
}

private fun addListeners() {
with(binding) {
toolbarMyGroup.ivAllTopbarArrowWithTitleArrowLeft.setOnClickListener { finish() }
tvMyGroupMoveSelectedGroup.setOnClickListener { navigateToNewGroupInfo() }
ivMyGroupSelectedMenu.setOnClickListener { showMyGroupMenu() }
root.setOnClickListener { layoutMyGroupSelectedMenu.visibility = View.INVISIBLE }
layoutMyGroupSelectedMenuCopy.setOnClickListener { copyGroupCode() }
layoutMyGroupSelectedMenuShare.setOnClickListener { shareGroupCode() }
}
}

private fun collectData() {
viewModel.filteredGroupList.flowWithLifecycle(lifecycle).onEach { filteredList ->
adapter.submitList(filteredList)
}.launchIn(lifecycleScope)

viewModel.selectedMyGroup.flowWithLifecycle(lifecycle).onEach { selectedMyGroup ->
binding.ivMyGroupSelectedOwner.visibility = if (selectedMyGroup?.isOwner == true) View.VISIBLE else View.INVISIBLE
}.launchIn(lifecycleScope)
}

private fun showMyGroupMenu() {
with(binding) {
if (layoutMyGroupSelectedMenu.visibility == View.VISIBLE) {
layoutMyGroupSelectedMenu.visibility = View.INVISIBLE
} else {
layoutMyGroupSelectedMenu.visibility = View.VISIBLE
}
}
}

private fun showChangeGroupModal(clickedEntity: MyGroupEntity) {
binding.layoutMyGroupSelectedMenu.visibility = View.INVISIBLE
MyGroupModalDialogFragment(
title = getString(
R.string.my_group_modal_move_question,
clickedEntity.name
),
buttonText = stringOf(R.string.my_group_modal_change),
textButtonText = stringOf(R.string.my_group_modal_back),
clickBtn = { chageToNewGroup(clickedEntity) },
clickTextBtn = { }
).show(supportFragmentManager, CHANGE_MODAL)
}

private fun chageToNewGroup(clickedEntity: MyGroupEntity) {
viewModel.changeGroupList(clickedEntity)

PingleSnackbar.makeSnackbar(
view = binding.root,
message = stringOf(R.string.my_group_snack_bar_chage_group_complete),
bottomMarin = SNACKBAR_BOTTOM_MARGIN,
snackbarType = SnackbarType.GUIDE
)
}

private fun copyGroupCode() {
binding.layoutMyGroupSelectedMenu.visibility = View.INVISIBLE
copyGroupCode(viewModel.getGroupCode())
PingleSnackbar.makeSnackbar(
view = binding.root,
message = stringOf(R.string.my_group_snack_bar_code_copy_complete),
bottomMarin = SNACKBAR_BOTTOM_MARGIN,
snackbarType = SnackbarType.GUIDE
)
}

private fun shareGroupCode() {
// TODO 콘텐츠 내용 알려주면 ContextExt와 함께 수정
binding.layoutMyGroupSelectedMenu.visibility = View.INVISIBLE
this.sharePingle(getString(R.string.my_group_share_pingle, viewModel.getGroupName(), PINGLE_SHARE_CODE, viewModel.getGroupCode(), PINGLE_PLAY_STORE_LINK))
}

private fun navigateToNewGroupInfo() {
Intent(this, OnBoardingActivity::class.java).apply {
startActivity(this)
}
}

companion object {
private const val CHANGE_MODAL = "ChangeGroupModal"
private const val SNACKBAR_BOTTOM_MARGIN = 57
}
}
Loading
Loading