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

[AN/USER] feat: 학교 상세 페이지 구현 (#697) #722

Merged
merged 24 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
64e8759
feat: 학교 상세 도메인 모델 추가
EmilyCh0 Feb 9, 2024
8469319
feat: SchoolRepository 정의
EmilyCh0 Feb 9, 2024
5ef793a
feat: 테스트용 FakeSchool 추가
EmilyCh0 Feb 9, 2024
2aa3b2b
feat: SchoolDefaultRepository 임시 구현 (Fake 데이터 리턴)
EmilyCh0 Feb 9, 2024
61d0ffe
feat: 학교 상세 dto 추가
EmilyCh0 Feb 10, 2024
b48c2bf
feat: SchoolDetailUiState 정의
EmilyCh0 Feb 10, 2024
6eb05c6
feat: SchoolDetailViewModel 구현
EmilyCh0 Feb 10, 2024
d6cd393
feat: SchoolDetailFragment 구현
EmilyCh0 Feb 12, 2024
bc6da8e
feat: UiState 분리
EmilyCh0 Feb 12, 2024
d1f1f2b
feat: FakeSchool 소셜미디어 데이터 추가
EmilyCh0 Feb 17, 2024
f74935f
feat: SchoolDetailFragment 뷰 수정
EmilyCh0 Feb 17, 2024
5e724f6
move: 패키지 위치 변경
EmilyCh0 Feb 17, 2024
3832327
feat: 상단 뒤로 가기 버튼
EmilyCh0 Feb 18, 2024
cc91707
feat: schoolId 추가
EmilyCh0 Feb 18, 2024
a025518
fix: dday view 수정
EmilyCh0 Feb 18, 2024
b555447
feat: 북마크
EmilyCh0 Feb 20, 2024
60357d6
Merge branch 'dev' into feat/#697
EmilyCh0 Feb 20, 2024
2a85266
fix: resolve conflict
EmilyCh0 Feb 20, 2024
702afb4
refactor: ktlint check
EmilyCh0 Feb 20, 2024
48848ad
refactor: ktlint check
EmilyCh0 Feb 20, 2024
7a30d1c
refactor: Fake 리포지토리명 변경
EmilyCh0 Feb 24, 2024
f1c5aec
refactor: id 카멜케이스로 수정
EmilyCh0 Feb 24, 2024
52824ad
refactor: FakeSchoolRepository 주석 삭제
EmilyCh0 Feb 24, 2024
6fe46ff
refactor: 중복된 소셜미디어 뷰 제거
EmilyCh0 Feb 25, 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 @@ -2,8 +2,10 @@ package com.festago.festago.data.di.singletonscope

import com.festago.festago.data.repository.FakeArtistRepository
import com.festago.festago.data.repository.FakeFestivalRepository
import com.festago.festago.data.repository.SchoolDefaultRepository
import com.festago.festago.domain.repository.ArtistRepository
import com.festago.festago.domain.repository.FestivalRepository
import com.festago.festago.domain.repository.SchoolRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -21,4 +23,8 @@ interface RepositoryModule {
@Binds
@Singleton
fun bindsArtistRepository(artistRepository: FakeArtistRepository): ArtistRepository

@Binds
@Singleton
fun bindsSchoolDefaultRepository(schoolRepository: SchoolDefaultRepository): SchoolRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.festago.festago.data.dto.school

import com.festago.festago.domain.model.school.SchoolInfo
import kotlinx.serialization.Serializable

@Serializable
data class SchoolInfoResponse(
val id: Int,
val schoolName: String,
val logoUrl: String,
val backgroundUrl: String,
Comment on lines +10 to +11
Copy link
Member

Choose a reason for hiding this comment

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

명세 이름이 변경되면 반영해주세요!

Copy link
Member Author

Choose a reason for hiding this comment

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

API 연동이랑 변경된 명세 반영은 따로 이슈 파서 작업하겠습니다!

val socialMediaResponse: List<SocialMediaResponse>,
) {
fun toDomain(): SchoolInfo = SchoolInfo(
id = id,
schoolName = schoolName,
logoUrl = logoUrl,
backgroundUrl = backgroundUrl,
socialMedia = socialMediaResponse.map { it.toDomain() },
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.festago.festago.data.dto.school

import com.festago.festago.domain.model.social.SocialMedia
import kotlinx.serialization.Serializable

@Serializable
data class SocialMediaResponse(
val type: String,
val name: String,
val logoUrl: String,
val url: String,
) {
fun toDomain(): SocialMedia = SocialMedia(
type = type,
name = name,
logoUrl = logoUrl,
url = url,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.festago.festago.data.repository

import com.festago.festago.domain.model.school.SchoolInfo
import com.festago.festago.domain.model.social.SocialMedia

object FakeSchool {
val googleSchool = SchoolInfo(
id = 1,
schoolName = "구글대학교",
logoUrl = "https://cdn1.iconfinder.com/data/icons/logos-brands-in-colors/544/Google__G__Logo-512.png",
backgroundUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/1200px-Google_2015_logo.svg.png",
socialMedia = listOf(
SocialMedia(
type = "INSTAGRAM",
name = "구글대학교 인스타",
logoUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Instagram_logo_2016.svg/2048px-Instagram_logo_2016.svg.png",
url = "https://www.instagram.com/",
),
SocialMedia(
type = "INSTAGRAM",
name = "구글대학교 X",
logoUrl = "https://about.x.com/content/dam/about-twitter/x/brand-toolkit/logo-black.png.twimg.1920.png",
url = "https://twitter.com/?lang=en",
)
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.festago.festago.data.repository

import com.festago.festago.domain.model.festival.FestivalsPage
import com.festago.festago.domain.model.school.SchoolInfo
import com.festago.festago.domain.repository.SchoolRepository
import javax.inject.Inject

class SchoolDefaultRepository @Inject constructor(
Copy link
Collaborator

Choose a reason for hiding this comment

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

현재 Festival과 Artist는 Fake객체를 반환하는 리포지터리 네이밍은 다음과 같이 구분되어있는데요!
두가지 방법이 있어서 어떤 방식으로 통일할지 생각해보면 좋을 것같습니다!
Fake**Repository

FakeFestivalRepository : FestivalRepository
FestivalDefaultRepository : FestivalRepository

Copy link
Member Author

Choose a reason for hiding this comment

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

Festival, Artist와 동일하게 FakeSchoolRepository로 변경했습니다. API 연동할 때 SchoolDefaultRepository 추가할게요.

Copy link
Member

Choose a reason for hiding this comment

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

Fake**Repository
Default**Repository

로 통일하는게 어떤가요?

FakeFestivalRepository : FestivalRepository
DefaultFestivalRepository : FestivalRepository

본래 Default 보다 인터페이스 네이밍이 더 잘보이게 하려고 앞에 배치한 것 같은데 권장이나 어순을 고려해서 수식어를 앞에 배치하는게 좋다고 생각합니다:)

// TODO: Service 연결
) : SchoolRepository {
override suspend fun loadSchoolInfo(schoolId: Long): Result<SchoolInfo> {
// TODO: API 연동
return Result.success(FakeSchool.googleSchool)
}

override suspend fun loadSchoolFestivals(schoolId: Long): Result<FestivalsPage> {
// TODO: API 연동
return Result.success(
FestivalsPage(
isLastPage = true,
festivals = FakeFestivals.progressFestivals,
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.festago.festago.domain.model.school

import com.festago.festago.domain.model.social.SocialMedia

data class SchoolInfo(
val id: Int,
val schoolName: String,
val logoUrl: String,
val backgroundUrl: String,
val socialMedia: List<SocialMedia>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.festago.festago.domain.model.social

data class SocialMedia(
val type: String,
val name: String,
val logoUrl: String,
val url: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.festago.festago.domain.repository

import com.festago.festago.domain.model.festival.FestivalsPage
import com.festago.festago.domain.model.school.SchoolInfo

interface SchoolRepository {
suspend fun loadSchoolInfo(schoolId: Long): Result<SchoolInfo>
suspend fun loadSchoolFestivals(schoolId: Long): Result<FestivalsPage>
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.festago.festago.presentation.ui.home.festivallist.festival.FestivalLi
import com.festago.festago.presentation.ui.home.festivallist.uistate.FestivalFilterUiState
import com.festago.festago.presentation.ui.home.festivallist.uistate.FestivalListUiState
import com.festago.festago.presentation.ui.home.festivallist.uistate.FestivalTabUiState
import com.festago.festago.presentation.ui.schooldetail.SchoolDetailFragment
import com.festago.festago.presentation.util.repeatOnStarted
import com.festago.festago.presentation.util.setOnApplyWindowInsetsCompatListener
import dagger.hilt.android.AndroidEntryPoint
Expand Down Expand Up @@ -76,6 +77,9 @@ class FestivalListFragment : Fragment() {
vm.loadFestivals()
binding.srlFestivalList.isRefreshing = false
}
binding.ivSearch.setOnClickListener { // 임시 연결
showSchoolDetail()
}
}

private fun initViewPager() {
Expand Down Expand Up @@ -141,6 +145,13 @@ class FestivalListFragment : Fragment() {
)
}

private fun showSchoolDetail() {
activity?.supportFragmentManager!!.beginTransaction()
.replace(R.id.fcvHomeContainer, SchoolDetailFragment.newInstance(0))
.addToBackStack(null)
.commit()
}

override fun onDestroyView() {
_binding = null
super.onDestroyView()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.festago.festago.presentation.ui.schooldetail

import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import com.festago.festago.presentation.ui.schooldetail.uistate.ArtistUiState

class ArtistAdapter : ListAdapter<ArtistUiState, ArtistViewHolder>(diffUtil) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtistViewHolder {
return ArtistViewHolder.of(parent)
}

override fun onBindViewHolder(holder: ArtistViewHolder, position: Int) {
holder.bind(getItem(position))
}

companion object {
private val diffUtil = object : DiffUtil.ItemCallback<ArtistUiState>() {
override fun areItemsTheSame(
oldItem: ArtistUiState,
newItem: ArtistUiState,
): Boolean {
return oldItem.id == newItem.id
}

override fun areContentsTheSame(
oldItem: ArtistUiState,
newItem: ArtistUiState,
): Boolean {
return oldItem == newItem
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.festago.festago.presentation.ui.schooldetail

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.festago.festago.presentation.databinding.ItemSchoolDetailArtistBinding
import com.festago.festago.presentation.ui.schooldetail.uistate.ArtistUiState

class ArtistViewHolder(
private val binding: ItemSchoolDetailArtistBinding,
) : RecyclerView.ViewHolder(binding.root) {

fun bind(item: ArtistUiState) {
binding.artist = item
}

companion object {
fun of(parent: ViewGroup): ArtistViewHolder {
val binding = ItemSchoolDetailArtistBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false,
)
return ArtistViewHolder(binding)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.festago.festago.presentation.ui.schooldetail

import android.content.res.Resources
import android.graphics.Rect
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import com.festago.festago.presentation.R
import com.festago.festago.presentation.databinding.ItemSchoolDetailFestivalBinding
import com.festago.festago.presentation.ui.schooldetail.uistate.FestivalItemUiState
import java.time.LocalDate

class SchoolDetailFestivalViewHolder(
private val binding: ItemSchoolDetailFestivalBinding
) : RecyclerView.ViewHolder(binding.root) {
private val artistAdapter = ArtistAdapter()

init {
binding.rvFestivalArtists.adapter = artistAdapter
binding.rvFestivalArtists.addItemDecoration(ArtistItemDecoration())
}

fun bind(item: FestivalItemUiState) {
binding.item = item
artistAdapter.submitList(item.artists)
bindDDayView(item)
}

private fun bindDDayView(item: FestivalItemUiState) {
val context = binding.root.context

val dDayView = binding.tvFestivalDDay
when {
LocalDate.now() > item.endDate -> Unit

LocalDate.now() >= item.startDate -> {
dDayView.text = context.getString(R.string.festival_list_tv_dday_in_progress)
dDayView.setTextColor(context.getColor(R.color.secondary_pink_01))
dDayView.background = AppCompatResources.getDrawable(
context,
R.drawable.bg_festival_list_dday_in_progress,
)
}

LocalDate.now() == item.startDate.minusDays(1) -> {
dDayView.setTextColor(context.getColor(R.color.background_gray_01))
dDayView.text = context.getString(
R.string.festival_list_tv_dday_format,
LocalDate.now().compareTo(item.startDate).toString(),
)
dDayView.setBackgroundColor(0xffff1273.toInt())
}

else -> binding.tvFestivalDDay.apply {
dDayView.setTextColor(context.getColor(R.color.background_gray_01))
dDayView.text = context.getString(
R.string.festival_list_tv_dday_format,
(LocalDate.now().toEpochDay() - item.startDate.toEpochDay()).toString(),
)
dDayView.setBackgroundColor(context.getColor(android.R.color.black))
}
}
}

private class ArtistItemDecoration : ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State,
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.right = 8.dpToPx
}

private val Int.dpToPx: Int
get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
Resources.getSystem().displayMetrics,
).toInt()
}

companion object {
fun of(parent: ViewGroup): SchoolDetailFestivalViewHolder {
val binding = ItemSchoolDetailFestivalBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false,
)
return SchoolDetailFestivalViewHolder(binding)
}
}
}
Loading
Loading