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 12 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.GroupListEntity

@Serializable
data class ResponseGroupListDto(
@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 toResponseGroupListEntity() = GroupListEntity(
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/GroupListEntity.kt
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sopt.pingle.domain.model

data class GroupListEntity(
val 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
@@ -1,12 +1,162 @@
package org.sopt.pingle.presentation.ui.mygroup

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import dagger.hilt.android.AndroidEntryPoint
import org.sopt.pingle.R
import org.sopt.pingle.databinding.ActivityMyGroupBinding
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.AllModalDialogFragment
import org.sopt.pingle.util.component.PingleSnackbar
import org.sopt.pingle.util.context.stringOf

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

private val viewModel by viewModels<MyGroupViewModel>()
private lateinit var onBackPressed: OnBackPressedCallback

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

initLayout()
addListeners()
onBackPressedBtn()
}

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

private fun initLayout() {
checkMyGroupOwner()

with(binding) {
toolbar.text = getString(R.string.my_group_title)
// TODO chip 머지되면 text에 localStorage에 저장된 keyword 가져오기
tvMyGroupNowName.text = viewModel.getGroupName()
tvMyGroupNowMeetingCount.text =
getString(R.string.my_group_meeting_count, viewModel.getGroupMeetingCount())
tvMyGroupNowMemberCount.text =
getString(R.string.my_group_member_count, viewModel.getGroupParticipantCount())

val adapter = MyGroupAdapter(::showChangeGroupModal)
rvMyGroupList.adapter = adapter
adapter.submitList(viewModel.dummyGroupList)
}
}

private fun addListeners() {
with(binding) {
toolbar.ivAllTopbarArrowWithTitleArrowLeft.setOnClickListener { finish() }
tvMyGroupMoveNewGroup.setOnClickListener { navigateToNewGroupInfo() }
ivMyGroupNowMenu.setOnClickListener { showMyGroupMenu() }
root.setOnClickListener { layoutMyGroupMenu.visibility = View.INVISIBLE }
layoutMyGroupMenuCopy.setOnClickListener { copyGroupCode() }
layoutMyGroupMenuShare.setOnClickListener { shareGroupCode() }
}
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved
}

private fun checkMyGroupOwner() {
with(binding) {
if (viewModel.getMyGroupIsOwner()) {
ivMyGroupNowOwner.visibility = View.VISIBLE
} else {
ivMyGroupNowOwner.visibility = View.INVISIBLE
}
Copy link
Member

Choose a reason for hiding this comment

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

코드가 한줄인경우 대괄호를 빼는게 예쁜거같아요!

Suggested change
if (viewModel.getMyGroupIsOwner()) {
ivMyGroupNowOwner.visibility = View.VISIBLE
} else {
ivMyGroupNowOwner.visibility = View.INVISIBLE
}
if (viewModel.getMyGroupIsOwner()) ivMyGroupNowOwner.visibility = View.VISIBLE
else ivMyGroupNowOwner.visibility = View.INVISIBLE

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

이게ㅜㅜ 저도 그렇게 쓰고싶은데 컨트롤 엘이었나 린트였나 돌리면 일케 바뀌더라구요.. if~else문에 braces 없으면 안 좋다 어쩌구 하면서•• 참나!!

Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 가독성 때문에 if, else 괄호 치는게 좋음 ㅋㅋ 개취인듯여 ~~

}
}

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

private fun showChangeGroupModal() {
// TODO viewModel에서 Entity의 특정 position에 해당하는 값 가져와서 현재 단체랑 위치 바꾸기
AllModalDialogFragment(
title = getString(R.string.my_group_modal_move_question, viewModel.getGroupName()),
detail = null,
buttonText = getString(R.string.my_group_modal_change),
jihyunniiii marked this conversation as resolved.
Show resolved Hide resolved
textButtonText = getString(R.string.my_group_modal_back),
clickBtn = { chageToNewGroup() },
clickTextBtn = { }
).show(supportFragmentManager, CHANGE_MODAL)
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 Author

Choose a reason for hiding this comment

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

넹 확인했서요 AllModalFragment 같은 칭구를 하나 더 만들어서 띄우려구요! 테스트용으로 썼습니둥

}

private fun chageToNewGroup() {
// TODO 서버통신으로 단체 get 해오고 현재 local에 저장된 것과 다른 경우만 리사이클러뷰 데이터로 업데이트

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() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip: ClipData = ClipData.newPlainText(GROUP_CODE_COPY, viewModel.getGroupCode())
clipboard.setPrimaryClip(clip)
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved

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() {
val intent = Intent(Intent.ACTION_SEND_MULTIPLE)
with(intent) {
type = SHARE_TYPE
// TODO 기획에서 전달해준 템플릿 적용
putExtra(
Intent.EXTRA_TEXT,
"핑글 앱을 다운받고, ${viewModel.getGroupName()} 사람들을 만나보세요!\n\n$PINGLE_SHARE_CODE ${viewModel.getGroupCode()} \n\n $PINGLE_PLAY_STORE_LINK"
)
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved
}
startActivity(Intent.createChooser(intent, null))
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved
}

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

private fun onBackPressedBtn() {
onBackPressed = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
finish()
}
}
onBackPressedDispatcher.addCallback(this, onBackPressed)
}
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved

companion object {
private const val CHANGE_MODAL = "ChangeGroupModal"
private const val SNACKBAR_BOTTOM_MARGIN = 57
private const val GROUP_CODE_COPY = "CopyGroupCode"
private const val PINGLE_PLAY_STORE_LINK =
"앱 링크 : https://play.google.com/store/apps/details?id=org.sopt.pingle&pcampaignid=web_share"
private const val PINGLE_SHARE_CODE = "초대코드 : "
private const val SHARE_TYPE = "text/plain"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.sopt.pingle.presentation.ui.mygroup

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.sopt.pingle.databinding.ItemMyGroupBinding
import org.sopt.pingle.databinding.ItemMyGroupOwnerBinding
import org.sopt.pingle.domain.model.GroupListEntity
import org.sopt.pingle.util.view.ItemDiffCallback

class MyGroupAdapter(
private val groupOnClick: () -> Unit
) : ListAdapter<GroupListEntity, RecyclerView.ViewHolder>(
ItemDiffCallback<GroupListEntity>(
onContentsTheSame = { old, new -> old == new },
onItemsTheSame = { old, new -> old.id == new.id }
)
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
1 -> MyGroupViewHolder(
ItemMyGroupBinding.inflate(LayoutInflater.from(parent.context), parent, false),
groupOnClick
)
2 -> MyGroupOwnerViewHolder(
ItemMyGroupOwnerBinding.inflate(LayoutInflater.from(parent.context), parent, false),
groupOnClick
)
else -> throw RuntimeException()
HAJIEUN02 marked this conversation as resolved.
Show resolved Hide resolved
}
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is MyGroupViewHolder -> holder.onBind(currentList[position])
is MyGroupOwnerViewHolder -> holder.onBind(currentList[position])
}
}

