Skip to content

Commit

Permalink
[AN/USER] feat: 학교 상세 페이지 구현 (#697) (#722)
Browse files Browse the repository at this point in the history
* feat: 학교 상세 도메인 모델 추가

* feat: SchoolRepository 정의

* feat: 테스트용 FakeSchool 추가

* feat: SchoolDefaultRepository 임시 구현 (Fake 데이터 리턴)

* feat: 학교 상세 dto 추가

* feat: SchoolDetailUiState 정의

* feat: SchoolDetailViewModel 구현

* feat: SchoolDetailFragment 구현

* feat: UiState 분리

* feat: FakeSchool 소셜미디어 데이터 추가

* feat: SchoolDetailFragment 뷰 수정

* move: 패키지 위치 변경

* feat: 상단 뒤로 가기 버튼

* feat: schoolId 추가

* fix: dday view 수정

* feat: 북마크

* fix: resolve conflict

* refactor: ktlint check

* refactor: ktlint check

* refactor: Fake 리포지토리명 변경

* refactor: id 카멜케이스로 수정

* refactor: FakeSchoolRepository 주석 삭제

* refactor: 중복된 소셜미디어 뷰 제거
  • Loading branch information
EmilyCh0 authored Feb 26, 2024
1 parent 180ea3f commit e4fa895
Show file tree
Hide file tree
Showing 24 changed files with 908 additions and 0 deletions.
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.FakeSchoolRepository
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 bindsSchoolRepository(schoolRepository: FakeSchoolRepository): 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,
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,21 @@
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 FakeSchoolRepository @Inject constructor() : SchoolRepository {
override suspend fun loadSchoolInfo(schoolId: Long): Result<SchoolInfo> {
return Result.success(FakeSchool.googleSchool)
}

override suspend fun loadSchoolFestivals(schoolId: Long): Result<FestivalsPage> {
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

0 comments on commit e4fa895

Please sign in to comment.