diff --git a/android/festago/data/src/main/java/com/festago/festago/data/dto/festival/FestivalDetailResponse.kt b/android/festago/data/src/main/java/com/festago/festago/data/dto/festival/FestivalDetailResponse.kt new file mode 100644 index 000000000..9d8c55da7 --- /dev/null +++ b/android/festago/data/src/main/java/com/festago/festago/data/dto/festival/FestivalDetailResponse.kt @@ -0,0 +1,31 @@ +package com.festago.festago.data.dto.festival + +import com.festago.festago.data.dto.school.SchoolResponse +import com.festago.festago.data.dto.school.SocialMediaResponse +import com.festago.festago.data.dto.stage.StageResponse +import com.festago.festago.domain.model.festival.FestivalDetail +import kotlinx.serialization.Serializable +import java.time.LocalDate + +@Serializable +data class FestivalDetailResponse( + val id: Long, + val name: String, + val startDate: String, + val endDate: String, + val posterImageUrl: String, + val school: SchoolResponse, + val socialMedias: List, + val stages: List, +) { + fun toDomain() = FestivalDetail( + id, + name, + LocalDate.parse(startDate), + LocalDate.parse(endDate), + posterImageUrl, + school.toDomain(), + socialMedias.map { it.toDomain() }, + stages.map { it.toDomain() }, + ) +} diff --git a/android/festago/data/src/main/java/com/festago/festago/data/dto/stage/StageResponse.kt b/android/festago/data/src/main/java/com/festago/festago/data/dto/stage/StageResponse.kt new file mode 100644 index 000000000..f3fc230bb --- /dev/null +++ b/android/festago/data/src/main/java/com/festago/festago/data/dto/stage/StageResponse.kt @@ -0,0 +1,19 @@ +package com.festago.festago.data.dto.stage + +import com.festago.festago.data.dto.artist.ArtistResponse +import com.festago.festago.domain.model.stage.Stage +import kotlinx.serialization.Serializable +import java.time.LocalDateTime + +@Serializable +data class StageResponse( + val id: Long, + val startDateTime: String, + val artists: List, +) { + fun toDomain() = Stage( + id = id, + startDateTime = LocalDateTime.parse(startDateTime), + artists = artists.map { it.toDomain() }, + ) +} diff --git a/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeArtistRepository.kt b/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeArtistRepository.kt index bf551e3b6..aa6afef2f 100644 --- a/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeArtistRepository.kt +++ b/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeArtistRepository.kt @@ -3,8 +3,8 @@ package com.festago.festago.data.repository import com.festago.festago.domain.model.artist.Artist import com.festago.festago.domain.model.artist.ArtistDetail import com.festago.festago.domain.model.artist.ArtistMedia -import com.festago.festago.domain.model.artist.Stages import com.festago.festago.domain.model.festival.Festival +import com.festago.festago.domain.model.festival.FestivalsPage import com.festago.festago.domain.model.school.School import com.festago.festago.domain.repository.ArtistRepository import java.time.LocalDate @@ -37,11 +37,11 @@ class FakeArtistRepository @Inject constructor() : ArtistRepository { ), ) - override suspend fun loadArtistStages(id: Long, size: Int): Result = + override suspend fun loadArtistFestivals(id: Long, size: Int): Result = Result.success( - Stages( - false, - (0..10).flatMap { + FestivalsPage( + isLastPage = false, + festivals = (0..10).flatMap { listOf( Festival( 1, diff --git a/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivalRepository.kt b/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivalRepository.kt index f17408dd5..7c7655e1d 100644 --- a/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivalRepository.kt +++ b/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivalRepository.kt @@ -2,6 +2,7 @@ package com.festago.festago.data.repository import com.festago.festago.domain.model.artist.Artist import com.festago.festago.domain.model.festival.Festival +import com.festago.festago.domain.model.festival.FestivalDetail import com.festago.festago.domain.model.festival.FestivalFilter import com.festago.festago.domain.model.festival.FestivalsPage import com.festago.festago.domain.model.festival.PopularFestivals @@ -69,11 +70,35 @@ class FakeFestivalRepository @Inject constructor() : FestivalRepository { name = "뉴진스", imageUrl = "https://cdn.mediatoday.co.kr/news/photo/202311/313885_438531_4716.jpg", ), + Artist( + id = 1L, + name = "BTS", + imageUrl = "https://i.namu.wiki/i/gpgJvt_C2vKJS4VA4K_Vm57Y5WoS83ofshxhJlQaT4P9Tu0N96vZ2OcdeAN7ZtRAM26UyyQs3sualkKk6i_SrRMvwVKrU015XJqzJ7wKRbOub_oUAxPSFre_8D5De3oy-fCxL0uZ-HGvsWxIX57yrw.webp", + ), + Artist( + id = 2L, + name = "싸이", + imageUrl = "https://i.namu.wiki/i/VH58lI8f-y8QSoxFH9IAjjCobySN0lflZ4rMy6Un7qawUwAyi9UfeseZWCzxH-lQeZk7q_eUyTHGlZBAPqSLWliIKWYDLaAgomVtOyAQg60aCpF3oNTBOgUe_hig3rbHW-YAgoj95Fww3MCToyM6MA.webp", + ), + Artist( + id = 10L, + name = "마마무", + imageUrl = "https://i.namu.wiki/i/Mre8tXnE40mB9_UwXIwASMEAUSVhHvyjJxXq-lQo40C3bLWYfxXBeai8t6TugyomPjFgxL3VfDA2zn65HlzqPXgTKlvdRl1gJ6PGZLxYYk8Uhk8L6va7zm_etSK5UzVLE56fUATqUCq-6tRQXigmYQ.webp", + ), + Artist( + id = 11L, + name = "블랙핑크", + imageUrl = "https://i.namu.wiki/i/VZxRYO8_CXa2QbOSZgttDq5ue5QEu_Fbk1Lwo3qpasLAfS802YExcnmVmDhCq3ONF0ExzhACz_YkZbxOGmIfjuPDZnFo7i0pWaT05NluHRHGfp9NqsAT6WBNb0k5KecOyDvakXk0VH2fUo4ojSwC6g.webp", + ), ), ) } } + override suspend fun loadFestivalDetail(id: Long): Result { + return Result.success(FakeFestivals.festivalDetail) + } + companion object { private const val LAST_ITEM_ID = 27L private const val DEFAULT_SIZE = 10 diff --git a/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivals.kt b/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivals.kt index 53080dbed..382516c38 100644 --- a/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivals.kt +++ b/android/festago/data/src/main/java/com/festago/festago/data/repository/FakeFestivals.kt @@ -2,11 +2,155 @@ package com.festago.festago.data.repository import com.festago.festago.domain.model.artist.Artist import com.festago.festago.domain.model.festival.Festival +import com.festago.festago.domain.model.festival.FestivalDetail import com.festago.festago.domain.model.school.School +import com.festago.festago.domain.model.social.SocialMedia +import com.festago.festago.domain.model.stage.Stage import java.time.LocalDate +import java.time.LocalDateTime object FakeFestivals { + val festivalDetail = FestivalDetail( + id = 1L, + name = "부경대 대동제", + startDate = LocalDate.now().plusDays(7L), + endDate = LocalDate.now().plusDays(10L), + posterImageUrl = "https://mblogthumb-phinf.pstatic.net/MjAyMzA1MjNfMTMx/MDAxNjg0ODIwNzY5NzQ5.MuYItN1HCOQUcADB6B7ua0SO9Au_QNNk01-6yZkcTH0g.wxSjluY-Glq20JIojs7OuScLQWh6c_sQsoW5xXqiM7Ag.JPEG.chummilmil99/SE-126908ba-0f82-4903-91c5-695db78a98e9.jpg?type=w800", + school = School(id = 2L, name = "부경대학교", imageUrl = ""), + socialMedias = 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/25th_solution/", + ), + SocialMedia( + type = "FACEBOOK", + name = "총학생회 페이스북", + logoUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Facebook_f_logo_%282019%29.svg/1200px-Facebook_f_logo_%282019%29.svg.png", + url = "https://www.facebook.com/23rdemotion/", + ), + ), + stages = listOf( + Stage( + id = 1L, + startDateTime = LocalDateTime.now().plusDays(0L), + artists = listOf( + Artist( + id = 1L, + name = "BTS", + imageUrl = "https://i.namu.wiki/i/gpgJvt_C2vKJS4VA4K_Vm57Y5WoS83ofshxhJlQaT4P9Tu0N96vZ2OcdeAN7ZtRAM26UyyQs3sualkKk6i_SrRMvwVKrU015XJqzJ7wKRbOub_oUAxPSFre_8D5De3oy-fCxL0uZ-HGvsWxIX57yrw.webp", + ), + Artist( + id = 2L, + name = "싸이", + imageUrl = "https://i.namu.wiki/i/VH58lI8f-y8QSoxFH9IAjjCobySN0lflZ4rMy6Un7qawUwAyi9UfeseZWCzxH-lQeZk7q_eUyTHGlZBAPqSLWliIKWYDLaAgomVtOyAQg60aCpF3oNTBOgUe_hig3rbHW-YAgoj95Fww3MCToyM6MA.webp", + ), + Artist( + id = 10L, + name = "마마무", + imageUrl = "https://i.namu.wiki/i/Mre8tXnE40mB9_UwXIwASMEAUSVhHvyjJxXq-lQo40C3bLWYfxXBeai8t6TugyomPjFgxL3VfDA2zn65HlzqPXgTKlvdRl1gJ6PGZLxYYk8Uhk8L6va7zm_etSK5UzVLE56fUATqUCq-6tRQXigmYQ.webp", + ), + Artist( + id = 11L, + name = "블랙핑크", + imageUrl = "https://i.namu.wiki/i/VZxRYO8_CXa2QbOSZgttDq5ue5QEu_Fbk1Lwo3qpasLAfS802YExcnmVmDhCq3ONF0ExzhACz_YkZbxOGmIfjuPDZnFo7i0pWaT05NluHRHGfp9NqsAT6WBNb0k5KecOyDvakXk0VH2fUo4ojSwC6g.webp", + ), + Artist( + id = 4L, + name = "AKMU", + imageUrl = "https://i.namu.wiki/i/7yRF8Yrk9kdQxzETNO8TQp9jJpQENVUGbj-4YwB-xdVmJWoTAY7MgVA6G72Z-xmunPG0Zd3WTN_EsTwsx7oNFIO-yl0nHmaIU-ZRCpyhzVE5L9y8Sb9gkAKVt_jZBtgvVrOjw1UQq32gQsYaoS1jsg.webp", + ), + ), + ), + Stage( + id = 2L, + startDateTime = LocalDateTime.now().plusDays(1L), + artists = listOf( + Artist( + id = 3L, + name = "아이유", + imageUrl = "https://i.namu.wiki/i/-GuxB5nI9Q-a5W_nAJEapwdUzCLyFShWJfmUfZk04cW_fFC485TRD6UlzGQCBnFpJegXBaa4WO-PThNom_7wlosOiXgb-k3-wgUr3PkyX89PU3RCschmgQ0FmS1ClOK3ph4ztAd55YWWlhk7Gm114w.webp", + ), + Artist( + id = 5L, + name = "뉴진스", + imageUrl = "https://i.namu.wiki/i/GdMUzQlsrAXyF5zlgqRR0lYvAGnFghBbLxqTZK_mzLvV0LYPNQdaak1ezYtKqSNBA7UaINkrMNqncRkxThI8j2IEk2qcXJ3bLqIllRexenai641g-uvxCxFcDa9doCy0kTnMLEp5gad8Ze2fLDDBvg.webp", + ), + Artist( + id = 6L, + name = "비비", + imageUrl = "https://i.namu.wiki/i/JlXBTAah7fOILgmvAQf5bW4yWbS082qw6XtV36g4a-2g5TrwTRaUf95r1YnEYi6dt_rf3o9YuRN2qVl0pdgIW5d6-DeYg67KwaSrqu3_MkUwQItlsrSLqDjm1G0jW-Z5mzQ2aOTU4ZvyE1hpSokIOA.webp", + ), + ), + ), + Stage( + id = 3L, + startDateTime = LocalDateTime.now().plusDays(2L), + artists = listOf( + Artist( + id = 7L, + name = "TWS", + imageUrl = "https://i.namu.wiki/i/rVwKhMepUc-b-hRa2Nc6mIJRO0eTfgxyAEwVS5XfADNRhQhYJdSg8ke3o6VZd3rLyNasMlGjuXJWqHDoD_Z24o3dBzkaf7gqhCc89XoCKOiII4P-eilx46XHOOTfd2eaonCVNQevsAVl0l5WIWaI5Q.webp", + ), + Artist( + id = 8L, + name = "소녀시대", + imageUrl = "https://i.namu.wiki/i/snftu-N6Op26hU4HITlraWW6Q_WiSXqhRX2NOhQadzI81RPC7054_mi-evsqRTdRe9nKcBEF-Ugji4vtWunmtiEY1v319tHhIVestCkcSJ0MZF6KbKOScoDjOypW7WPa58goYA-vX5D8baIa2UYFZg.webp", + ), + Artist( + id = 9L, + name = "르세라핌", + imageUrl = "https://i.namu.wiki/i/Zbm1DseL0fjSd9H2uLrfL9SpBLPYQe7j4S9BPI2wdTw9G_Gykifyw-Nil8yVZglxxW-CRQt15b-tMdrvfuUiSW9mm2ZEBf8sQQQgp9wZmZhe8neg_5A6ehJ6hYLATAqvnOw157aODDq4qU1J-kv-bA.webp", + ), + ), + ), + Stage( + id = 4L, + startDateTime = LocalDateTime.now().plusDays(3L), + artists = listOf( + Artist( + id = 7L, + name = "TWS", + imageUrl = "https://i.namu.wiki/i/rVwKhMepUc-b-hRa2Nc6mIJRO0eTfgxyAEwVS5XfADNRhQhYJdSg8ke3o6VZd3rLyNasMlGjuXJWqHDoD_Z24o3dBzkaf7gqhCc89XoCKOiII4P-eilx46XHOOTfd2eaonCVNQevsAVl0l5WIWaI5Q.webp", + ), + Artist( + id = 8L, + name = "소녀시대", + imageUrl = "https://i.namu.wiki/i/snftu-N6Op26hU4HITlraWW6Q_WiSXqhRX2NOhQadzI81RPC7054_mi-evsqRTdRe9nKcBEF-Ugji4vtWunmtiEY1v319tHhIVestCkcSJ0MZF6KbKOScoDjOypW7WPa58goYA-vX5D8baIa2UYFZg.webp", + ), + Artist( + id = 9L, + name = "르세라핌", + imageUrl = "https://i.namu.wiki/i/Zbm1DseL0fjSd9H2uLrfL9SpBLPYQe7j4S9BPI2wdTw9G_Gykifyw-Nil8yVZglxxW-CRQt15b-tMdrvfuUiSW9mm2ZEBf8sQQQgp9wZmZhe8neg_5A6ehJ6hYLATAqvnOw157aODDq4qU1J-kv-bA.webp", + ), + ), + ), + Stage( + id = 5L, + startDateTime = LocalDateTime.now().plusDays(4L), + artists = listOf( + Artist( + id = 7L, + name = "TWS", + imageUrl = "https://i.namu.wiki/i/rVwKhMepUc-b-hRa2Nc6mIJRO0eTfgxyAEwVS5XfADNRhQhYJdSg8ke3o6VZd3rLyNasMlGjuXJWqHDoD_Z24o3dBzkaf7gqhCc89XoCKOiII4P-eilx46XHOOTfd2eaonCVNQevsAVl0l5WIWaI5Q.webp", + ), + Artist( + id = 8L, + name = "소녀시대", + imageUrl = "https://i.namu.wiki/i/snftu-N6Op26hU4HITlraWW6Q_WiSXqhRX2NOhQadzI81RPC7054_mi-evsqRTdRe9nKcBEF-Ugji4vtWunmtiEY1v319tHhIVestCkcSJ0MZF6KbKOScoDjOypW7WPa58goYA-vX5D8baIa2UYFZg.webp", + ), + Artist( + id = 9L, + name = "르세라핌", + imageUrl = "https://i.namu.wiki/i/Zbm1DseL0fjSd9H2uLrfL9SpBLPYQe7j4S9BPI2wdTw9G_Gykifyw-Nil8yVZglxxW-CRQt15b-tMdrvfuUiSW9mm2ZEBf8sQQQgp9wZmZhe8neg_5A6ehJ6hYLATAqvnOw157aODDq4qU1J-kv-bA.webp", + ), + ), + ), + ), + ) + val progressFestivals = listOf( Festival( id = 1, diff --git a/android/festago/data/src/main/java/com/festago/festago/data/repository/FestivalDefaultRepository.kt b/android/festago/data/src/main/java/com/festago/festago/data/repository/FestivalDefaultRepository.kt index 9f342dda7..8b8dee5c1 100644 --- a/android/festago/data/src/main/java/com/festago/festago/data/repository/FestivalDefaultRepository.kt +++ b/android/festago/data/src/main/java/com/festago/festago/data/repository/FestivalDefaultRepository.kt @@ -3,6 +3,7 @@ package com.festago.festago.data.repository import com.festago.festago.data.service.FestivalRetrofitService import com.festago.festago.data.util.onSuccessOrCatch import com.festago.festago.data.util.runCatchingResponse +import com.festago.festago.domain.model.festival.FestivalDetail import com.festago.festago.domain.model.festival.FestivalFilter import com.festago.festago.domain.model.festival.FestivalsPage import com.festago.festago.domain.model.festival.PopularFestivals @@ -38,4 +39,10 @@ class FestivalDefaultRepository @Inject constructor( ) }.onSuccessOrCatch { it.toDomain() } } + + override suspend fun loadFestivalDetail(id: Long): Result { + return runCatchingResponse { + festivalRetrofitService.getFestivalDetail(id) + }.onSuccessOrCatch { it.toDomain() } + } } diff --git a/android/festago/data/src/main/java/com/festago/festago/data/service/FestivalRetrofitService.kt b/android/festago/data/src/main/java/com/festago/festago/data/service/FestivalRetrofitService.kt index 3620f5754..52881d3d7 100644 --- a/android/festago/data/src/main/java/com/festago/festago/data/service/FestivalRetrofitService.kt +++ b/android/festago/data/src/main/java/com/festago/festago/data/service/FestivalRetrofitService.kt @@ -1,9 +1,11 @@ package com.festago.festago.data.service +import com.festago.festago.data.dto.festival.FestivalDetailResponse import com.festago.festago.data.dto.festival.FestivalsResponse import com.festago.festago.data.dto.festival.PopularFestivalsResponse import retrofit2.Response import retrofit2.http.GET +import retrofit2.http.Path import retrofit2.http.Query import java.time.LocalDate @@ -19,4 +21,9 @@ interface FestivalRetrofitService { @Query("lastStartDate") lastStartDate: LocalDate?, @Query("size") size: Int?, ): Response + + @GET("api/v1/festivals/{festivalId}") + suspend fun getFestivalDetail( + @Path("festivalId") festivalId: Long, + ): Response } diff --git a/android/festago/domain/src/main/java/com/festago/festago/domain/model/artist/Stages.kt b/android/festago/domain/src/main/java/com/festago/festago/domain/model/artist/Stages.kt deleted file mode 100644 index 3f62b37f6..000000000 --- a/android/festago/domain/src/main/java/com/festago/festago/domain/model/artist/Stages.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.festago.festago.domain.model.artist - -import com.festago.festago.domain.model.festival.Festival - -data class Stages( - val last: Boolean, - val stage: List, -) diff --git a/android/festago/domain/src/main/java/com/festago/festago/domain/model/festival/FestivalDetail.kt b/android/festago/domain/src/main/java/com/festago/festago/domain/model/festival/FestivalDetail.kt new file mode 100644 index 000000000..6036a8de3 --- /dev/null +++ b/android/festago/domain/src/main/java/com/festago/festago/domain/model/festival/FestivalDetail.kt @@ -0,0 +1,17 @@ +package com.festago.festago.domain.model.festival + +import com.festago.festago.domain.model.school.School +import com.festago.festago.domain.model.social.SocialMedia +import com.festago.festago.domain.model.stage.Stage +import java.time.LocalDate + +data class FestivalDetail( + val id: Long, + val name: String, + val startDate: LocalDate, + val endDate: LocalDate, + val posterImageUrl: String, + val school: School, + val socialMedias: List, + val stages: List, +) diff --git a/android/festago/domain/src/main/java/com/festago/festago/domain/model/stage/Stage.kt b/android/festago/domain/src/main/java/com/festago/festago/domain/model/stage/Stage.kt new file mode 100644 index 000000000..89ca13659 --- /dev/null +++ b/android/festago/domain/src/main/java/com/festago/festago/domain/model/stage/Stage.kt @@ -0,0 +1,10 @@ +package com.festago.festago.domain.model.stage + +import com.festago.festago.domain.model.artist.Artist +import java.time.LocalDateTime + +class Stage( + val id: Long, + val startDateTime: LocalDateTime, + val artists: List, +) diff --git a/android/festago/domain/src/main/java/com/festago/festago/domain/repository/ArtistRepository.kt b/android/festago/domain/src/main/java/com/festago/festago/domain/repository/ArtistRepository.kt index 63b84bbfb..a49d3f194 100644 --- a/android/festago/domain/src/main/java/com/festago/festago/domain/repository/ArtistRepository.kt +++ b/android/festago/domain/src/main/java/com/festago/festago/domain/repository/ArtistRepository.kt @@ -1,10 +1,10 @@ package com.festago.festago.domain.repository import com.festago.festago.domain.model.artist.ArtistDetail -import com.festago.festago.domain.model.artist.Stages +import com.festago.festago.domain.model.festival.FestivalsPage interface ArtistRepository { suspend fun loadArtistDetail(id: Long): Result - suspend fun loadArtistStages(id: Long, size: Int): Result + suspend fun loadArtistFestivals(id: Long, size: Int): Result } diff --git a/android/festago/domain/src/main/java/com/festago/festago/domain/repository/FestivalRepository.kt b/android/festago/domain/src/main/java/com/festago/festago/domain/repository/FestivalRepository.kt index 94e8d588d..ccd07c5cd 100644 --- a/android/festago/domain/src/main/java/com/festago/festago/domain/repository/FestivalRepository.kt +++ b/android/festago/domain/src/main/java/com/festago/festago/domain/repository/FestivalRepository.kt @@ -1,5 +1,6 @@ package com.festago.festago.domain.repository +import com.festago.festago.domain.model.festival.FestivalDetail import com.festago.festago.domain.model.festival.FestivalFilter import com.festago.festago.domain.model.festival.FestivalsPage import com.festago.festago.domain.model.festival.PopularFestivals @@ -15,4 +16,6 @@ interface FestivalRepository { lastStartDate: LocalDate? = null, size: Int? = null, ): Result + + suspend fun loadFestivalDetail(id: Long): Result } diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/ArtistDetailViewModel.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/ArtistDetailViewModel.kt index 187652630..cd36a317c 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/ArtistDetailViewModel.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/ArtistDetailViewModel.kt @@ -2,11 +2,11 @@ package com.festago.festago.presentation.ui.artistdetail import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.festago.festago.domain.model.artist.Stages +import com.festago.festago.domain.model.festival.FestivalsPage import com.festago.festago.domain.repository.ArtistRepository import com.festago.festago.presentation.ui.artistdetail.uistate.ArtistDetailUiState import com.festago.festago.presentation.ui.artistdetail.uistate.ArtistUiState -import com.festago.festago.presentation.ui.artistdetail.uistate.StageUiState +import com.festago.festago.presentation.ui.artistdetail.uistate.FestivalItemUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -27,7 +27,7 @@ class ArtistDetailViewModel @Inject constructor( runCatching { _uiState.value = ArtistDetailUiState.Success( artistRepository.loadArtistDetail(id).getOrThrow(), - artistRepository.loadArtistStages(id, 20).getOrThrow().toUiState(), + artistRepository.loadArtistFestivals(id, 20).getOrThrow().toUiState(), ) }.onFailure { _uiState.value = ArtistDetailUiState.Error @@ -35,8 +35,8 @@ class ArtistDetailViewModel @Inject constructor( } } - private fun Stages.toUiState() = this.stage.map { - StageUiState( + private fun FestivalsPage.toUiState() = festivals.map { + FestivalItemUiState( id = it.id, name = it.name, imageUrl = it.imageUrl, diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailAdapter.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailAdapter.kt index 41bd602a3..0eacaee6b 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailAdapter.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailAdapter.kt @@ -3,11 +3,11 @@ package com.festago.festago.presentation.ui.artistdetail.adapter.festival import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter -import com.festago.festago.presentation.ui.artistdetail.uistate.StageUiState +import com.festago.festago.presentation.ui.artistdetail.uistate.FestivalItemUiState class ArtistDetailAdapter( private val onArtistClick: (Long) -> Unit, -) : ListAdapter(diffUtil) { +) : ListAdapter(diffUtil) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtistDetailFestivalViewHolder { return ArtistDetailFestivalViewHolder.of(parent, onArtistClick) } @@ -18,12 +18,12 @@ class ArtistDetailAdapter( } companion object { - private val diffUtil = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: StageUiState, newItem: StageUiState): Boolean { + private val diffUtil = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: FestivalItemUiState, newItem: FestivalItemUiState): Boolean { return oldItem.id == newItem.id } - override fun areContentsTheSame(oldItem: StageUiState, newItem: StageUiState): Boolean { + override fun areContentsTheSame(oldItem: FestivalItemUiState, newItem: FestivalItemUiState): Boolean { return oldItem == newItem } } diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailFestivalViewHolder.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailFestivalViewHolder.kt index 8cf2c0e5b..c5b7095b3 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailFestivalViewHolder.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/adapter/festival/ArtistDetailFestivalViewHolder.kt @@ -12,7 +12,7 @@ import androidx.recyclerview.widget.RecyclerView.ItemDecoration import com.festago.festago.presentation.R import com.festago.festago.presentation.databinding.ItemArtistDetailFestivalBinding import com.festago.festago.presentation.ui.artistdetail.adapter.artistlist.ArtistAdapter -import com.festago.festago.presentation.ui.artistdetail.uistate.StageUiState +import com.festago.festago.presentation.ui.artistdetail.uistate.FestivalItemUiState import java.time.LocalDate class ArtistDetailFestivalViewHolder( @@ -26,13 +26,13 @@ class ArtistDetailFestivalViewHolder( binding.rvFestivalArtists.addItemDecoration(ArtistItemDecoration()) } - fun bind(item: StageUiState) { + fun bind(item: FestivalItemUiState) { binding.item = item artistAdapter.submitList(item.artists) bindDDayView(item) } - private fun bindDDayView(item: StageUiState) { + private fun bindDDayView(item: FestivalItemUiState) { val context = binding.root.context val dDayView = binding.tvFestivalDDay diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/ArtistDetailUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/ArtistDetailUiState.kt index d4f5a6f65..de1abed14 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/ArtistDetailUiState.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/ArtistDetailUiState.kt @@ -9,6 +9,6 @@ sealed interface ArtistDetailUiState { data class Success( val artist: ArtistDetail, - val stages: List, + val stages: List, ) : ArtistDetailUiState } diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/StageUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/FestivalItemUiState.kt similarity index 88% rename from android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/StageUiState.kt rename to android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/FestivalItemUiState.kt index c8407eda0..779dd6d04 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/StageUiState.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/artistdetail/uistate/FestivalItemUiState.kt @@ -2,7 +2,7 @@ package com.festago.festago.presentation.ui.artistdetail.uistate import java.time.LocalDate -data class StageUiState( +data class FestivalItemUiState( val id: Long, val name: String, val startDate: LocalDate, diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailEvent.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailEvent.kt new file mode 100644 index 000000000..e27d31f27 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailEvent.kt @@ -0,0 +1,5 @@ +package com.festago.festago.presentation.ui.festivaldetail + +sealed interface FestivalDetailEvent { + class ShowArtistDetail(val artistId: Long) : FestivalDetailEvent +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailFragment.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailFragment.kt new file mode 100644 index 000000000..727df7aa7 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailFragment.kt @@ -0,0 +1,170 @@ +package com.festago.festago.presentation.ui.festivaldetail + +import android.content.Intent +import android.graphics.Color +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.appcompat.content.res.AppCompatResources +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentTransaction +import androidx.fragment.app.commit +import androidx.fragment.app.viewModels +import com.festago.festago.presentation.R +import com.festago.festago.presentation.databinding.FragmentFestivalDetailBinding +import com.festago.festago.presentation.databinding.ItemMediaBinding +import com.festago.festago.presentation.ui.artistdetail.ArtistDetailFragment +import com.festago.festago.presentation.ui.festivaldetail.adapter.stage.StageListAdapter +import com.festago.festago.presentation.ui.festivaldetail.uiState.FestivalDetailUiState +import com.festago.festago.presentation.util.repeatOnStarted +import dagger.hilt.android.AndroidEntryPoint +import java.time.LocalDate + +@AndroidEntryPoint +class FestivalDetailFragment : Fragment() { + + private var _binding: FragmentFestivalDetailBinding? = null + private val binding get() = _binding!! + + private val vm: FestivalDetailViewModel by viewModels() + + private lateinit var adapter: StageListAdapter + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + _binding = FragmentFestivalDetailBinding.inflate(inflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initView() + initObserve() + } + + private fun initView() { + val id = requireArguments().getLong(FESTIVAL_ID) + adapter = StageListAdapter() + binding.rvStageList.adapter = adapter + vm.loadFestivalDetail(id) + binding.ivBack.setOnClickListener { + requireActivity().onBackPressedDispatcher.onBackPressed() + } + binding.cvBookmark.setOnClickListener { + binding.ivBookmark.isSelected = !binding.ivBookmark.isSelected + } + } + + private fun initObserve() { + repeatOnStarted(viewLifecycleOwner) { + vm.uiState.collect { + binding.uiState = it + updateUi(it) + } + } + repeatOnStarted(viewLifecycleOwner) { + vm.event.collect { + handleEvent(it) + } + } + } + + private fun updateUi(uiState: FestivalDetailUiState) { + when (uiState) { + is FestivalDetailUiState.Loading, + is FestivalDetailUiState.Error, + -> Unit + + is FestivalDetailUiState.Success -> handleSuccess(uiState) + } + } + + private fun handleSuccess(uiState: FestivalDetailUiState.Success) { + binding.successUiState = uiState + binding.tvFestivalDDay.setFestivalDDay(uiState.festival.startDate, uiState.festival.endDate) + binding.ivFestivalBackground.setColorFilter(Color.parseColor("#66000000")) + adapter.submitList(uiState.stages) + binding.llcFestivalSocialMedia.removeAllViews() + uiState.festival.socialMedias.forEach { media -> + with(ItemMediaBinding.inflate(layoutInflater, binding.llcFestivalSocialMedia, false)) { + imageUrl = media.logoUrl + ivImage.setOnClickListener { startBrowser(media.url) } + binding.llcFestivalSocialMedia.addView(ivImage) + } + } + } + + private fun TextView.setFestivalDDay(startDate: LocalDate, endDate: LocalDate) { + when { + LocalDate.now() in startDate..endDate -> { + text = context.getString(R.string.festival_detail_tv_dday_in_progress) + setTextColor(context.getColor(R.color.secondary_pink_01)) + background = AppCompatResources.getDrawable( + context, + R.drawable.bg_festival_list_dday_in_progress, + ) + } + + LocalDate.now() < startDate -> { + val dDay = LocalDate.now().toEpochDay() - startDate.toEpochDay() + val backgroundColor = if (dDay >= -7L) { + context.getColor(R.color.secondary_pink_01) + } else { + context.getColor(R.color.contents_gray_07) + } + setBackgroundColor(backgroundColor) + setTextColor(context.getColor(R.color.background_gray_01)) + text = context.getString(R.string.festival_detail_tv_dday_format, dDay.toString()) + } + + else -> { + setBackgroundColor(Color.TRANSPARENT) + setTextColor(context.getColor(R.color.background_gray_01)) + background = AppCompatResources.getDrawable( + context, + R.drawable.bg_festival_detail_dday_end, + ) + text = context.getString(R.string.festival_detail_tv_dday_end) + } + } + } + + private fun startBrowser(url: String) { + val intent = Intent(Intent.ACTION_VIEW) + intent.data = Uri.parse(url) + startActivity(intent) + } + + private fun handleEvent(event: FestivalDetailEvent) { + when (event) { + is FestivalDetailEvent.ShowArtistDetail -> { + requireActivity().supportFragmentManager.commit { + add(R.id.fcvHomeContainer, ArtistDetailFragment.newInstance(event.artistId)) + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN) + addToBackStack(null) + } + } + } + } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } + + companion object { + private const val FESTIVAL_ID = "FESTIVAL_ID" + + fun newInstance(id: Long) = FestivalDetailFragment().apply { + arguments = Bundle().apply { + putLong(FESTIVAL_ID, id) + } + } + } +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailViewModel.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailViewModel.kt new file mode 100644 index 000000000..85ee869e0 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/FestivalDetailViewModel.kt @@ -0,0 +1,87 @@ +package com.festago.festago.presentation.ui.festivaldetail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.festago.festago.common.analytics.AnalyticsHelper +import com.festago.festago.common.analytics.logNetworkFailure +import com.festago.festago.domain.model.artist.Artist +import com.festago.festago.domain.model.festival.FestivalDetail +import com.festago.festago.domain.model.stage.Stage +import com.festago.festago.domain.repository.FestivalRepository +import com.festago.festago.presentation.ui.festivaldetail.uiState.ArtistItemUiState +import com.festago.festago.presentation.ui.festivaldetail.uiState.FestivalDetailUiState +import com.festago.festago.presentation.ui.festivaldetail.uiState.FestivalUiState +import com.festago.festago.presentation.ui.festivaldetail.uiState.StageItemUiState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class FestivalDetailViewModel @Inject constructor( + private val festivalRepository: FestivalRepository, + private val analyticsHelper: AnalyticsHelper, +) : ViewModel() { + + private val _uiState = MutableStateFlow(FestivalDetailUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _event = MutableSharedFlow() + val event: SharedFlow = _event.asSharedFlow() + + fun loadFestivalDetail(festivalId: Long) { + viewModelScope.launch { + festivalRepository.loadFestivalDetail(festivalId).onSuccess { festivalDetail -> + _uiState.value = festivalDetail.toSuccessUiState() + }.onFailure { + _uiState.value = FestivalDetailUiState.Error + analyticsHelper.logNetworkFailure( + key = KEY_LOAD_FESTIVAL_DETAIL, + value = it.message.toString(), + ) + } + } + } + + private fun FestivalDetail.toSuccessUiState() = + FestivalDetailUiState.Success( + FestivalUiState( + id = id, + name = name, + startDate = startDate, + endDate = endDate, + posterImageUrl = posterImageUrl, + school = school, + socialMedias = socialMedias, + ), + stages = stages.map { it.toUiState() }, + ) + + private fun Stage.toUiState() = StageItemUiState( + id = id, + startDateTime = startDateTime, + artists = artists.map { it.toUiState() }, + ) + + private fun Artist.toUiState() = ArtistItemUiState( + id = id, + name = name, + imageUrl = imageUrl, + onArtistDetail = ::showArtistDetail, + ) + + private fun showArtistDetail(artistId: Long) { + viewModelScope.launch { + _event.emit(FestivalDetailEvent.ShowArtistDetail(artistId)) + } + } + + companion object { + private const val KEY_LOAD_FESTIVAL_DETAIL = "KEY_LOAD_FESTIVAL_DETAIL" + } +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/artist/ArtistAdapter.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/artist/ArtistAdapter.kt new file mode 100644 index 000000000..aa465f746 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/artist/ArtistAdapter.kt @@ -0,0 +1,35 @@ +package com.festago.festago.presentation.ui.festivaldetail.adapter.artist + +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import com.festago.festago.presentation.ui.festivaldetail.uiState.ArtistItemUiState + +class ArtistAdapter : ListAdapter(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() { + override fun areItemsTheSame( + oldItem: ArtistItemUiState, + newItem: ArtistItemUiState, + ): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame( + oldItem: ArtistItemUiState, + newItem: ArtistItemUiState, + ): Boolean { + return oldItem == newItem + } + } + } +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/artist/ArtistViewHolder.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/artist/ArtistViewHolder.kt new file mode 100644 index 000000000..b023f23e7 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/artist/ArtistViewHolder.kt @@ -0,0 +1,27 @@ +package com.festago.festago.presentation.ui.festivaldetail.adapter.artist + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.festago.festago.presentation.databinding.ItemFestivalDetailStageArtistBinding +import com.festago.festago.presentation.ui.festivaldetail.uiState.ArtistItemUiState + +class ArtistViewHolder( + private val binding: ItemFestivalDetailStageArtistBinding, +) : RecyclerView.ViewHolder(binding.root) { + + fun bind(item: ArtistItemUiState) { + binding.item = item + } + + companion object { + fun of(parent: ViewGroup): ArtistViewHolder { + val binding = ItemFestivalDetailStageArtistBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false, + ) + return ArtistViewHolder(binding) + } + } +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/stage/StageListAdapter.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/stage/StageListAdapter.kt new file mode 100644 index 000000000..99491ada9 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/stage/StageListAdapter.kt @@ -0,0 +1,35 @@ +package com.festago.festago.presentation.ui.festivaldetail.adapter.stage + +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import com.festago.festago.presentation.ui.festivaldetail.uiState.StageItemUiState + +class StageListAdapter : ListAdapter(diffUtil) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StageViewHolder { + return StageViewHolder.of(parent) + } + + override fun onBindViewHolder(holder: StageViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + companion object { + val diffUtil = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: StageItemUiState, + newItem: StageItemUiState, + ): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame( + oldItem: StageItemUiState, + newItem: StageItemUiState, + ): Boolean { + return oldItem == newItem + } + } + } +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/stage/StageViewHolder.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/stage/StageViewHolder.kt new file mode 100644 index 000000000..f64b5a254 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/adapter/stage/StageViewHolder.kt @@ -0,0 +1,35 @@ +package com.festago.festago.presentation.ui.festivaldetail.adapter.stage + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.festago.festago.presentation.databinding.ItemFestivalDetailStageBinding +import com.festago.festago.presentation.ui.festivaldetail.adapter.artist.ArtistAdapter +import com.festago.festago.presentation.ui.festivaldetail.uiState.StageItemUiState + +class StageViewHolder( + private val binding: ItemFestivalDetailStageBinding, +) : RecyclerView.ViewHolder(binding.root) { + + private val artistAdapter = ArtistAdapter() + + init { + binding.rvStageArtists.adapter = artistAdapter + } + + fun bind(item: StageItemUiState) { + binding.item = item + artistAdapter.submitList(item.artists) + } + + companion object { + fun of(parent: ViewGroup): StageViewHolder { + val binding = ItemFestivalDetailStageBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false, + ) + return StageViewHolder(binding) + } + } +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/ArtistItemUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/ArtistItemUiState.kt new file mode 100644 index 000000000..80f9c1698 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/ArtistItemUiState.kt @@ -0,0 +1,8 @@ +package com.festago.festago.presentation.ui.festivaldetail.uiState + +data class ArtistItemUiState( + val id: Long, + val name: String, + val imageUrl: String, + val onArtistDetail: (artistId: Long) -> Unit, +) diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/FestivalDetailUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/FestivalDetailUiState.kt new file mode 100644 index 000000000..d91ea42cc --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/FestivalDetailUiState.kt @@ -0,0 +1,16 @@ +package com.festago.festago.presentation.ui.festivaldetail.uiState + +interface FestivalDetailUiState { + object Loading : FestivalDetailUiState + + data class Success( + val festival: FestivalUiState, + val stages: List, + ) : FestivalDetailUiState + + object Error : FestivalDetailUiState + + val shouldShowSuccess get() = this is Success + val shouldShowLoading get() = this is Loading + val shouldShowError get() = this is Error +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/FestivalUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/FestivalUiState.kt new file mode 100644 index 000000000..9cf4ac3ff --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/FestivalUiState.kt @@ -0,0 +1,15 @@ +package com.festago.festago.presentation.ui.festivaldetail.uiState + +import com.festago.festago.domain.model.school.School +import com.festago.festago.domain.model.social.SocialMedia +import java.time.LocalDate + +data class FestivalUiState( + val id: Long, + val name: String, + val startDate: LocalDate, + val endDate: LocalDate, + val posterImageUrl: String, + val school: School, + val socialMedias: List, +) diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/StageItemUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/StageItemUiState.kt new file mode 100644 index 000000000..e5ea66194 --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/festivaldetail/uiState/StageItemUiState.kt @@ -0,0 +1,9 @@ +package com.festago.festago.presentation.ui.festivaldetail.uiState + +import java.time.LocalDateTime + +data class StageItemUiState( + val id: Long, + val startDateTime: LocalDateTime, + val artists: List, +) diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/HomeActivity.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/HomeActivity.kt index c15ae38d5..1c1a26a45 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/HomeActivity.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/HomeActivity.kt @@ -14,10 +14,12 @@ import androidx.fragment.app.Fragment import com.festago.festago.presentation.R import com.festago.festago.presentation.databinding.ActivityHomeBinding import com.festago.festago.presentation.ui.artistdetail.ArtistDetailFragment +import com.festago.festago.presentation.ui.festivaldetail.FestivalDetailFragment import com.festago.festago.presentation.ui.home.bookmarklist.BookmarkListFragment import com.festago.festago.presentation.ui.home.festivallist.FestivalListFragment import com.festago.festago.presentation.ui.home.mypage.MyPageFragment import com.festago.festago.presentation.ui.home.ticketlist.TicketListFragment +import com.festago.festago.presentation.ui.schooldetail.SchoolDetailFragment import com.festago.festago.presentation.util.setOnApplyWindowInsetsCompatListener import com.festago.festago.presentation.util.setStatusBarMode import dagger.hilt.android.AndroidEntryPoint @@ -63,12 +65,15 @@ class HomeActivity : AppCompatActivity() { private fun initBackStackListener() { supportFragmentManager.addOnBackStackChangedListener { - val fragment = supportFragmentManager.findFragmentById(R.id.fcvHomeContainer) - if (fragment is ArtistDetailFragment) { - setStatusBarMode(isLight = false, backgroundColor = Color.TRANSPARENT) - } else { - setStatusBarMode(isLight = true, backgroundColor = Color.TRANSPARENT) + val isLight = when (supportFragmentManager.findFragmentById(R.id.fcvHomeContainer)) { + is ArtistDetailFragment, + is FestivalDetailFragment, + is SchoolDetailFragment, + -> false + + else -> true } + setStatusBarMode(isLight = isLight, backgroundColor = Color.TRANSPARENT) } } @@ -109,7 +114,8 @@ class HomeActivity : AppCompatActivity() { var targetFragment = supportFragmentManager.findFragmentByTag(tag) if (targetFragment == null) { - targetFragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, tag) + targetFragment = + supportFragmentManager.fragmentFactory.instantiate(classLoader, tag) fragmentTransaction.add(R.id.fcvHomeContainer, targetFragment, tag) } else { fragmentTransaction.show(targetFragment) diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListEvent.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListEvent.kt new file mode 100644 index 000000000..7d91ef5bc --- /dev/null +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListEvent.kt @@ -0,0 +1,5 @@ +package com.festago.festago.presentation.ui.home.festivallist + +sealed interface FestivalListEvent { + class ShowFestivalDetail(val festivalId: Long) : FestivalListEvent +} diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt index 89105b822..980de27cc 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt @@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView import com.festago.festago.presentation.R import com.festago.festago.presentation.databinding.FragmentFestivalListBinding import com.festago.festago.presentation.ui.artistdetail.ArtistDetailFragment +import com.festago.festago.presentation.ui.festivaldetail.FestivalDetailFragment import com.festago.festago.presentation.ui.home.festivallist.festival.FestivalListAdapter import com.festago.festago.presentation.ui.home.festivallist.uistate.FestivalListUiState import com.festago.festago.presentation.ui.home.festivallist.uistate.FestivalMoreItemUiState @@ -65,6 +66,11 @@ class FestivalListFragment : Fragment() { updateUi(it) } } + repeatOnStarted(viewLifecycleOwner) { + vm.event.collect { + handleEvent(it) + } + } } private fun initView() { @@ -159,6 +165,18 @@ class FestivalListFragment : Fragment() { } } + private fun handleEvent(event: FestivalListEvent) { + when (event) { + is FestivalListEvent.ShowFestivalDetail -> { + requireActivity().supportFragmentManager.commit { + add(R.id.fcvHomeContainer, FestivalDetailFragment.newInstance(event.festivalId)) + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN) + addToBackStack(null) + } + } + } + } + private fun handleSuccess(uiState: FestivalListUiState.Success) { val items = uiState.getItems() festivalListAdapter.submitList(items) @@ -177,7 +195,7 @@ class FestivalListFragment : Fragment() { private fun showSchoolDetail() { activity?.supportFragmentManager!!.beginTransaction() - .replace(R.id.fcvHomeContainer, SchoolDetailFragment.newInstance(0)) + .add(R.id.fcvHomeContainer, SchoolDetailFragment.newInstance(0)) .addToBackStack(null) .commit() } diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt index 77e194129..aecc9cf8f 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt @@ -15,8 +15,11 @@ import com.festago.festago.presentation.ui.home.festivallist.uistate.PopularFest import com.festago.festago.presentation.ui.home.festivallist.uistate.SchoolUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -30,6 +33,9 @@ class FestivalListViewModel @Inject constructor( private val _uiState = MutableStateFlow(FestivalListUiState.Loading) val uiState: StateFlow = _uiState.asStateFlow() + private val _event = MutableSharedFlow() + val event: SharedFlow = _event.asSharedFlow() + private var festivalFilter: FestivalFilter = FestivalFilter.PROGRESS fun initFestivalList() { @@ -119,8 +125,15 @@ class FestivalListViewModel @Inject constructor( artists = artists.map { artist -> ArtistUiState(artist.id, artist.name, artist.imageUrl) }, + ::showFestivalDetail, ) + private fun showFestivalDetail(festivalId: Long) { + viewModelScope.launch { + _event.emit(FestivalListEvent.ShowFestivalDetail(festivalId)) + } + } + companion object { private const val KEY_LOAD_FESTIVAL = "KEY_LOAD_FESTIVAL" } diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/uistate/FestivalItemUiState.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/uistate/FestivalItemUiState.kt index f7f7d29c0..ba83253a2 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/uistate/FestivalItemUiState.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/home/festivallist/uistate/FestivalItemUiState.kt @@ -10,4 +10,5 @@ data class FestivalItemUiState( val imageUrl: String, val schoolUiState: SchoolUiState, val artists: List, + val onFestivalDetail: (festivalId: Long) -> Unit, ) diff --git a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/schooldetail/SchoolDetailFragment.kt b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/schooldetail/SchoolDetailFragment.kt index b02bec137..334b536a4 100644 --- a/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/schooldetail/SchoolDetailFragment.kt +++ b/android/festago/presentation/src/main/java/com/festago/festago/presentation/ui/schooldetail/SchoolDetailFragment.kt @@ -28,7 +28,7 @@ class SchoolDetailFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { _binding = FragmentSchoolDetailBinding.inflate(inflater) return binding.root diff --git a/android/festago/presentation/src/main/res/drawable/bg_festival_detail_dday_end.xml b/android/festago/presentation/src/main/res/drawable/bg_festival_detail_dday_end.xml new file mode 100644 index 000000000..b022949e6 --- /dev/null +++ b/android/festago/presentation/src/main/res/drawable/bg_festival_detail_dday_end.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/festago/presentation/src/main/res/layout/fragment_artist_detail.xml b/android/festago/presentation/src/main/res/layout/fragment_artist_detail.xml index 66ae64aa0..d2fe488db 100644 --- a/android/festago/presentation/src/main/res/layout/fragment_artist_detail.xml +++ b/android/festago/presentation/src/main/res/layout/fragment_artist_detail.xml @@ -15,6 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background_gray_01" + android:clickable="true" android:orientation="vertical" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.0"> @@ -72,9 +73,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" + android:contentDescription="@null" android:scaleType="centerCrop" - android:src="@drawable/ic_launcher_foreground" - android:contentDescription="@null" /> + android:src="@drawable/ic_launcher_foreground" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/festago/presentation/src/main/res/layout/fragment_festival_list.xml b/android/festago/presentation/src/main/res/layout/fragment_festival_list.xml index 70e55fb23..4b870fed2 100644 --- a/android/festago/presentation/src/main/res/layout/fragment_festival_list.xml +++ b/android/festago/presentation/src/main/res/layout/fragment_festival_list.xml @@ -13,6 +13,7 @@ + type="com.festago.festago.presentation.ui.artistdetail.uistate.FestivalItemUiState" /> @@ -70,14 +70,17 @@ + tools:text="중앙대학교 청진난만 중앙대학교 천진난만" /> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/festago/presentation/src/main/res/layout/item_festival_detail_stage_artist.xml b/android/festago/presentation/src/main/res/layout/item_festival_detail_stage_artist.xml new file mode 100644 index 000000000..6b563b798 --- /dev/null +++ b/android/festago/presentation/src/main/res/layout/item_festival_detail_stage_artist.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/festago/presentation/src/main/res/layout/item_festival_list_festival.xml b/android/festago/presentation/src/main/res/layout/item_festival_list_festival.xml index fa4c71415..26b167aa5 100644 --- a/android/festago/presentation/src/main/res/layout/item_festival_list_festival.xml +++ b/android/festago/presentation/src/main/res/layout/item_festival_list_festival.xml @@ -17,13 +17,12 @@ + android:background="@drawable/bg_festival_list_festival"> @@ -70,14 +69,17 @@ + tools:text="중앙대학교 청진난만 중앙대학교 천진난만" /> - \ No newline at end of file + diff --git a/android/festago/presentation/src/main/res/layout/item_popular_festival_foreground.xml b/android/festago/presentation/src/main/res/layout/item_popular_festival_foreground.xml index 7b5bc2475..f68d11c25 100644 --- a/android/festago/presentation/src/main/res/layout/item_popular_festival_foreground.xml +++ b/android/festago/presentation/src/main/res/layout/item_popular_festival_foreground.xml @@ -20,6 +20,7 @@ @@ -70,14 +70,17 @@ + tools:text="중앙대학교 청진난만 중앙대학교 천진난만" /> 북마크 마이페이지 한 번 더 누르면 앱이 종료됩니다 - + + Hello blank fragment 요즘 뜨는 축제 %s - %s @@ -27,4 +28,9 @@ 아직 도착한 알림이 없어요 새로운 소식이 도착하면 알려드릴게요 + + 진행 중 + D%1$s + 종료 +