override fun getItemViewType(position: Int): Int {
return if (currentList[position].isOwner) {
2
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 Author

Choose a reason for hiding this comment

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

넹 반영해서 상수화 했숨다!!

} else {
1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.pingle.presentation.ui.mygroup

import androidx.recyclerview.widget.RecyclerView
import org.sopt.pingle.databinding.ItemMyGroupOwnerBinding
import org.sopt.pingle.domain.model.GroupListEntity

class MyGroupOwnerViewHolder(
private val binding: ItemMyGroupOwnerBinding,
private val groupOnClick: () -> Unit
) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(groupListEntity: GroupListEntity) {
with(binding) {
this.groupListEntity = groupListEntity
layoutMyGroupListOwner.setOnClickListener { groupOnClick() }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.pingle.presentation.ui.mygroup

import androidx.recyclerview.widget.RecyclerView
import org.sopt.pingle.databinding.ItemMyGroupBinding
import org.sopt.pingle.domain.model.GroupListEntity

class MyGroupViewHolder(
private val binding: ItemMyGroupBinding,
private val groupOnClick: () -> Unit
) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(groupListEntity: GroupListEntity) {
with(binding) {
this.groupListEntity = groupListEntity
layoutMyGroupListDefault.setOnClickListener { groupOnClick() }
}
}
}
Loading